【问题标题】:Locally run all of the spiders in Scrapy本地运行 Scrapy 中的所有蜘蛛
【发布时间】:2013-03-11 23:38:32
【问题描述】:

有没有办法在不使用 Scrapy 守护进程的情况下运行 Scrapy 项目中的所有蜘蛛?曾经有一种方法可以使用scrapy crawl 运行多个蜘蛛,但该语法已被删除,并且 Scrapy 的代码发生了很大变化。

我尝试创建自己的命令:

from scrapy.command import ScrapyCommand
from scrapy.utils.misc import load_object
from scrapy.conf import settings

class Command(ScrapyCommand):
    requires_project = True

    def syntax(self):
        return '[options]'

    def short_desc(self):
        return 'Runs all of the spiders'

    def run(self, args, opts):
        spman_cls = load_object(settings['SPIDER_MANAGER_CLASS'])
        spiders = spman_cls.from_settings(settings)

        for spider_name in spiders.list():
            spider = self.crawler.spiders.create(spider_name)
            self.crawler.crawl(spider)

        self.crawler.start()

但是一旦一个蜘蛛注册到self.crawler.crawl(),我得到所有其他蜘蛛的断言错误:

Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/scrapy/cmdline.py", line 138, in _run_command
    cmd.run(args, opts)
  File "/home/blender/Projects/scrapers/store_crawler/store_crawler/commands/crawlall.py", line 22, in run
    self.crawler.crawl(spider)
  File "/usr/lib/python2.7/site-packages/scrapy/crawler.py", line 47, in crawl
    return self.engine.open_spider(spider, requests)
  File "/usr/lib/python2.7/site-packages/twisted/internet/defer.py", line 1214, in unwindGenerator
    return _inlineCallbacks(None, gen, Deferred())
--- <exception caught here> ---
  File "/usr/lib/python2.7/site-packages/twisted/internet/defer.py", line 1071, in _inlineCallbacks
    result = g.send(result)
  File "/usr/lib/python2.7/site-packages/scrapy/core/engine.py", line 215, in open_spider
    spider.name
exceptions.AssertionError: No free spider slots when opening 'spidername'

有没有办法做到这一点?我宁愿不要为了像这样运行我所有的蜘蛛而开始子类化核心 Scrapy 组件。

【问题讨论】:

  • 你用的是什么 Scrapy 版本? $ scrapy version -v
  • 你知道scrapyd吗?
  • 0.16.4。我确实知道 Scrapyd,但我正在本地测试这些蜘蛛,所以我宁愿不使用它。

标签: python web-crawler scrapy


【解决方案1】:

Linux 脚本

#!/bin/bash
for spider in $(scrapy list)
do
scrapy crawl "$spider" -o "$spider".json
done

【讨论】:

    【解决方案2】:

    此代码适用于我的 scrapy 版本为 1.3.3(将其保存在 scrapy.cfg 的同一目录中):

    from scrapy.utils.project import get_project_settings
    from scrapy.crawler import CrawlerProcess
    
    setting = get_project_settings()
    process = CrawlerProcess(setting)
    
    for spider_name in process.spiders.list():
        print ("Running spider %s" % (spider_name))
        process.crawl(spider_name,query="dvh") #query dvh is custom argument used in your scrapy
    
    process.start()
    

    对于scrapy 1.5.x(所以你不会收到弃用警告)

    from scrapy.utils.project import get_project_settings
    from scrapy.crawler import CrawlerProcess
    
    setting = get_project_settings()
    process = CrawlerProcess(setting)
    
    for spider_name in process.spider_loader.list():
        print ("Running spider %s" % (spider_name))
        process.crawl(spider_name,query="dvh") #query dvh is custom argument used in your scrapy
    
    process.start()
    

    【讨论】:

    • 我也使用了上面 Yuda Prawira 给出的答案,它在 Scrapy 1.5.2 中仍然有效,但我收到了这个警告:ScrapyDeprecationWarning: CrawlerRunner.spiders attribute is renamed to CrawlerRunner.spider_loader. 你所要做的就是在 for 循环代码中更改名称:for spider in process.spider_loader.list(): ... 否则仍然有效!
    【解决方案3】:

    @Steven Almeroth 的答案将在 Scrapy 1.0 中失败,您应该像这样编辑脚本:

    from scrapy.commands import ScrapyCommand
    from scrapy.utils.project import get_project_settings
    from scrapy.crawler import CrawlerProcess
    
    class Command(ScrapyCommand):
    
        requires_project = True
        excludes = ['spider1']
    
        def syntax(self):
            return '[options]'
    
        def short_desc(self):
            return 'Runs all of the spiders'
    
        def run(self, args, opts):
            settings = get_project_settings()
            crawler_process = CrawlerProcess(settings) 
    
            for spider_name in crawler_process.spider_loader.list():
                if spider_name in self.excludes:
                    continue
                spider_cls = crawler_process.spider_loader.load(spider_name) 
                crawler_process.crawl(spider_cls)
            crawler_process.start()
    

    【讨论】:

      【解决方案4】:

      你为什么不直接使用类似的东西:

      scrapy list|xargs -n 1 scrapy crawl
      

      ?

      【讨论】:

      • 使用-P 0 选项为xargs 并行运行所有蜘蛛。
      • 如何动态输出带有蜘蛛名字的json
      【解决方案5】:

      这是一个不在自定义命令中运行,而是手动运行 Reactor 并创建新的 Crawler for each spider 的示例:

      from twisted.internet import reactor
      from scrapy.crawler import Crawler
      # scrapy.conf.settings singlton was deprecated last year
      from scrapy.utils.project import get_project_settings
      from scrapy import log
      
      def setup_crawler(spider_name):
          crawler = Crawler(settings)
          crawler.configure()
          spider = crawler.spiders.create(spider_name)
          crawler.crawl(spider)
          crawler.start()
      
      log.start()
      settings = get_project_settings()
      crawler = Crawler(settings)
      crawler.configure()
      
      for spider_name in crawler.spiders.list():
          setup_crawler(spider_name)
      
      reactor.run()
      

      您必须设计some signal system 以在所有蜘蛛完成后停止反应器。

      编辑:这里是您如何在自定义命令中运行多个蜘蛛:

      from scrapy.command import ScrapyCommand
      from scrapy.utils.project import get_project_settings
      from scrapy.crawler import Crawler
      
      class Command(ScrapyCommand):
      
          requires_project = True
      
          def syntax(self):
              return '[options]'
      
          def short_desc(self):
              return 'Runs all of the spiders'
      
          def run(self, args, opts):
              settings = get_project_settings()
      
              for spider_name in self.crawler.spiders.list():
                  crawler = Crawler(settings)
                  crawler.configure()
                  spider = crawler.spiders.create(spider_name)
                  crawler.crawl(spider)
                  crawler.start()
      
              self.crawler.start()
      

      【讨论】:

      • 谢谢,这正是我想要做的。
      • 如何给节目加注星标?
      • 将代码放入文本编辑器并保存为mycoolcrawler.py。在 Linux 中,您可能可以从保存它的目录中的命令行中运行 python mycoolcrawler.py。在 Windows 中,您可能只需从文件管理器中双击它。
      • 你能解释一下CrawlerSpider之间的区别吗? AFAIK,Spider 控制诸如如何处理响应(例如要抓取哪些项目以及如何提取链接......),那么 Crawler 做什么?
      • @Alcott 没错,Spider 处理响应,Crawler 处理 Spider:实例化它们、配置设置和中间件等。
      猜你喜欢
      • 1970-01-01
      • 2014-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多