信号

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 treq


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 objects

内置信号参考

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

引擎信号

engine_started

scrapy.signals.engine_started()

当 Scrapy 引擎开始抓取时发送。

此信号支持异步处理程序

注意

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

engine_stopped

scrapy.signals.engine_stopped()

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

此信号支持异步处理程序

scheduler_empty

scrapy.signals.scheduler_empty()

每当引擎从调度器请求待处理的请求(即调用其 next_request() 方法)并且调度器返回空时发送。

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

此信号不支持异步处理程序

项信号

注意

由于最多有 CONCURRENT_ITEMS 个项目并行处理,许多延迟操作会使用 DeferredList 同时触发。因此,下一批会等待 DeferredList 触发,然后为下一批抓取的项目运行相应的项信号处理程序。

item_scraped

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

当项目被抓取后,在它通过所有项目管道阶段(未被丢弃)后发送。

此信号支持异步处理程序

参数:
  • item (项目对象) – 被抓取的项目

  • spider (Spider 对象) – 抓取该项目的爬虫

  • response (Response | None) – 抓取该项目时的响应,如果它是由 start() 产生的,则为 None

item_dropped

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

当一个项目从项目管道中被丢弃后发送,此时某个阶段抛出了 DropItem 异常。

此信号支持异步处理程序

参数:
  • item (项目对象) – 从项目管道中丢弃的项目

  • spider (Spider 对象) – 抓取该项目的爬虫

  • response (Response | None) – 丢弃该项目时的响应,如果它是由 start() 产生的,则为 None

  • exception (DropItem 异常) – 导致项目被丢弃的异常(必须是 DropItem 的子类)

item_error

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

项目管道产生错误(即抛出异常),DropItem 异常除外时发送。

此信号支持异步处理程序

参数:

爬虫信号

spider_closed

scrapy.signals.spider_closed(spider, reason)

在爬虫关闭后发送。这可用于释放通过 spider_opened 预留的每个爬虫资源。

此信号支持异步处理程序

参数:
  • spider (Spider 对象) – 已关闭的爬虫

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

spider_opened

scrapy.signals.spider_opened(spider)

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

此信号支持异步处理程序

参数:

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

spider_idle

scrapy.signals.spider_idle(spider)

当爬虫进入空闲状态时发送,这意味着爬虫没有进一步的

  • 待下载请求

  • 已调度请求

  • 项目管道中正在处理的项目

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

您可以抛出 DontCloseSpider 异常来阻止爬虫被关闭。

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

此信号不支持异步处理程序

参数:

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

注意

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

spider_error

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

当爬虫回调函数产生错误(即抛出异常)时发送。

此信号不支持异步处理程序

参数:

feed_slot_closed

scrapy.signals.feed_slot_closed(slot)

Feed Exports槽关闭时发送。

此信号支持异步处理程序

参数:

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

feed_exporter_closed

scrapy.signals.feed_exporter_closed()

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

此信号支持异步处理程序

memusage_warning_reached

scrapy.signals.memusage_warning_reached()

当内存使用量达到警告阈值 (MEMUSAGE_WARNING_MB) 时,由 MemoryUsage 扩展发送。

此信号不支持异步处理程序

请求信号

request_scheduled

scrapy.signals.request_scheduled(request, spider)

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

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

此信号不支持异步处理程序

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

参数:
  • request (Request 对象) – 到达调度器的请求

  • spider (Spider 对象) – 产生该请求的爬虫

request_dropped

scrapy.signals.request_dropped(request, spider)

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

此信号不支持异步处理程序

参数:
  • request (Request 对象) – 到达调度器的请求

  • spider (Spider 对象) – 产生该请求的爬虫

request_reached_downloader

scrapy.signals.request_reached_downloader(request, spider)

Request 到达下载器时发送。

此信号不支持异步处理程序

参数:
  • request (Request 对象) – 到达下载器的请求

  • spider (Spider 对象) – 产生该请求的爬虫

request_left_downloader

scrapy.signals.request_left_downloader(request, spider)

Request 离开下载器时发送,即使发生故障也是如此。

此信号不支持异步处理程序

参数:
  • request (Request 对象) – 到达下载器的请求

  • spider (Spider 对象) – 产生该请求的爬虫

bytes_received

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

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

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

此信号不支持异步处理程序

参数:
  • data (bytes 对象) – 下载处理程序接收到的数据

  • request (Request 对象) – 产生下载的请求

  • spider (Spider 对象) – 与响应关联的爬虫

headers_received

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

当 HTTP 1.1 和 S3 下载处理程序收到给定请求的响应头,并在下载任何额外内容之前发送。

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

此信号不支持异步处理程序

参数:
  • headers (scrapy.http.headers.Headers 对象) – 下载处理程序接收到的响应头

  • body_length (int) – 响应体的预期大小,以字节为单位

  • request (Request 对象) – 产生下载的请求

  • spider (Spider 对象) – 与响应关联的爬虫

响应信号

response_received

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

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

此信号不支持异步处理程序

参数:
  • response (Response 对象) – 收到的响应

  • request (Request 对象) – 产生响应的请求

  • spider (Spider 对象) – 响应所属的爬虫

注意

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

response_downloaded

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

由下载器在 Response 下载完成后立即发送。

此信号不支持异步处理程序

参数:
  • response (Response 对象) – 已下载的响应

  • request (Request 对象) – 产生响应的请求

  • spider (Spider 对象) – 响应所属的爬虫