扩展(Extensions)

扩展框架提供一个机制,使得你能将自定义功能绑定到Scrapy。

扩展只是正常的类,它们在Scrapy启动时被实例化、初始化。

扩展设置(Extension settings)

扩展使用 Scrapy settings 管理它们的设置,这跟其他Scrapy代码一样。

通常扩展需要给它们的设置加上前缀,以避免跟已有(或将来)的扩展冲突。 比如,一个扩展处理Google Sitemaps, 则可以使用类似 GOOGLESITEMAP_ENABLEDGOOGLESITEMAP_DEPTH等设置。

加载和激活扩展

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

要使得扩展可用,需要把它添加到Scrapy的 EXTENSIONS 配置中。 EXTENSIONS 中,每个扩展都使用一个字符串表示,即扩展类的全Python路径。 比如:

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

如你所见,EXTENSIONS配置是一个dict,key是扩展类的路径,value是顺序, 它定义扩展加载的顺序。EXTENSIONS设置与Scrapy中定义的EXTENSIONS_BASE设置合并 (不是覆盖),然后按顺序得到最终要启用的扩展的列表。

因为扩展通常不互相依赖,其加载顺序在大多数情况下无关紧要。这也是为什么EXTENSIONS_BASE设置定义所有扩展的顺序都相同 (0)。然而,如果你添加的扩展需要取决于其他已加载的扩展,可以利用此功能。

可用的、开启的和禁用的扩展

并不是所有可用的扩展都会被开启。 一些扩展经常依赖一些特别的配置。 比如,HTTP Cache扩展是可用的但默认是禁用的,除非 HTTPCACHE_ENABLED 配置项设置了。

禁用扩展(Disabling an extension)

为了禁用一个默认开启的扩展(比如,包含在 EXTENSIONS_BASE设置中的扩展), 需要将其顺序设置为None 比如:

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

编写你自己的扩展

每个扩展都是一个Python类。 Scrapy扩展(包括middlewares和pipelines)的主要入口是 from_crawler 类方法, 它接收一个 Crawler 类的实例,该实例是控制Scrapy crawler的主要对象。 你可以通过这个对象访问settings,signals,stats,控制爬虫的行为。

通常来说,扩展关联到 signals 并执行它们触发的任务。

最后,如果 from_crawler 方法抛出 NotConfigured 异常, 扩展会被禁用。 否则,扩展会被开启。

扩展例子(Sample extension)

这里我们将实现一个简单的扩展来演示上面描述到的概念。 该扩展会在以下事件时记录一条日志:

  • spider被打开
  • spider被关闭
  • 爬取了特定数量的条目(items)

该扩展通过 MYEXT_ENABLED 配置项开启, items的数量通过 MYEXT_ITEMCOUNT 配置项设置。

以下是扩展的代码:

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):
        # first check if the extension should be enabled and raise
        # NotConfigured otherwise
        if not crawler.settings.getbool('MYEXT_ENABLED'):
            raise NotConfigured

        # get the number of items from settings
        item_count = crawler.settings.getint('MYEXT_ITEMCOUNT', 1000)

        # instantiate the extension object
        ext = cls(item_count)

        # connect the extension object to signals
        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 the extension object
        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)

内置扩展参考

一般用途的扩展

日志统计扩展

class scrapy.extensions.logstats.LogStats

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

核心统计扩展

class scrapy.extensions.corestats.CoreStats

如果统计收集器(stats collection)启用了,该扩展开启核心统计收集(参考 数据收集(Stats Collection))。

Telnet 控制台扩展

class scrapy.extensions.telnet.TelnetConsole

提供一个telnet控制台,用于进入当前执行的Scrapy进程的Python解析器, 这对代码调试非常有帮助。

telnet控制台通过 TELNETCONSOLE_ENABLED 配置项开启, 服务器会监听 TELNETCONSOLE_PORT 指定的端口。

内存使用扩展

class scrapy.extensions.memusage.MemoryUsage

Note

此扩展不能在Windows 中工作。

监控Scrapy进程内存使用量,并且:

  1. 如果使用内存量超过某个指定值,发送提醒邮件
  2. 如果超过某个指定值,关闭spider

当内存用量达到 MEMUSAGE_WARNING_MB指定的值,发送提醒邮件, 当内存用量达到 MEMUSAGE_LIMIT_MB指定的值,发送提醒邮件,同时关闭spider, Scrapy进程退出。

该扩展通过 MEMUSAGE_ENABLED 配置项开启,可以使用以下选项:

内存调试器扩展

class scrapy.extensions.memdebug.MemoryDebugger

该扩展用于调试内存使用量,它收集以下信息: 存储的信息包括:

开启该扩展,需打开 MEMDEBUG_ENABLED 配置项。 信息将会存储在统计信息(stats)中。

关闭Spider扩展

class scrapy.extensions.closespider.CloseSpider

当某些状况发生,spider会自动关闭,每种情况使用指定的关闭原因。

关闭spider的情况可以通过下面的设置项配置:

CLOSESPIDER_TIMEOUT

默认值: 0

一个整数值,单位为秒。 如果一个spider在指定的秒数后仍在运行, 它将以 closespider_timeout 的原因被自动关闭。 如果值设置为0(或者没有设置),spiders不会因为超时而关闭。

CLOSESPIDER_ITEMCOUNT

缺省值: 0

一个整数值,指定条目的个数。 如果spider爬取条目数超过了指定的数, 并且这些条目通过item pipeline传递,spider将会以 closespider_itemcount 的原因被自动关闭。 如果零 (或非集合),Spider不会被任何传递的Item关闭。

CLOSESPIDER_PAGECOUNT

New in version 0.11.

缺省值: 0

一个整数值,指定最大的抓取响应(reponses)数。 如果spider抓取数超过指定的值,则会以 closespider_pagecount 的原因自动关闭。 如果设置为0(或者未设置),spiders不会因为抓取的响应数而关闭。

CLOSESPIDER_ERRORCOUNT

New in version 0.11.

缺省值: 0

一个整数值,指定spider可以接受的最大错误数。 如果spider生成多于该数目的错误,它将以 closespider_errorcount 的原因关闭。 如果设置为0(或者未设置),spiders不会因为发生错误过多而关闭。

StatsMailer extension

class scrapy.extensions.statsmailer.StatsMailer

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

调试扩展

Stack trace dump extension

class scrapy.extensions.debug.StackTraceDump

当收到 SIGQUITSIGUSR2信号,spider进程的信息将会被存储下来。存储的信息包括:

  1. engine状态(使用 scrapy.utils.engin.get_engine_status())
  2. 所有存活的引用(live references)(参考 使用 trackref 调试内存泄露)
  3. 所有线程的堆栈信息

当堆栈信息和engine状态存储后,Scrapy进程继续正常运行。

该扩展只在POSIX兼容平台上工作(即不能在Windows运行), 因为 SIGQUITSIGUSR2信号在Windows上不可用。

至少有两种方式可以向Scrapy发送 SIGQUIT信号:

  1. 在Scrapy进程运行时通过按Ctrl-(仅Linux可行?)

  2. 运行该命令(<pid> 是Scrapy运行的进程):

    kill -QUIT <pid>
    

调试扩展(Debugger extension)

class scrapy.extensions.debug.Debugger

当收到 SIGUSR2信号,将会在Scrapy进程中调用Python debugger debugger退出后,Scrapy进程继续正常运行。

更多信息参考 Debugging in Python

该扩展只在POSIX兼容平台上工作(比如不能再Windows上运行)。