【问题标题】:Scrapy `ReactorNotRestartable`: one class to run two (or more) spidersScrapy `ReactorNotRestartable`:一个类运行两个(或更多)蜘蛛
【发布时间】:2015-09-07 08:13:51
【问题描述】:

我正在使用 Scrapy 使用两阶段抓取来汇总每日数据。第一阶段从索引页面生成 URL 列表,第二阶段将列表中每个 URL 的 HTML 写入 Kafka 主题。

虽然爬网的两个组件是相关的,但我希望它们是独立的:url_generator 将作为计划任务每​​天运行一次,page_requester 将持续运行,在可用时处理 URL。为了“礼貌”,我将调整DOWNLOAD_DELAY,以便爬虫在 24 小时内完成,但对站点的负载最小。

我创建了一个 CrawlerRunner 类,它具有生成 URL 和检索 HTML 的功能:

from twisted.internet import reactor
from scrapy.crawler import Crawler
from scrapy import log, signals
from scrapy_somesite.spiders.create_urls_spider import CreateSomeSiteUrlList
from scrapy_somesite.spiders.crawl_urls_spider import SomeSiteRetrievePages
from scrapy.utils.project import get_project_settings
import os
import sys

class CrawlerRunner:

    def __init__(self):
        sys.path.append(os.path.join(os.path.curdir, "crawl/somesite"))
        os.environ['SCRAPY_SETTINGS_MODULE'] = 'scrapy_somesite.settings'
        self.settings = get_project_settings()
        log.start()

    def create_urls(self):
        spider = CreateSomeSiteUrlList()
        crawler_create_urls = Crawler(self.settings)
        crawler_create_urls.signals.connect(reactor.stop, signal=signals.spider_closed)
        crawler_create_urls.configure()
        crawler_create_urls.crawl(spider)
        crawler_create_urls.start()
        reactor.run()

    def crawl_urls(self):
        spider = SomeSiteRetrievePages()
        crawler_crawl_urls = Crawler(self.settings)
        crawler_crawl_urls.signals.connect(reactor.stop, signal=signals.spider_closed)
        crawler_crawl_urls.configure()
        crawler_crawl_urls.crawl(spider)
        crawler_crawl_urls.start()
        reactor.run()

当我实例化该类时,我能够成功地单独执行任一函数,但不幸的是,我无法同时执行它们:

from crawl.somesite import crawler_runner

cr = crawler_runner.CrawlerRunner()

cr.create_urls()
cr.crawl_urls()

第二个函数调用在尝试执行crawl_urls 函数中的reactor.run() 时会生成twisted.internet.error.ReactorNotRestartable

我想知道这段代码是否有一个简单的修复方法(例如,运行两个单独的 Twisted 反应器的某种方式),或者是否有更好的方式来构建这个项目。

【问题讨论】:

    标签: scrapy twisted scrapy-spider


    【解决方案1】:

    通过保持反应器打开直到所有蜘蛛停止运行,可以在一个反应​​器中运行多个蜘蛛。这是通过保留所有正在运行的蜘蛛的列表并且在此列表为空之前不执行reactor.stop() 来实现的:

    import sys
    import os
    from scrapy.utils.project import get_project_settings
    from scrapy_somesite.spiders.create_urls_spider import Spider1
    from scrapy_somesite.spiders.crawl_urls_spider import Spider2
    
    from scrapy import signals, log
    from twisted.internet import reactor
    from scrapy.crawler import Crawler
    
    class CrawlRunner:
    
        def __init__(self):
            self.running_crawlers = []
    
        def spider_closing(self, spider):
            log.msg("Spider closed: %s" % spider, level=log.INFO)
            self.running_crawlers.remove(spider)
            if not self.running_crawlers:
                reactor.stop()
    
        def run(self):
    
            sys.path.append(os.path.join(os.path.curdir, "crawl/somesite"))
            os.environ['SCRAPY_SETTINGS_MODULE'] = 'scrapy_somesite.settings'
            settings = get_project_settings()
            log.start(loglevel=log.DEBUG)
    
            to_crawl = [Spider1, Spider2]
    
            for spider in to_crawl:
    
                crawler = Crawler(settings)
                crawler_obj = spider()
                self.running_crawlers.append(crawler_obj)
    
                crawler.signals.connect(self.spider_closing, signal=signals.spider_closed)
                crawler.configure()
                crawler.crawl(crawler_obj)
                crawler.start()
    
            reactor.run()
    

    类被执行:

    from crawl.somesite.crawl import CrawlRunner
    
    cr = CrawlRunner()
    cr.run()
    

    此解决方案基于blogpost by Kiran Koduru

    【讨论】:

    • 有没有办法在反应堆运行时将爬虫添加到反应堆中?怎么办? reactor.run() 阻塞了?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多