Запустите scrapy с несколькими пауками, не блокируя процесс

Я пытаюсь запустить scrapy spider в отдельном скрипте, и когда я выполняю этот скрипт в цикле (например, запускаю того же паука с разными параметрами), я получаю ReactorAlreadyRunning. Мой фрагмент:

from celery import task
from episode.skywalker.crawlers import settings
from multiprocessing.queues import Queue
from scrapy import log, project, signals
from scrapy.settings import CrawlerSettings
from scrapy.spider import BaseSpider
from scrapy.spidermanager import SpiderManager
from scrapy.xlib.pydispatch import dispatcher
import multiprocessing
from twisted.internet.error import ReactorAlreadyRunning


class CrawlerWorker(multiprocessing.Process):

    def __init__(self, spider, result_queue):
        from scrapy.crawler import CrawlerProcess
        multiprocessing.Process.__init__(self)
        self.result_queue = result_queue
        self.crawler = CrawlerProcess(CrawlerSettings(settings))
        if not hasattr(project, 'crawler'):
            self.crawler.install()
        self.crawler.configure()

        self.items = []
        self.spider = spider
        dispatcher.connect(self._item_passed, signals.item_passed)

    def _item_passed(self, item):
        self.items.append(item)

    def run(self):
        self.crawler.crawl(self.spider)
        try:
            self.crawler.start()
        except ReactorAlreadyRunning:
            pass

        self.crawler.stop()
        self.result_queue.put(self.items)


@task
def execute_spider(spider, **spider__kwargs):
    '''
    Execute spider within separate process
    @param spider: spider class to crawl or the name (check if instance)
    '''

    if not isinstance(spider, BaseSpider):
        manager = SpiderManager(settings.SPIDER_MODULES)
        spider = manager.create(spider, **spider__kwargs)
    result_queue = Queue()
    crawler = CrawlerWorker(spider, result_queue)
    crawler.start()
    items = []

    for item in result_queue.get():
        items.append(item)

Я предполагаю, что это вызвано несколькими запусками реактора с перекрученной реакцией. Как мне этого избежать? Есть вообще способ запустить пауков без реактора?


person eviltnan    schedule 23.05.2013    source источник
comment
Ваш вопрос не в том, как запустить пауков без реактора, а в том, как запустить несколько пауков. Сосредоточение внимания на том, запущен реактор и кто его запускает, скорее всего, даст вам неправильный ответ.   -  person Glyph    schedule 24.05.2013
comment
Мне было интересно, могу ли я запустить несколько пауков, не блокируя основной процесс. Тем не менее, спасибо за исправление.   -  person eviltnan    schedule 24.05.2013


Ответы (1)


Я выяснил, что вызвало проблему: если вы каким-то образом вызываете метод execute_spider в процессе CrawlerWorker (например, через рекурсию), это вызывает создание второго реактора, что невозможно.

Мое решение: переместить все операторы, вызывающие рекурсивные вызовы, в execute_spider метод, чтобы они запускали выполнение паука в том же процессе, а не во вторичном CrawlerWorker. Я тоже встроил такое заявление

try:
        self.crawler.start()
except ReactorAlreadyRunning:
        raise RecursiveSpiderCall("Spider %s was called from another spider recursively. Such behavior is not allowed" % (self.spider))

поймать непреднамеренно рекурсивные вызовы пауков.

person eviltnan    schedule 25.05.2013