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() 处理。

参数:
  • response (Response 对象) – 正在处理的响应

  • spider (Spider 对象) – 此响应的目标 Spider

process_spider_output(response, result, spider)

此方法在 Spider 处理完响应后,通过 Spider 返回的结果调用。

process_spider_output() 必须返回一个包含 Request 对象和 Item 对象 的可迭代对象。

版本 2.7 更改: 此方法可以定义为 异步生成器,在这种情况下,result 是一个 异步可迭代对象

建议将此方法定义为 异步生成器,这将在未来版本的 Scrapy 中成为必需。但是,如果您计划与他人共享您的 Spider 中间件,请考虑将 Scrapy 2.7 作为您的 Spider 中间件的最低要求,或使您的 Spider 中间件通用,以便它能在 Scrapy 2.7 之前的版本中使用。

参数:
  • response (Response 对象) – 从 Spider 生成此输出的响应

  • result (包含 Request 对象和 Item 对象 的可迭代对象) – 由 Spider 返回的结果

  • spider (Spider 对象) – 正在处理其结果的 Spider

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 或包含 RequestItem 对象的迭代对象。

如果返回 None,Scrapy 将继续处理此异常,执行后续中间件组件中的任何其他 process_spider_exception(),直到没有中间件组件,并且异常到达引擎(在那里被记录和丢弃)。

如果返回一个可迭代对象,则 process_spider_output() 管线将启动,从下一个 Spider 中间件开始,并且不会再调用其他 process_spider_exception() 方法。

参数:
  • response (Response 对象) – 引发异常时正在处理的响应

  • exception (Exception 对象) – 引发的异常

  • spider (Spider 对象) – 引发异常的 Spider

自定义 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。

get_processed_item(item: Any, response: Response | None) Any[source]

从 Spider 输出返回一个处理后的 Item。

此方法接收来自起始种子或 Spider 输出的单个 Item。它应该返回相同或不同的 Item,或返回 None 以忽略它。

参数:
  • item (Item 对象) – 输入的 Item

  • response (Response 对象 或 起始种子的 None) – 正在处理的响应

返回:

处理后的 Item 或 None

get_processed_request(request: Request, response: Response | None) Request | None[source]

从 Spider 输出返回一个处理后的请求。

此方法接收来自起始种子或 Spider 输出的单个请求。它应该返回相同或不同的请求,或返回 None 以忽略它。

参数:
  • request (Request 对象) – 输入的请求

  • response (Response 对象 或 起始种子的 None) – 正在处理的响应

返回:

处理后的请求或 None

内置 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_listHTTPERROR_ALLOWED_CODES 设置来指定 Spider 可以处理的响应代码。

例如,如果您希望您的 Spider 处理 404 响应,您可以这样做

from scrapy.spiders import CrawlSpider


class MySpider(CrawlSpider):
    handle_httpstatus_list = [404]

Request.metahandle_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"

字符串值

类名(字符串形式)

"scrapy-default" (默认)

scrapy.spidermiddlewares.referer.DefaultReferrerPolicy

“no-referrer”

scrapy.spidermiddlewares.referer.NoReferrerPolicy

“no-referrer-when-downgrade”

scrapy.spidermiddlewares.referer.NoReferrerWhenDowngradePolicy

“same-origin”

scrapy.spidermiddlewares.referer.SameOriginPolicy

“origin”

scrapy.spidermiddlewares.referer.OriginPolicy

“strict-origin”

scrapy.spidermiddlewares.referer.StrictOriginPolicy

“origin-when-cross-origin”

scrapy.spidermiddlewares.referer.OriginWhenCrossOriginPolicy

“strict-origin-when-cross-origin”

scrapy.spidermiddlewares.referer.StrictOriginWhenCrossOriginPolicy

“unsafe-url”

scrapy.spidermiddlewares.referer.UnsafeUrlPolicy

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 可以通过以下设置进行配置(更多信息请参见设置文档)