13.7 扩展
扩展框架提供了一种机制,你可以将自定义功能绑定到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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论