Lzh on GitHub

Scrapy 广泛使用信号来通知特定事件的发生。你可以在你的 Scrapy 项目中捕获其中一些信号(例如,使用扩展)来执行额外的任务或扩展 Scrapy 以添加开箱即用的功能。

尽管信号提供了几个参数,但捕获它们的处理程序不需要接受所有参数——信号分发机制只会传递处理程序接收的参数。

你可以通过信号 API 连接到信号(或发送你自己的信号)。

这是一个简单的示例,展示了如何捕获信号并执行一些操作:

from scrapy import signals
from scrapy import Spider

class DmozSpider(Spider):
    name = "dmoz"
    allowed_domains = ["dmoz.org"]
    start_urls = [
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/",
    ]

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(DmozSpider, cls).from_crawler(crawler, *args, **kwargs)
        crawler.signals.connect(spider.spider_closed, signal=signals.spider_closed)
        return spider

    def spider_closed(self, spider):
        spider.logger.info("Spider closed: %s", spider.name)

    def parse(self, response):
        pass

延迟信号处理程序

某些信号支持从其处理程序返回 Deferredawaitable objects,允许你运行不阻塞 Scrapy 的异步代码。如果信号处理程序返回其中一个对象,Scrapy 会等待该异步操作完成。

让我们以协程为例:

import scrapy
import json
import treq # 假设 treq 已安装并用于异步 HTTP 请求

class SignalSpider(scrapy.Spider):
    name = "signals"
    start_urls = ["https://quotes.toscrape.com/page/1/"]

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(SignalSpider, cls).from_crawler(crawler, *args, **kwargs)
        crawler.signals.connect(spider.item_scraped, signal=signals.item_scraped)
        return spider

    async def item_scraped(self, item):
        # 将抓取到的项目发送到服务器
        response = await treq.post(
            "http://example.com/post",
            json.dumps(item).encode("ascii"),
            headers={b"Content-Type": [b"application/json"]},
        )

        return response

    def parse(self, response):
        for quote in response.css("div.quote"):
            yield {
                "text": quote.css("span.text::text").get(),
                "author": quote.css("small.author::text").get(),
                "tags": quote.css("div.tags a.tag::text").getall(),
            }

请参阅下面的内置信号参考,了解哪些信号支持 Deferredawaitable objects

内置信号参考

以下是 Scrapy 内置信号及其含义的列表。

引擎信号

engine_started

scrapy.signals.engine_started()

Scrapy 引擎开始抓取时发送。

此信号支持从其处理程序返回 deferreds。

注意: 此信号可能在 spider_opened 信号之后触发,具体取决于爬虫的启动方式。因此,不要依赖此信号在 spider_opened 之前触发。

engine_stopped

scrapy.signals.engine_stopped()

Scrapy 引擎停止时发送(例如,当抓取过程完成时)。

此信号支持从其处理程序返回 deferreds。

scheduler_empty

scrapy.signals.scheduler_empty()

每当引擎从调度器请求挂起请求(即调用其 next_request() 方法)并且调度器返回 None 时发送。

有关示例,请参阅延迟启动请求迭代。

项目信号

注意: 由于最多 CONCURRENT_ITEMS 个项目并行处理,许多 deferreds 使用 DeferredList 一起触发。因此,下一批等待 DeferredList 触发,然后为下一批抓取项目运行相应的项目信号处理程序。

item_scraped

scrapy.signals.item_scraped(item, response, spider)

在项目被抓取后,经过所有项目管道阶段(没有被丢弃)后发送。

此信号支持从其处理程序返回 deferreds。

参数:

  • item (项目对象) – 抓取到的项目
  • spider (Spider 对象) – 抓取项目的爬虫
  • response (Response | None) – 抓取项目的响应,如果从 start() 产出,则为 None

item_dropped

scrapy.signals.item_dropped(item, response, exception, spider)

当项目管道的某个阶段引发 DropItem 异常后,项目从项目管道中丢弃时发送。

此信号支持从其处理程序返回 deferreds。

参数:

  • item (项目对象) – 从项目管道中丢弃的项目
  • spider (Spider 对象) – 抓取项目的爬虫
  • response (Response | None) – 丢弃项目时所处的响应,如果从 start() 产出,则为 None
  • exception (DropItem 异常) – 导致项目被丢弃的异常(必须是 DropItem 子类)

item_error

scrapy.signals.item_error(item, response, spider, failure)

当项目管道生成错误(即引发异常)时发送,DropItem 异常除外。

此信号支持从其处理程序返回 deferreds。

参数:

  • item (项目对象) – 在项目管道中导致错误的项目
  • response (Response | None) – 引发异常时正在处理的响应,如果从 start() 产出,则为 None
  • spider (Spider 对象) – 引发异常的爬虫
  • failure (twisted.python.failure.Failure) – 引发的异常

爬虫信号

spider_closed

scrapy.signals.spider_closed(spider, reason)

爬虫关闭后发送。这可以用于释放 spider_opened 时保留的每个爬虫资源。

此信号支持从其处理程序返回 deferreds。

参数:

  • spider (Spider 对象) – 已关闭的爬虫
  • reason (str) – 描述爬虫关闭原因的字符串。如果因爬虫完成抓取而关闭,则原因为 'finished'。否则,如果爬虫通过调用 close_spider 引擎方法手动关闭,则原因为该方法的 reason 参数中传递的值(默认为 'cancelled')。如果引擎关闭(例如,通过按 Ctrl-C 停止它),原因将是 'shutdown'

spider_opened

scrapy.signals.spider_opened(spider)

爬虫已打开以进行抓取后发送。这通常用于保留每个爬虫资源,但可用于打开爬虫时需要执行的任何任务。

此信号支持从其处理程序返回 deferreds。

参数:

  • spider (Spider 对象) – 已打开的爬虫

spider_idle

scrapy.signals.spider_idle(spider)

当爬虫进入空闲状态时发送,这意味着爬虫不再有:

  • 等待下载的请求
  • 已调度的请求
  • 项目管道中正在处理的项目

如果在所有此信号的处理程序完成后空闲状态仍然存在,引擎将开始关闭爬虫。在爬虫完成关闭后,将发送 spider_closed 信号。

你可以引发 DontCloseSpider 异常以防止爬虫关闭。

或者,你可以引发 CloseSpider 异常以提供自定义的爬虫关闭原因。空闲处理程序是放置一些代码来评估最终爬虫结果并相应更新最终关闭原因(例如,将其设置为“too_few_results”而不是“finished”)的理想位置。

此信号不支持从其处理程序返回 deferreds。

参数:

  • spider (Spider 对象) – 已进入空闲状态的爬虫

注意: 在你的 spider_idle 处理程序中调度一些请求不能保证可以阻止爬虫关闭,尽管有时可以。这是因为如果所有调度的请求都被调度器拒绝(例如,由于重复而被过滤),爬虫可能仍保持空闲状态。

spider_error

scrapy.signals.spider_error(failure, response, spider)

当爬虫回调生成错误(即引发异常)时发送。

此信号不支持从其处理程序返回 deferreds。

参数:

  • failure (twisted.python.failure.Failure) – 引发的异常
  • response (Response 对象) – 引发异常时正在处理的响应
  • spider (Spider 对象) – 引发异常的爬虫

feed_slot_closed

scrapy.signals.feed_slot_closed(slot)

当 feed 导出槽关闭时发送。

此信号支持从其处理程序返回 deferreds。

参数:

  • slot (scrapy.extensions.feedexport.FeedSlot) – 关闭的槽

feed_exporter_closed

scrapy.signals.feed_exporter_closed()

当 feed 导出扩展关闭时发送,在扩展处理 spider_closed 信号期间,在所有 feed 导出处理完毕后。

此信号支持从其处理程序返回 deferreds。

请求信号

request_scheduled

scrapy.signals.request_scheduled(request, spider)

当引擎被要求调度一个 Request 以便稍后下载时发送,在请求到达调度器之前。

引发 IgnoreRequest 以在请求到达调度器之前将其丢弃。

此信号不支持从其处理程序返回 deferreds。

版本 2.11.2 新增: 允许使用 IgnoreRequest 丢弃请求。

参数:

  • request (Request 对象) – 到达调度器的请求
  • spider (Spider 对象) – 生成请求的爬虫

request_dropped

scrapy.signals.request_dropped(request, spider)

当引擎调度要稍后下载的 Request 被调度器拒绝时发送。

此信号不支持从其处理程序返回 deferreds。

参数:

  • request (Request 对象) – 到达调度器的请求
  • spider (Spider 对象) – 生成请求的爬虫

request_reached_downloader

scrapy.signals.request_reached_downloader(request, spider)

Request 到达下载器时发送。

此信号不支持从其处理程序返回 deferreds。

参数:

  • request (Request 对象) – 到达下载器的请求
  • spider (Spider 对象) – 生成请求的爬虫

request_left_downloader

版本 2.0 新增。

scrapy.signals.request_left_downloader(request, spider)

Request 离开下载器时发送,即使失败。

此信号不支持从其处理程序返回 deferreds。

参数:

  • request (Request 对象) – 到达下载器的请求
  • spider (Spider 对象) – 生成请求的爬虫

bytes_received

版本 2.2 新增。

scrapy.signals.bytes_received(data, request, spider)

当 HTTP 1.1 和 S3 下载处理程序收到特定请求的一组字节时发送。此信号可能对同一请求多次触发,每次都带有部分数据。例如,一个 25 kb 响应的可能场景是两次触发 10 kb 数据信号,最后一次触发 5 kb 数据信号。

此信号的处理程序可以通过引发 StopDownload 异常来停止正在进行的响应下载。有关更多信息和示例,请参阅停止响应下载主题。

此信号不支持从其处理程序返回 deferreds。

参数:

  • data (bytes 对象) – 下载处理程序接收的数据
  • request (Request 对象) – 生成下载的请求
  • spider (Spider 对象) – 与响应关联的爬虫

headers_received

版本 2.5 新增。

scrapy.signals.headers_received(headers, body_length, request, spider)

当给定请求的响应头可用时,在下载任何其他内容之前,由 HTTP 1.1 和 S3 下载处理程序发送。

此信号的处理程序可以通过引发 StopDownload 异常来停止正在进行的响应下载。有关更多信息和示例,请参阅停止响应下载主题。

此信号不支持从其处理程序返回 deferreds。

参数:

  • headers (scrapy.http.headers.Headers 对象) – 下载处理程序接收的头
  • body_length (int) – 响应体预期大小,以字节为单位
  • request (Request 对象) – 生成下载的请求
  • spider (Spider 对象) – 与响应关联的爬虫

响应信号

response_received

scrapy.signals.response_received(response, request, spider)

当引擎从下载器接收到新的 Response 时发送。

此信号不支持从其处理程序返回 deferreds。

参数:

  • response (Response 对象) – 接收到的响应
  • request (Request 对象) – 生成响应的请求
  • spider (Spider 对象) – 响应所属的爬虫

注意: 如果下载器中间件修改 Response 对象并设置特定的 request 属性,则 request 参数可能不包含到达下载器的原始请求。

response_downloaded

scrapy.signals.response_downloaded(response, request, spider)

下载器在 HTTPResponse 下载后立即发送。

此信号不支持从其处理程序返回 deferreds。

参数:

  • response (Response 对象) – 下载的响应
  • request (Request 对象) – 生成响应的请求
  • spider (Spider 对象) – 响应所属的爬虫