【问题标题】:scrapy: Call a function when a spider quitsscrapy:当蜘蛛退出时调用一个函数
【发布时间】:2012-09-05 19:52:26
【问题描述】:

有没有办法在 Spider 类中的方法终止之前触发它?

我可以自己终止蜘蛛,像这样:

class MySpider(CrawlSpider):
    #Config stuff goes here...

    def quit(self):
        #Do some stuff...
        raise CloseSpider('MySpider is quitting now.')

    def my_parser(self, response):
        if termination_condition:
            self.quit()

        #Parsing stuff goes here...

但我找不到任何关于如何确定蜘蛛何时将自然退出的信息。

【问题讨论】:

    标签: python scrapy


    【解决方案1】:

    看来你可以通过dispatcher注册一个信号监听器。

    我会尝试类似:

    from scrapy import signals
    from scrapy.xlib.pydispatch import dispatcher
    
    class MySpider(CrawlSpider):
        def __init__(self):
            dispatcher.connect(self.spider_closed, signals.spider_closed)
    
        def spider_closed(self, spider):
          # second param is instance of spder about to be closed.
    

    在较新版本的 scrapy 中,scrapy.xlib.pydispatch 已弃用。相反,您可以使用pydispatch import dispatcher

    【讨论】:

    • 完美运行。但我建议将方法命名为 MySpider.quit() 或类似名称,以避免与信号名称混淆。谢谢!
    • 优秀的解决方案。是的,该示例应该与CrawlSpider 完全相同。
    • 我很困惑为什么需要 spider_closed 的第二个参数。蜘蛛不是要自闭吗?
    • 不适用于 v. 1.1,因为 xlib.pydispatch 已被弃用。相反,他们建议使用 PyDispatcher。虽然还不能让它工作......
    • 在较新版本的 scrapy 中,scrapy.xlib.pydispatch 已弃用。你可以使用from pydispatch import dispatcher
    【解决方案2】:

    只是为了更新,你可以像这样调用closed函数:

    class MySpider(CrawlSpider):
        def closed(self, reason):
            do-something()
    

    【讨论】:

    • 在我的scrapy中是def close(self, reason):,而不是closed
    • @AminahNuraini Scrapy 1.0.4 def closed(reason)
    【解决方案3】:

    对于 Scrapy 版本 1.0.0+(它也可能适用于旧版本)。

    from scrapy import signals
    
    class MySpider(CrawlSpider):
        name = 'myspider'
    
        @classmethod
        def from_crawler(cls, crawler, *args, **kwargs):
            spider = super(MySpider, cls).from_crawler(crawler, *args, **kwargs)
            crawler.signals.connect(spider.spider_opened, signals.spider_opened)
            crawler.signals.connect(spider.spider_closed, signals.spider_closed)
            return spider
    
        def spider_opened(self, spider):
            print('Opening {} spider'.format(spider.name))
    
        def spider_closed(self, spider):
            print('Closing {} spider'.format(spider.name))
    

    一个很好的用法是将tqdm进度条添加到scrapy spider。

    # -*- coding: utf-8 -*-
    from scrapy import signals
    from scrapy.linkextractors import LinkExtractor
    from scrapy.spiders import CrawlSpider, Rule
    from tqdm import tqdm
    
    
    class MySpider(CrawlSpider):
        name = 'myspider'
        allowed_domains = ['somedomain.comm']
        start_urls = ['http://www.somedomain.comm/ccid.php']
    
        rules = (
            Rule(LinkExtractor(allow=r'^http://www.somedomain.comm/ccds.php\?id=.*'),
                 callback='parse_item',
                 ),
            Rule(LinkExtractor(allow=r'^http://www.somedomain.comm/ccid.php$',
                               restrict_xpaths='//table/tr[contains(., "SMTH")]'), follow=True),
        )
    
        def parse_item(self, response):
            self.pbar.update()  # update progress bar by 1
            item = MyItem()
            # parse response
            return item
    
        @classmethod
        def from_crawler(cls, crawler, *args, **kwargs):
            spider = super(MySpider, cls).from_crawler(crawler, *args, **kwargs)
            crawler.signals.connect(spider.spider_opened, signals.spider_opened)
            crawler.signals.connect(spider.spider_closed, signals.spider_closed)
            return spider
    
        def spider_opened(self, spider):
            self.pbar = tqdm()  # initialize progress bar
            self.pbar.clear()
            self.pbar.write('Opening {} spider'.format(spider.name))
    
        def spider_closed(self, spider):
            self.pbar.clear()
            self.pbar.write('Closing {} spider'.format(spider.name))
            self.pbar.close()  # close progress bar
    

    【讨论】:

    • 这是方法!虽然它看起来不那么透明,但它的优点是消除了使用 def __init__(self):.. 和使用 from scrapy.xlib.pydispatch import dispatcher 的 PyDispatcher 导入的额外混乱。
    【解决方案4】:

    对于最新版本(v1.7),只需在您的蜘蛛类中定义closed(reason) 方法。

    closed(reason):

    当蜘蛛关闭时调用。该方法提供了一个快捷方式 蜘蛛关闭信号的signals.connect()。

    Scrapy Doc : scrapy.spiders.Spider.closed

    【讨论】:

      【解决方案5】:

      对我来说,接受的行不通/至少对于scrapy 0.19来说已经过时了。 我让它与以下内容一起工作:

      from scrapy.signalmanager import SignalManager
      from scrapy.xlib.pydispatch import dispatcher
      
      class MySpider(CrawlSpider):
          def __init__(self, *args, **kwargs):
              super(MySpider, self).__init__(*args, **kwargs)
              SignalManager(dispatcher.Any).connect(
                  self.closed_handler, signal=signals.spider_closed)
      
          def closed_handler(self, spider):
              # do stuff here
      

      【讨论】:

        【解决方案6】:

        如果你有很多蜘蛛并且想在它们关闭之前做一些事情,也许在你的项目中添加 statscollector 会很方便。

        在设置中:

        STATS_CLASS = 'scraper.stats.MyStatsCollector'
        

        和收集器:

        from scrapy.statscollectors import StatsCollector
        
        class MyStatsCollector(StatsCollector):
            def _persist_stats(self, stats, spider):
                do something here
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多