二十三、Scrapy的extensions

Scrapy提供扩展(扩展是正常的python类,它们会在Scrapy启动时被实例化、初始化)机制,让人能将自定义功能绑定到Scrapy中。

1、Scrapy中的内置扩展设置EXTENSIONS_BASE

  扩展在扩展类被实例化时加载和激活,实例化代码必须在类的构造函数(__init__)中执行。

  (1)'scrapy.extensions.corestats.CoreStats':0

    名称:核心统计扩展

    说明:如果统计收集器(stats collection)启用了,该扩展开启核心统计收集

  (2)'scrapy.telnet.TelnetConsole':0

    名称:Telnet控制台扩展

    说明:提供了一个telnet控制台,telnet控制台通过TELNETCONSOLE_ENABLED配置项开启,服务器会监听TELNETCONSOLE_PORT指定的端口

  (3)'scrapy.extensions.memusage.MemoryUsage':0

    名称:内存使用扩展

    说明:监听Scrapy进程内存使用量,如果使用内存量超过某个指定值,发送提醒邮件,如果超过某个指定值,关闭spider

  (4)'scrapy.extensions.memdebug.MemoryDebugger':0

    名称:内存调试扩展

    说明:该扩展用于调试内存使用量,开启该扩展,需要打开MEMDEBUG_ENABLED配置项

  (5)'scrapy.extensions.closespider.CloseSpider':0

    名称:当某些状况发生,spider会自动关闭,用来为状况指定关闭方式

  (6)'scrapy.extensions.feedexport.FeedExporter':0

  (7)'scrapy.extensions.logstats.LogStats':0

    名称:记录统计扩展

    说明:记录基本的统计信息,比如爬取的页面和条目(items)

  (8)‘scrapy.extensions.spiderstate.SpiderState’:0

  (9)‘scrapy.extensions.throttle.AutoThrottle’:0

  (10)‘scrapy.extensions.statsmailer.StatsMailer’:0

    名称:StatsMailer扩展

    说明:这个简单的扩展可用来在一个域名爬取完毕时发送提醒邮件,包含Scrapy收集的统计信息。邮件会发送给通过STATSMAILER_RCPTS指定的所有接收人

  扩展一般分为三种状态:可用的(Available)、开启的(enabled)和禁用的(disabled)。一些扩展经常需要依赖一些特别的配置,比如HTTP Cache扩展是可用的但默认是禁用的,除非设置了HTTPCACHE_ENABLED配置项。通过将其顺序设置为None,即可禁用。

2、定制扩展

  扩展类是一个Python类,如果想操作Scrapy的功能,需要一个入口:from_crawler类方法,它接收一个Crawler类的实例,通过这个对象可以访问settings(设置)、signals(信号)、stats(状态),以便控制爬虫的行为。

  2.1 Scrapy提供的异常及其用法

  (1)DropItem异常

    原型:scrapy.exceptions.DropItem

    说明:该异常由item pipeline抛出,用于停止处理item

  (2)CloseSpider异常

    原型:scrapy.exceptions.CloseSpider(reason='cancelled')

    说明:该异常由spider的回调函数(callback)抛出,来停止/暂停spider。支持的参数:reason(str):关闭的原因

  (3)IgnoreRequest异常

    原型:scrapy.exceptions.IgnoreRequest

    说明:该异常由调度器(scheduler)或其他下载器中间件抛出,声明忽略该request

  (4)NotConfigured异常

    原型:scrapy.exceptions.NotConfigured

    说明:该异常由某些组件抛出,申明其仍然保持关闭。这些组件包括:Extensions、Item pipelines、Downloader middlwares、Spider middlewares。该异常必须由组件的构造器(constructor)抛出。

  (5)NotSupported异常

    原型:scrapy.exceptions.NotSupported

    说明:该异常申明一个不支持的特性

  2.2 Scrapy内置的信号

  (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)状态时该信号被发送。空闲说明:1)Requests正在等待被下载。2)Request被调度。3)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(Request对象):接收到的resposne

       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

  2.3 扩展代码

      代码来自:《Python爬虫开发与项目实战》范传辉著

      扩展需要关联到signals并执行它们触发的任务,如果from_crawler()方法抛出NotConfigured异常,扩展会被禁用,否则,扩展会被开启。

import logging
from scrapy import signals
from scrapy import crawler
from scrapy.exceptions import NotConfigured

logger = logging.getLogger(__name__)

class SpiderOpenCloseLogging(object):
    """当出现(spider被打开,spider被关闭,爬取了特定数量的Item)事件时,记录一条日志"""
    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 spiders %s",spider.name)

    def spider_closed(self,spider):
        logger.info("closed spiders %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)

 

上一篇:400gbase-sr8 400g osfp to osfp twinax copper dac c


下一篇:零基础学Java语言翁恺第2周编程题2