Spider 中间件
Spider 中间件是 Scrapy 的 Spider 处理机制中的一个钩子(hook)框架,您可以在其中插入自定义功能,用于处理发送给 Spiders 进行处理的响应,以及处理由 Spiders 生成的请求和 Item。
激活 Spider 中间件
要激活 Spider 中间件组件,请将其添加到 SPIDER_MIDDLEWARES
设置中。该设置是一个字典,其键是中间件类的路径,其值是中间件的顺序。
例如
SPIDER_MIDDLEWARES = {
"myproject.middlewares.CustomSpiderMiddleware": 543,
}
将 SPIDER_MIDDLEWARES
设置与 Scrapy 中定义的(且不应被覆盖的)SPIDER_MIDDLEWARES_BASE
设置合并,然后按顺序排序,得到最终的已启用中间件有序列表:第一个中间件最靠近引擎,最后一个最靠近 Spider。换句话说,每个中间件的 process_spider_input()
方法将按中间件顺序递增(100、200、300 等)调用,而每个中间件的 process_spider_output()
方法将按顺序递减调用。
要决定为您的中间件分配哪个顺序,请查看 SPIDER_MIDDLEWARES_BASE
设置,并根据您想要插入中间件的位置选择一个值。顺序确实很重要,因为每个中间件执行的操作不同,您的中间件可能依赖于之前(或之后)应用的某些中间件。
如果您想禁用内置中间件(在 SPIDER_MIDDLEWARES_BASE
中定义并默认启用的那些),您必须在项目的 SPIDER_MIDDLEWARES
设置中定义它,并将其值指定为 None
。例如,如果您想禁用 off-site 中间件
SPIDER_MIDDLEWARES = {
"scrapy.spidermiddlewares.referer.RefererMiddleware": None,
"myproject.middlewares.CustomRefererSpiderMiddleware": 700,
}
最后,请记住有些中间件可能需要通过特定的设置来启用。有关更多信息,请参阅每个中间件的文档。
编写自己的 Spider 中间件
每个 Spider 中间件都是一个 组件,它定义了以下一个或多个方法
- class scrapy.spidermiddlewares.SpiderMiddleware
- async process_start(start: AsyncIterator[Any], /) AsyncIterator[Any]
迭代
start()
方法的输出,或之前 Spider 中间件的process_start()
方法的输出,并覆盖它。例如async def process_start(self, start): async for item_or_request in start: yield item_or_request
您可以 yield 与
start()
相同类型的对象。要编写可在低于 2.13 的 Scrapy 版本上工作的 Spider 中间件,请同时定义一个同步的
process_start_requests()
方法,该方法返回一个可迭代对象。例如def process_start_requests(self, start, spider): yield from start
- process_spider_input(response, spider)
此方法对通过 Spider 中间件并进入 Spider 进行处理的每个响应调用。
process_spider_input()
应该返回None
或引发异常。如果返回
None
,Scrapy 将继续处理此响应,执行所有其他中间件,直到最终将响应交给 Spider 进行处理。如果引发异常,Scrapy 将不会再调用任何其他 Spider 中间件的
process_spider_input()
方法,并且会调用请求的回调(errback),如果存在的话;否则,它将开始process_spider_exception()
链。errback 的输出会反向链接回来,供process_spider_output()
处理,如果它(errback)也引发了异常,则由process_spider_exception()
处理。
- process_spider_output(response, result, spider)
此方法在 Spider 处理完响应后,通过 Spider 返回的结果调用。
process_spider_output()
必须返回一个包含Request
对象和 Item 对象 的可迭代对象。建议将此方法定义为 异步生成器,这将在未来版本的 Scrapy 中成为必需。但是,如果您计划与他人共享您的 Spider 中间件,请考虑将 Scrapy 2.7 作为您的 Spider 中间件的最低要求,或使您的 Spider 中间件通用,以便它能在 Scrapy 2.7 之前的版本中使用。
- async process_spider_output_async(response, result, spider)
版本 2.7 新增。
如果定义,此方法必须是 异步生成器,如果
result
是 异步可迭代对象,则会调用此方法而不是process_spider_output()
。
- process_spider_exception(response, exception, spider)
当 Spider 或
process_spider_output()
方法(来自之前的 Spider 中间件)引发异常时,会调用此方法。process_spider_exception()
应该返回None
或包含Request
或 Item 对象的迭代对象。如果返回
None
,Scrapy 将继续处理此异常,执行后续中间件组件中的任何其他process_spider_exception()
,直到没有中间件组件,并且异常到达引擎(在那里被记录和丢弃)。如果返回一个可迭代对象,则
process_spider_output()
管线将启动,从下一个 Spider 中间件开始,并且不会再调用其他process_spider_exception()
方法。
自定义 Spider 中间件的基类
Scrapy 提供了一个用于自定义 Spider 中间件的基类。虽然不是必须使用,但它可以帮助简化中间件的实现,并减少 通用中间件 中的样板代码。
- class scrapy.spidermiddlewares.base.BaseSpiderMiddleware(crawler: Crawler)[source]
可选的 Spider 中间件基类。
版本 2.13 新增。
此类为异步的
process_spider_output()
和process_start()
方法提供助手方法。没有这些方法的中间件不需要使用此类。您可以覆盖
get_processed_request()
方法来为请求添加处理代码,并覆盖get_processed_item()
方法来为 Item 添加处理代码。这些方法从 Spider 输出的可迭代对象中接收单个请求或 Item,并返回一个请求或 Item(可以是相同的或新的),或者返回None
以从处理中移除此请求或 Item。
内置 Spider 中间件参考
本页介绍所有随 Scrapy 提供的 Spider 中间件组件。有关如何使用它们以及如何编写自己的 Spider 中间件的信息,请参阅Spider 中间件使用指南。
有关默认启用组件(及其顺序)的列表,请参阅 SPIDER_MIDDLEWARES_BASE
设置。
DepthMiddleware
- class scrapy.spidermiddlewares.depth.DepthMiddleware[source]
DepthMiddleware 用于跟踪被抓取网站内每个 Request 的深度。它通过在之前未设置值(通常仅针对第一个 Request)时将
request.meta['depth'] = 0
,否则递增 1 来工作。它可用于限制抓取的最大深度,根据 Request 的深度控制优先级等。
可以通过以下设置配置
DepthMiddleware
(有关更多信息,请参阅设置文档)DEPTH_LIMIT
- 允许抓取任何网站的最大深度。如果为零,则不施加限制。DEPTH_STATS_VERBOSE
- 是否收集每个深度的请求数量。DEPTH_PRIORITY
- 是否根据请求的深度确定优先级。
HttpErrorMiddleware
- class scrapy.spidermiddlewares.httperror.HttpErrorMiddleware[source]
过滤掉不成功(错误)的 HTTP 响应,以便 Spider 无需处理它们,这(大多数情况下)会增加开销,消耗更多资源,并使 Spider 逻辑更复杂。
根据 HTTP 标准,成功的响应是状态码在 200-300 范围内的响应。
如果您仍然想处理该范围之外的响应代码,可以使用 Spider 属性 handle_httpstatus_list
或 HTTPERROR_ALLOWED_CODES
设置来指定 Spider 可以处理的响应代码。
例如,如果您希望您的 Spider 处理 404 响应,您可以这样做
from scrapy.spiders import CrawlSpider
class MySpider(CrawlSpider):
handle_httpstatus_list = [404]
Request.meta
的 handle_httpstatus_list
键也可以用来按请求指定允许的响应代码。如果您想允许请求的任何响应代码,您还可以将 meta 键 handle_httpstatus_all
设置为 True
,并将其设置为 False
来禁用 handle_httpstatus_all
键的效果。
但是,请记住,处理非 200 响应通常不是一个好主意,除非您非常清楚您在做什么。
有关更多信息,请参阅:HTTP 状态码定义。
HttpErrorMiddleware 设置
HTTPERROR_ALLOWED_CODES
默认值: []
传递包含在此列表中的所有非 200 状态码的响应。
HTTPERROR_ALLOW_ALL
默认值: False
传递所有响应,无论其状态码如何。
RefererMiddleware
- class scrapy.spidermiddlewares.referer.RefererMiddleware[source]
根据生成该 Request 的 Response 的 URL,填充 Request 的
Referer
头部。
RefererMiddleware 设置
REFERER_ENABLED
默认值: True
是否启用 referer 中间件。
REFERRER_POLICY
默认值: 'scrapy.spidermiddlewares.referer.DefaultReferrerPolicy'
填充 Request “Referer” 头部时应用的 Referrer Policy。
注意
您还可以为每个请求设置 Referrer Policy,使用特殊的 "referrer_policy"
Request.meta 键,其可接受值与 REFERRER_POLICY
设置相同。
REFERRER_POLICY 的可接受值
是
scrapy.spidermiddlewares.referer.ReferrerPolicy
子类的路径 - 自定义策略或内置策略之一(见下文类),或一个或多个逗号分隔的标准 W3C 定义的字符串值,
或特殊的
"scrapy-default"
。
- class scrapy.spidermiddlewares.referer.DefaultReferrerPolicy[source]
这是“no-referrer-when-downgrade”的一个变体,此外,如果父请求使用的是
file://
或s3://
方案,则不发送“Referer”。
警告
Scrapy 的默认 referrer 策略——就像 “no-referrer-when-downgrade”(W3C 推荐的浏览器值)一样——会将非空的“Referer”头部从任何 http(s)://
发送到任何 https://
URL,即使域名不同。
如果您希望在跨域请求中移除 referrer 信息,“same-origin” 可能是更好的选择。
- class scrapy.spidermiddlewares.referer.NoReferrerPolicy[source]
https://www.w3.org/TR/referrer-policy/#referrer-policy-no-referrer
最简单的策略是“no-referrer”,它指定从特定请求客户端发起的请求,无论目标源是什么,都不会发送 referrer 信息。头部将被完全省略。
- class scrapy.spidermiddlewares.referer.NoReferrerWhenDowngradePolicy[source]
https://www.w3.org/TR/referrer-policy/#referrer-policy-no-referrer-when-downgrade
“no-referrer-when-downgrade”策略会将完整的 URL 发送到从 TLS 保护的环境设置对象到潜在可信 URL 的请求中,以及从非 TLS 保护的客户端到任何源的请求中。
另一方面,从 TLS 保护的客户端到非潜在可信 URL 的请求将不包含 referrer 信息。不会发送 Referer HTTP 头部。
如果未另行指定策略,这是用户代理的默认行为。
注意
“no-referrer-when-downgrade”策略是 W3C 推荐的默认值,被主流网络浏览器使用。
然而,它不是 Scrapy 的默认 referrer 策略(参见 DefaultReferrerPolicy
)。
- class scrapy.spidermiddlewares.referer.SameOriginPolicy[source]
https://www.w3.org/TR/referrer-policy/#referrer-policy-same-origin
“same-origin”策略指定,从特定请求客户端发起的同源请求中,将发送一个为用作 referrer 而被剥离的完整 URL 作为 referrer 信息。
另一方面,跨域请求将不包含 referrer 信息。不会发送 Referer HTTP 头部。
- class scrapy.spidermiddlewares.referer.OriginPolicy[source]
https://www.w3.org/TR/referrer-policy/#referrer-policy-origin
“origin”策略指定,从特定请求客户端发起的同源请求和跨域请求中,仅发送请求客户端的源的 ASCII 序列化作为 referrer 信息。
- class scrapy.spidermiddlewares.referer.StrictOriginPolicy[source]
https://www.w3.org/TR/referrer-policy/#referrer-policy-strict-origin
“strict-origin”策略在以下情况下发送请求客户端的源的 ASCII 序列化:- 从 TLS 保护的环境设置对象到潜在可信 URL,以及 - 从非 TLS 保护的环境设置对象到任何源。
另一方面,从 TLS 保护的请求客户端到非潜在可信 URL 的请求将不包含 referrer 信息。不会发送 Referer HTTP 头部。
- class scrapy.spidermiddlewares.referer.OriginWhenCrossOriginPolicy[source]
https://www.w3.org/TR/referrer-policy/#referrer-policy-origin-when-cross-origin
“origin-when-cross-origin”策略指定,从特定请求客户端发起的同源请求中,将发送一个为用作 referrer 而被剥离的完整 URL 作为 referrer 信息;而从特定请求客户端发起的跨域请求中,仅发送请求客户端的源的 ASCII 序列化作为 referrer 信息。
- class scrapy.spidermiddlewares.referer.StrictOriginWhenCrossOriginPolicy[source]
https://www.w3.org/TR/referrer-policy/#referrer-policy-strict-origin-when-cross-origin
“strict-origin-when-cross-origin”策略指定,从特定请求客户端发起的同源请求中,将发送一个为用作 referrer 而被剥离的完整 URL 作为 referrer 信息;而从特定请求客户端发起跨域请求时,仅发送请求客户端的源的 ASCII 序列化,具体取决于:
从 TLS 保护的环境设置对象到潜在可信 URL,以及
从非 TLS 保护的环境设置对象到任何源。
另一方面,从 TLS 保护的客户端到非潜在可信 URL 的请求将不包含 referrer 信息。不会发送 Referer HTTP 头部。
- class scrapy.spidermiddlewares.referer.UnsafeUrlPolicy[source]
https://www.w3.org/TR/referrer-policy/#referrer-policy-unsafe-url
“unsafe-url”策略指定,从特定请求客户端发起的跨域请求和同源请求中,都会发送一个为用作 referrer 而被剥离的完整 URL。
注意:此策略的名称并不虚假;它是不安全的。此策略会将 TLS 保护资源的源和路径泄露给不安全的源。对于潜在的敏感文档,请仔细考虑设置此策略的影响。
警告
不建议使用“unsafe-url”策略。
StartSpiderMiddleware
- class scrapy.spidermiddlewares.start.StartSpiderMiddleware(crawler: Crawler)[source]
设置
is_start_request
。is_start_request
meta
键,在 start requests 中设置为True
,允许您区分 start requests 和其他请求,例如在 downloader middlewares 中。
UrlLengthMiddleware
- class scrapy.spidermiddlewares.urllength.UrlLengthMiddleware[source]
过滤掉 URL 长度超过 URLLENGTH_LIMIT 的请求
UrlLengthMiddleware
可以通过以下设置进行配置(更多信息请参见设置文档)URLLENGTH_LIMIT
- 允许爬取的 URL 的最大长度。