返回介绍

13.7 扩展

发布于 2024-01-26 22:39:51 字数 6366 浏览 0 评论 0 收藏 0

扩展框架提供了一种机制,你可以将自定义功能绑定到Scrapy中。扩展只是正常的Python类,它们会在Scrapy启动时被实例化、初始化。

13.7.1 配置扩展

扩展需要在settings中进行设置,和中间件的设置类似。扩展在扩展类被实例化时加载和激活,实例化代码必须在类的构造函数(__init__)中执行。要使得扩展可用,需要把它添加到Settings的EXTENSIONS配置中。在EXTENSIONS中,每个扩展都使用一个字符串表示,即扩展类的全Python路径。例如:

  EXTENSIONS = {
     'scrapy.extensions.corestats.CoreStats': 500,
     'scrapy.telnet.TelnetConsole': 500,
  }

EXTENSIONS配置的格式和中间件配置的格式差不多,都是一个字典,键是扩展类的路径,值是顺序,它定义扩展加载的顺序。扩展顺序不像中间件的顺序那么重要,扩展之间一般没有关联。Scrapy中的内置扩展设置EXTENSIONS_BASE如下:

·'scrapy.extensions.corestats.CoreStats':0

·'scrapy.telnet.TelnetConsole':0

·'scrapy.extensions.memusage.MemoryUsage':0

·'scrapy.extensions.memdebug.MemoryDebugger':0

·'scrapy.extensions.closespider.CloseSpider':0

·'scrapy.extensions.feedexport.FeedExporter':0

·'scrapy.extensions.logstats.LogStats':0

·'scrapy.extensions.spiderstate.SpiderState':0

·'scrapy.extensions.throttle.AutoThrottle':0

扩展一般分为三种状态:可用的(Available)、开启的(enabled)和禁用的(disabled)。并不是所有可用的扩展都会被开启。一些扩展经常依赖一些特别的配置,比如HTTP Cache扩展是可用的但默认是禁用的,除非设置了HTTPCACHE_ENABLED配置项。如何禁用一个默认开启的扩展呢?和中间件的禁用一样,需要将其顺序(order)设置为None。比如:

  EXTENSIONS = {
     'scrapy.extensions.corestats.CoreStats': None,
  }

13.7.2 定制扩展

如何定制我们自己的扩展,强化Scrapy的功能才是我们比较关心的问题。扩展类是一个不同的Python类,但是如果想操作Scrapy的功能,需要一个入口:from_crawler类方法,它接收一个Crawler类的实例,通过这个对象可以访问settings(设置)、signals(信号)、stats(状态),以便控制爬虫的行为。通常来说,扩展需要关联到signals并执行它们触发的任务,如果from_crawler方法抛出NotConfigured异常,扩展会被禁用。否则,扩展会被开启。下面通过一个例子来实现简单扩展,功能是当出现以下事件时,记录一条日志:

·Spider被打开。

·Spider被关闭。

·爬取了特定数量的Item。

扩展代码如下:

  import logging
  from scrapy import signals
  from scrapy.exceptions import NotConfigured
  
  logger = logging.getLogger(__name__)
  
  class SpiderOpenCloseLogging(object):
  
     def __init__(self, item_count):
       self.item_count = item_count
  
       self.items_scraped = 0
  
     @classmethod
     def from_crawler(cls, crawler):
       # 首先检查一下是否存在相应的配置,如果不存在则抛出NotConfigured异常
       if not crawler.settings.getbool('MYEXT_ENABLED'):
  
            raise NotConfigured
  
       # 从setting中获取MYEXT_ITEMCOUNT的值
  
       item_count = crawler.settings.getint('MYEXT_ITEMCOUNT', 1000)
  
       # 初始化扩展实例
  
       ext = cls(item_count)
  
       # 将扩展中的spider_opened、spider_closed和item_scraped连接到相应信号处,进行触发。
  
       crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
  
       crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
  
       crawler.signals.connect(ext.item_scraped, signal=signals.item_scraped)
  
       # 扩展实例返回
       return ext
  
     def spider_opened(self, spider):
       logger.info("opened spider %s", spider.name)
  
     def spider_closed(self, spider):
       logger.info("closed spider %s", spider.name)
  
     def item_scraped(self, item, spider):
       self.items_scraped += 1
       if self.items_scraped % self.item_count == 0:
            logger.info("scraped %d items", self.items_scraped)

编写扩展依赖的Crawler实例,其中信号的设置很重要。下面说一下内置的信号。

1.engine_started

原型:scrapy.signals.engine_started()

说明:当Scrapy引擎启动爬取时发送该信号。该信号支持返回deferreds。

2.engine_stopped

原型:scrapy.signals.engine_stopped()

说明:当Scrapy引擎停止时发送该信号,例如爬取结束。该信号支持返回deferreds。

3.item_scraped

原型:scrapy.signals.item_scraped(item,response,spider)

参数:item(dict或Item对象):爬取到的item

spider(Spider对象):爬取item的spider

response(Response对象):提取item的response

说明:当item被爬取,并通过所有Item Pipeline后(没有被丢弃(dropped),发送该信号。该信号支持返回deferreds。

4.item_dropped

原型:scrapy.signals.item_dropped(item,exception,spider)

参数:item(dict或Item对象):Item Pipeline丢弃的item。

spider(Spider对象):爬取item的spider。

exception(DropItem异常):导致item被丢弃的异常。

说明:当item通过Item Pipeline,有些pipeline抛出DropItem异常,丢弃Item时,该信号被发送。该信号支持返回deferreds。

5.spider_closed

原型:scrapy.signals.spider_closed(spider,reason)

参数:spider(Spider对象):关闭的spider。

reason(str):描述Spider被关闭的原因的字符串。如果Spider是由于完成爬取而被关闭,则其为“finished”。否则,如果Spider是被引擎的close_spider方法所关闭,则其为调用该方法时传入的reason参数(默认为“cancelled”)。如果引擎被关闭(例如,输入Ctrl-C),则其为“shutdown”。

说明:当某个Spider被关闭时,该信号被发送。该信号可以用来释放每个Spider在spider_opened时占用的资源。该信号支持返回deferreds。

6.spider_opened

原型:scrapy.signals.spider_opened(spider)

参数:spider(Spider对象):开启的spider。

说明:当spider开始爬取时发送该信号。该信号一般用来分配Spider的资源,不过它也能做任何事。该信号支持返回deferreds。

7.spider_idle

原型:scrapy.signals.spider_idle(spider)

参数:spider(Spider对象):空闲的Spider。

说明:当Spider进入空闲(idle)状态时该信号被发送。空闲意味着:

·Requests正在等待被下载。

·Requests被调度。

·Items正在Item Pipeline中被处理。

当该信号的所有处理器(handler)被调用后,如果Spider仍然保持空闲状态,引擎将会关闭该Spider。当Spider被关闭后,spider_closed信号将被发送,可以在spider_idle处理器中调度某些请求来避免spider被关闭。

该信号不支持返回deferreds。

8.spider_error

原型:scrapy.signals.spider_error(failure,response,spider)

参数:failure(Failure对象):以Twisted Failure对象抛出的异常。

response(Response对象):当异常被抛出时被处理的response。

spider(Spider对象):抛出异常的Spider。

说明:当Spider的回调函数产生错误时,例如抛出异常,该信号被发送。

9.request_scheduled

原型:scrapy.signals.request_scheduled(request,spider)

参数:request(Request对象):到达调度器的Request。

spider(Spider对象):产生该Request的Spider。

说明:当引擎调度一个Request对象用于下载时,该信号被发送。该信号不支持返回deferreds。

10.response_received

原型:scrapy.signals.response_received(response,request,spider)

参数:response(Response对象):接收到的response。

request(Request对象):生成response的request。

spider(Spider对象):response所对应的spider。

说明:当引擎从downloader获取到一个新的Response时发送该信号。该信号不支持返回deferreds。

11.response_downloaded

原型:scrapy.signals.response_downloaded(response,request,spider)

参数:response(Response对象):下载的response。

request(Request对象):生成response的request。

spider(Spider对象):response所对应的spider。

说明:当一个HTTPResponse被下载时,由downloader发送该信号。该信号不支持返回deferreds。

13.7.3 内置扩展

下面简要介绍一下Scrapy的内置扩展,方便我们使用,同时也可以参考内置扩展的源码来拓展自己的功能。常见内置扩展如表13-4所示。

表13-4 常见内置扩展

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文