запустить одновременно N его копий. Про многопоточность я уже написал один пост, который полностью состоит из быдлокода=) С тех пор, я чутка поумнел и для организации потоков наследуюсь от класса Thread. С многопроцессовостью всё аналогично, только классы другие, а методы и структура вся та же.
# coding: utf8
import spynner
from spynner import browser
import multiprocessing
from multiprocessing import Process
class Serfer(multiprocessing.Process):
def __init__(self,queue):
multiprocessing.Process.__init__(self)
self.__queue = queue # наша очередь заданий
self.kill_received = False # На всякий случай переменная, вдруг надо будет всё остановить
def run(self):
while not self.kill_received:
try: item = self.__queue.get_nowait() # ждём данные
except Queue.Empty: break
error = True
try: error = self.serfing(item)
except: traceback.print_exc()
time.sleep(0.1)
self.__queue.task_done() # задача завершена
if error: self.__queue.put(item) # Если была ошибка, то еще раз с этими данными
return
def serfing(self,url):
br = browser.Browser() # запускаем браузер
br.create_webview()
br.show() # отображаем
br.load(url) # загружаем страницу
br.wait_a_little(75)
br.destroy_webview()
br.close() # закрываем браузер
def main():
queue = multiprocessing.JoinableQueue() # создаем очередь заданий
processes = 5
# Урлы по которым надо будет перейти в браузере
urls = ["http://ya.ru","http://google.ru","http://yahoo.com",
"http://bing.com","http://rambler.ru"]
for url in urls:
queue.put(url) # заносим данные в очередь
for i in xrange(processes):
t = Serfer(queue) # создаем процесс
t.start() # стартуем
time.sleep(0.1)
queue.join() # приостанавливаем дальнейшее выполнение кода, пока очередь не опустошится
print "Done"
if __name__ == '__main__':
main()
Отличный пример! Добавил в свою копилку.
ОтветитьУдалитьМультипроцессинг выглядит также, как и мультитреадинг, не ожидал.
Спасибо что восстановил блог :)
ОтветитьУдалить>С тех пор, я чутка поумнел и для организации потоков наследуюсь от класса Thread.
это вот так:
...
class Register(threading.Thread):
def __init__(self,config):
...
и т.д?
А чем был плох старый способ из "Пример 3. Очереди." ?
Ага, из моего же скрипта код=) Ну так удобней, если очень много входных данных использовать и применять тот старый способ, придется делать кучу параметров у функции, которую будем ветвить. А тут класс, ООП, все дела, да и смотрится красиво и понятно, а в том случае при усложнении примера костыли одни получаются.
ОтветитьУдалитьпривет, подскажи пожалуйста, зачем здесь:
ОтветитьУдалитьfor i in xrange(processes):
t = Serfer(queue) # создаем процесс
t.start() # стартуем
time.sleep(0.1)
мы делаем паузу (то есть time.sleep(0.1)). я так понимаю, что должно пройти некоторое время, пока передаваемая очередь пройдёт pickling и станет доступна порождённому процессу в шаред памяти?
В общем, есть ли какой-то способ не делать паузу явно, а как-то ждать ровно необходимое время (которое может быть и больше 0.1 сек)... то есть ровно столько, сколько потребуется для инициализации нового процесса ?
Спасибо.
Гм, работая с потоками, паузу я делал для того, чтобы выводимый текст в консоли не накладывался друг на друга, если я делаю print text из потока. В этом примере сообщений в командную строку я не вывожу, а задержку просто забыл убрать =) По идее все эти паузы можно закомментировать.
ОтветитьУдалитьясно, просто я тут как-то начал замарачиваться с синхронизацей всех пораждённых процессов пауков, и потребовалось передавать в подпроцессы Кондишины и прочие объекты IPC синхронизации, так вот, эти объекты создавались только после истечения некоторой паузы, которую нужно было делать сразу после process.start(), и которая всегда само-собой была разной (что бы этот объект смог стать доступным после pickling-а уже в пространстве процесса), и подумал, что и в случае, когда используем обычные очереди, нужна такая пауза.
ОтветитьУдалитьКстати, всё-таки не пытался ради спортивного интереса заставить это всё работать в потоках, а не процессах? уж слишком межу ними синхронизироваться неудобно
Я ж написал, что невозможно заставить spynner работать в потоках, особенности библиотеки Qt, к сожалению. Так что только процессы, вообще splinter посмотреть попробуй, если честно не понравился мне этот spynner
ОтветитьУдалитьЕсли выставлять число процессов меньше числа урлов то не работает
ОтветитьУдалитьВисит вот с такими ошибками:
Application asked to unregister timer 0x1f000002 which is not registered in this thread. Fix application.
QObject::connect: Cannot connect (null)::configurationAdded(QNetworkConfiguration) to QNetworkConfigurationManager::configurationAdded(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationRemoved(QNetworkConfiguration) to QNetworkConfigurationManager::configurationRemoved(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationUpdateComplete() to QNetworkConfigurationManager::updateCompleted()
QObject::connect: Cannot connect (null)::onlineStateChanged(bool) to QNetworkConfigurationManager::onlineStateChanged(bool)
QObject::connect: Cannot connect (null)::configurationChanged(QNetworkConfiguration) to QNetworkConfigurationManager::configurationChanged(QNetworkConfiguration)
Application asked to unregister timer 0x3000007 which is not registered in this thread. Fix application.
QObject::connect: Cannot connect (null)::configurationAdded(QNetworkConfiguration) to QNetworkConfigurationManager::configurationAdded(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationRemoved(QNetworkConfiguration) to QNetworkConfigurationManager::configurationRemoved(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationUpdateComplete() to QNetworkConfigurationManager::updateCompleted()
QObject::connect: Cannot connect (null)::onlineStateChanged(bool) to QNetworkConfigurationManager::onlineStateChanged(bool)
QObject::connect: Cannot connect (null)::configurationChanged(QNetworkConfiguration) to QNetworkConfigurationManager::configurationChanged(QNetworkConfiguration)
о, у вас тут спайнер обсуждают )
ОтветитьУдалитьтаки всё, "кончился" проект, в unmaintained переведён... но штука полезная, и можно юзать как фреймвёрк для продолжения разработок, что я собственно и решил сделать. пока в планах адаптировать синтаксис к питон 2.7, портировать на PySide, и так по мелочи + ~10 методов добавить.
кстати, про splinter - тоже на него смотрел, но это не совсем то имхо, и в любом случае нужен весь силениум целиком На какой-то VDS себе не поставишь, да и вообще масса зависимостей, когда окружение под spynner сетапится за пол часа несколькими командами )
Вообще, интересно, кто-то смог заставить работать метод native_click?, а без этого оно всего-лишь игрушка. Сейчас рою исходник phantomjs, там посылка нейтивных событий клика в WebView дописана автором фантома... и было бы очень плохо, если для каждого нового инсталла qwebkit-а приходилось бы его ещё отдельно патчить для этого ) В общем, если у кого имеются сабжевые наработки, интересно пообсуждать.