扩展

扩展是 组件,允许您将自己的自定义功能插入到 Scrapy 中。

与其他组件不同,扩展在 Scrapy 中没有特定的角色。它们是“通配符”组件,可用于任何不适合其他任何类型组件角色的功能。

加载并激活扩展

扩展在启动时加载,每个运行中的爬虫创建一个扩展类的单一实例。

要启用扩展,请将其添加到 EXTENSIONS 设置中。例如

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

EXTENSIONS 会与 EXTENSIONS_BASE (不应被覆盖) 合并,结果值中的优先级决定了*加载*顺序。

由于扩展通常不相互依赖,因此在大多数情况下它们的加载顺序无关紧要。这就是为什么 EXTENSIONS_BASE 设置以相同的顺序 (0) 定义所有扩展。但是,如果您添加的扩展依赖于已加载的其他扩展,则可能需要仔细使用优先级。

编写您自己的扩展

每个扩展都是一个 组件

通常,扩展连接到 信号 并执行由它们触发的任务。

示例扩展

在这里,我们将实现一个简单的扩展来阐述上一节中描述的概念。该扩展将在每次以下情况发生时记录一条消息

  • 爬虫被打开

  • 爬虫被关闭

  • 抓取了特定数量的项

该扩展将通过 MYEXT_ENABLED 设置启用,项的数量将通过 MYEXT_ITEMCOUNT 设置指定。

以下是此类扩展的代码

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

logger = logging.getLogger(__name__)


class SpiderOpenCloseLogging:
    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[source]

记录抓取页面和抓取项等基本统计信息。

核心统计扩展

class scrapy.extensions.corestats.CoreStats[source]

启用核心统计信息的收集,前提是统计信息收集已启用 (参见 统计信息收集)。

收集以下统计信息

  • start_time: 抓取的开始日期/时间 (datetime)。

  • finish_time: 抓取的结束日期/时间 (datetime)。

  • elapsed_time_seconds: 抓取总时长,单位为秒 (float)。

  • finish_reason: 关闭原因字符串(例如 "finished", "closespider_timeout")。

  • item_scraped_count: 通过所有管道的项总数。

  • item_dropped_count: 被管道丢弃的项总数。

  • item_dropped_reasons_count/<ExceptionName>: 各异常的丢弃计数(例如 item_dropped_reasons_count/DropItem)。

  • response_received_count: 接收到的 HTTP 响应总数。

日志计数扩展

class scrapy.extensions.logcount.LogCount(crawler: Crawler)[source]

安装一个按级别统计日志消息的日志处理器。

安装的处理器是 scrapy.utils.log.LogCounterHandler。计数以 log_count/<level> 的形式存储在统计信息中。

2.14 版本中新增。

Telnet 控制台扩展

class scrapy.extensions.telnet.TelnetConsole[source]

提供一个 Telnet 控制台,用于进入当前运行的 Scrapy 进程中的 Python 解释器,这对于调试非常有用。

Telnet 控制台必须通过 TELNETCONSOLE_ENABLED 设置启用,服务器将监听 TELNETCONSOLE_PORT 中指定的端口。

内存使用扩展

class scrapy.extensions.memusage.MemoryUsage[source]

注意

此扩展不适用于 Windows。

监控运行爬虫的 Scrapy 进程使用的内存,并

  1. 当内存使用量超过 MEMUSAGE_WARNING_MB 时,发送 memusage_warning_reached 信号

  2. 当内存使用量超过 MEMUSAGE_LIMIT_MB 时,以 “memusage_exceeded” 为由关闭爬虫

此扩展通过 MEMUSAGE_ENABLED 设置启用,并可通过以下设置进行配置

内存调试器扩展

class scrapy.extensions.memdebug.MemoryDebugger[source]

一个用于调试内存使用的扩展。它收集有关以下信息

要启用此扩展,请打开 MEMDEBUG_ENABLED 设置。信息将存储在统计信息中。

爬虫状态扩展

class scrapy.extensions.spiderstate.SpiderState[source]

通过在爬取前加载和爬取后保存来管理爬虫状态数据。

JOBDIR 设置赋值以启用此扩展。启用后,此扩展管理您的 Spider 实例的 state 属性

  • 当您的爬虫关闭 (spider_closed) 时,其 state 属性的内容将被序列化到 JOBDIR 文件夹中名为 spider.state 的文件中。

  • 当您的爬虫打开 (spider_opened) 时,如果 JOBDIR 文件夹中存在之前生成的 spider.state 文件,它将被加载到 state 属性中。

有关示例,请参见 在批处理之间保持持久状态

关闭爬虫扩展

class scrapy.extensions.closespider.CloseSpider[source]

当满足某些条件时自动关闭爬虫,每个条件使用特定的关闭原因。

关闭爬虫的条件可通过以下设置进行配置

注意

当满足某个关闭条件时,当前在下载器队列中的请求(最多 CONCURRENT_REQUESTS 个请求)仍将继续处理。

CLOSESPIDER_TIMEOUT

默认值: 0.0

如果爬虫保持打开时间超过此秒数,它将以 closespider_timeout 为由自动关闭。如果为零(或未设置),爬虫不会因超时而关闭。

CLOSESPIDER_TIMEOUT_NO_ITEM

默认值:0

一个整数,指定秒数。如果爬虫在最后几秒内没有生成任何项,它将以 closespider_timeout_no_item 为由关闭。如果为零(或未设置),无论是否生成项,爬虫都不会关闭。

CLOSESPIDER_ITEMCOUNT

默认值:0

一个整数,指定项的数量。如果爬虫抓取数量超过此值且这些项通过了项管道,爬虫将以 closespider_itemcount 为由关闭。如果为零(或未设置),爬虫不会因通过的项数量而关闭。

CLOSESPIDER_PAGECOUNT

默认值:0

一个整数,指定要爬取的最大响应数量。如果爬虫爬取的数量超过此值,爬虫将以 closespider_pagecount 为由关闭。如果为零(或未设置),爬虫不会因爬取响应数量而关闭。

CLOSESPIDER_PAGECOUNT_NO_ITEM

默认值:0

一个整数,指定不抓取项的情况下连续爬取的最大响应数量。如果爬虫连续爬取的响应数量超过此值且在此期间未抓取任何项,爬虫将以 closespider_pagecount_no_item 为由关闭。如果为零(或未设置),爬虫不会因未抓取项的爬取响应数量而关闭。

CLOSESPIDER_ERRORCOUNT

默认值:0

一个整数,指定在关闭爬虫之前接收的最大错误数量。如果爬虫生成的错误数量超过此值,它将以 closespider_errorcount 为由关闭。如果为零(或未设置),爬虫不会因错误数量而关闭。

周期性日志扩展

class scrapy.extensions.periodic_log.PeriodicLog[source]

此扩展以 JSON 对象的形式周期性地记录丰富的统计数据

2023-08-04 02:30:57 [scrapy.extensions.logstats] INFO: Crawled 976 pages (at 162 pages/min), scraped 925 items (at 161 items/min)
2023-08-04 02:30:57 [scrapy.extensions.periodic_log] INFO: {
    "delta": {
        "downloader/request_bytes": 55582,
        "downloader/request_count": 162,
        "downloader/request_method_count/GET": 162,
        "downloader/response_bytes": 618133,
        "downloader/response_count": 162,
        "downloader/response_status_count/200": 162,
        "item_scraped_count": 161
    },
    "stats": {
        "downloader/request_bytes": 338243,
        "downloader/request_count": 992,
        "downloader/request_method_count/GET": 992,
        "downloader/response_bytes": 3836736,
        "downloader/response_count": 976,
        "downloader/response_status_count/200": 976,
        "item_scraped_count": 925,
        "log_count/INFO": 21,
        "log_count/WARNING": 1,
        "scheduler/dequeued": 992,
        "scheduler/dequeued/memory": 992,
        "scheduler/enqueued": 1050,
        "scheduler/enqueued/memory": 1050
    },
    "time": {
        "elapsed": 360.008903,
        "log_interval": 60.0,
        "log_interval_real": 60.006694,
        "start_time": "2023-08-03 23:24:57",
        "utcnow": "2023-08-03 23:30:57"
    }
}

此扩展记录以下可配置部分

  • "delta" 显示自上次统计日志消息以来某些数值统计数据如何变化。

    PERIODIC_LOG_DELTA 设置决定了目标统计数据。它们必须具有 intfloat 值。

  • "stats" 显示某些统计数据的当前值。

    PERIODIC_LOG_STATS 设置决定了目标统计数据。

  • "time" 显示详细的时间数据。

    PERIODIC_LOG_TIMING_ENABLED 设置决定是否显示此部分。

此扩展在开始时记录数据,然后以可通过 LOGSTATS_INTERVAL 设置配置的固定时间间隔记录,最后在爬取结束前记录。

示例扩展配置

custom_settings = {
    "LOG_LEVEL": "INFO",
    "PERIODIC_LOG_STATS": {
        "include": ["downloader/", "scheduler/", "log_count/", "item_scraped_count/"],
    },
    "PERIODIC_LOG_DELTA": {"include": ["downloader/"]},
    "PERIODIC_LOG_TIMING_ENABLED": True,
    "EXTENSIONS": {
        "scrapy.extensions.periodic_log.PeriodicLog": 0,
    },
}
PERIODIC_LOG_DELTA

默认值:None

  • "PERIODIC_LOG_DELTA": True - 显示所有 intfloat 统计值的增量。

  • "PERIODIC_LOG_DELTA": {"include": ["downloader/", "scheduler/"]} - 显示名称包含任何已配置子字符串的统计数据的增量。

  • "PERIODIC_LOG_DELTA": {"exclude": ["downloader/"]} - 显示名称不包含任何已配置子字符串的所有统计数据的增量。

PERIODIC_LOG_STATS

默认值:None

  • "PERIODIC_LOG_STATS": True - 显示所有统计数据的当前值。

  • "PERIODIC_LOG_STATS": {"include": ["downloader/", "scheduler/"]} - 显示名称包含任何已配置子字符串的统计数据的当前值。

  • "PERIODIC_LOG_STATS": {"exclude": ["downloader/"]} - 显示名称不包含任何已配置子字符串的所有统计数据的当前值。

PERIODIC_LOG_TIMING_ENABLED

默认值:False

True 启用时间数据(即 "time" 部分)的日志记录。

调试扩展

堆栈跟踪转储扩展

class scrapy.extensions.periodic_log.StackTraceDump

当接收到 SIGQUITSIGUSR2 信号时,转储有关运行进程的信息。转储的信息如下:

  1. 引擎状态(使用 scrapy.utils.engine.get_engine_status()

  2. 实时引用(参见 使用 trackref 调试内存泄漏

  3. 所有线程的堆栈跟踪

在堆栈跟踪和引擎状态转储后,Scrapy 进程继续正常运行。

此扩展仅适用于符合 POSIX 标准的平台(即非 Windows),因为 SIGQUITSIGUSR2 信号在 Windows 上不可用。

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

  1. 在 Scrapy 进程运行时按 Ctrl-\(仅限 Linux?)

  2. 通过运行此命令(假设 <pid> 是 Scrapy 进程的进程 ID)

    kill -QUIT <pid>
    

调试器扩展

class scrapy.extensions.periodic_log.Debugger

当接收到 SIGUSR2 信号时,在运行中的 Scrapy 进程内调用 Python 调试器。调试器退出后,Scrapy 进程继续正常运行。

此扩展仅适用于符合 POSIX 标准的平台(即非 Windows)。