信号(Signals)

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 对象,允许您运行不阻塞 Scrapy 的异步代码。如果信号处理器返回这些对象之一,Scrapy 会等待该异步操作完成。

让我们来看一个使用 协程 的示例

import scrapy


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):
        # Send the scraped item to the server
        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 对象

内置信号参考

以下是 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_error

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

数据项管道 产生错误(即引发异常)时发送,DropItem 异常除外。

此信号支持其处理器返回 deferreds。

参数:

爬虫信号

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。

参数:

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

scrapy.signals.request_left_downloader(request, spider)

2.0 新增。

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 对象) – 响应所属的爬虫