Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: eviltnanОтветов: 1

Я пытаюсь запустить 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)

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

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

pythonscrapytwisted

Ответы

Ответ 1 · рейтинг 1 · eviltnan

Я выяснил, что вызвало проблему: если вы каким-то образом вызываете метод 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))

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы