【问题标题】:Scrapy run multiple spiders from a main spider?Scrapy 从一个主蜘蛛运行多个蜘蛛?
【发布时间】:2017-04-15 11:47:11
【问题描述】:

我有两个蜘蛛,它们获取主蜘蛛抓取的 url 和数据。我的方法是在主蜘蛛中使用 CrawlerProcess 并将数据传递给两个蜘蛛。这是我的方法:

class LightnovelSpider(scrapy.Spider):

    name = "novelDetail"
    allowed_domains = ["readlightnovel.com"]

    def __init__(self,novels = []):
        self.novels = novels

    def start_requests(self):
        for novel in self.novels:
            self.logger.info(novel)
            request = scrapy.Request(novel, callback=self.parseNovel)
            yield request

    def parseNovel(self, response):
        #stuff here

class chapterSpider(scrapy.Spider):
    name = "chapters"
    #not done here

class initCrawler(scrapy.Spider):
    name = "main"
    fromMongo = {}
    toChapter = {}
    toNovel = []
    fromScraper = []


    def start_requests(self):
        urls = ['http://www.readlightnovel.com/novel-list']

        for url in urls:
            yield scrapy.Request(url=url,callback=self.parse)

    def parse(self,response):

        for novel in response.xpath('//div[@class="list-by-word-body"]/ul/li/a/@href[not(@href="#")]').extract():
            initCrawler.fromScraper.append(novel)

        self.checkchanged()

    def checkchanged(self):
        #some scraped data processing here
        self.dispatchSpiders()

    def dispatchSpiders(self):
        process = CrawlerProcess()
        novelSpider = LightnovelSpider()
        process.crawl(novelSpider,novels=initCrawler.toNovel)
        process.start()
        self.logger.info("Main Spider Finished")

我运行“scrapy crawl main”并得到一个漂亮的错误

我能看到的主要错误是 "twisted.internet.error.ReactorAlreadyRunning" 。我对此一无所知。是否有更好的方法从另一个运行多个蜘蛛和/或如何阻止此错误?

【问题讨论】:

    标签: scrapy scrapy-spider


    【解决方案1】:

    哇,不知道这样的东西可以用,但我从未尝试过。

    当多个抓取阶段必须协同工作时,我正在做的是以下两个选项之一:

    选项 1 - 使用数据库

    当刮板必须以连续模式运行、重新扫描站点等时,我只会让刮板将其结果推送到数据库中(通过管道)

    而且进行后续处理的蜘蛛也会从同一个数据库中提取他们需要的数据(例如,在你的情况下是新的 url)。

    然后使用调度程序或 cron 保持一切运行,蜘蛛将携手合作。

    选项 2 - 将所有内容合并到一个蜘蛛中

    当一切都需要作为一个脚本运行时,我选择了这种方式:我创建了一个将多个请求步骤链接在一起的蜘蛛。

    class LightnovelSpider(scrapy.Spider):
    
        name = "novels"
        allowed_domains = ["readlightnovel.com"]
    
        # was initCrawler.start_requests
        def start_requests(self):
            urls = ['http://www.readlightnovel.com/novel-list']
    
            for url in urls:
                yield scrapy.Request(url=url,callback=self.parse_novel_list)
    
        # a mix of initCrawler.parse and parts of LightnovelScraper.start_requests
        def parse_novel_list(self,response):
            for novel in response.xpath('//div[@class="list-by-word-body"]/ul/li/a/@href[not(@href="#")]').extract():
                yield Request(novel, callback=self.parse_novel)
    
        def parse_novel(self, response):
            #stuff here
            # ... and create requests with callback=self.parse_chapters
    
        def parse_chapters(self, response):
            # do stuff
    

    (代码未测试,只是展示基本思想)

    如果事情变得过于复杂,我会提取一些元素并将它们移动到 mixin 类中。

    在你的情况下,我很可能更喜欢选项 2。

    【讨论】:

      【解决方案2】:

      经过一番研究,我能够通过使用属性装饰器“@property”从主蜘蛛检索数据来解决这个问题,如下所示:

      class initCrawler(scrapy.Spider):
      
          #stuff here from question
      
          @property
          def getNovel(self):
              return self.toNovel
      
          @property
          def getChapter(self):
              return self.toChapter
      

      然后像这样使用 CrawlerRunner:

      from spiders.lightnovel import chapterSpider,lightnovelSpider,initCrawler
      from scrapy.crawler import CrawlerProcess,CrawlerRunner
      from twisted.internet import reactor, defer
      from scrapy.utils.log import configure_logging
      import logging
      
      configure_logging()
      
      runner = CrawlerRunner()
      
      @defer.inlineCallbacks
      def crawl():
          yield runner.crawl(initCrawler)
          toNovel = initCrawler.toNovel
          toChapter = initCrawler.toChapter
          yield runner.crawl(chapterSpider,chapters=toChapter)
          yield runner.crawl(lightnovelSpider,novels=toNovel)
      
          reactor.stop()
      
      crawl()
      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
        相关资源
        最近更新 更多