信号
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
延迟信号处理程序
某些信号支持从其处理程序返回 Deferred 或 awaitable 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(),
}
请参阅下面的内置信号参考,了解哪些信号支持 Deferred 和 awaitable 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对象) – 响应所属的爬虫