爬虫中间件

爬虫中间件是 Scrapy 爬虫处理机制中的一个钩子框架,您可以在其中插入自定义功能来处理发送给爬虫进行处理的响应,以及处理从爬虫生成的请求和数据项。

激活爬虫中间件

要激活一个爬虫中间件组件,请将其添加到 SPIDER_MIDDLEWARES 设置中,该设置是一个字典,其键是中间件的类路径,值是中间件的顺序。

这里是一个例子

SPIDER_MIDDLEWARES = {
    "myproject.middlewares.CustomSpiderMiddleware": 543,
}

SPIDER_MIDDLEWARES 设置与 Scrapy 中定义的 SPIDER_MIDDLEWARES_BASE 设置(不应被覆盖)合并,然后按顺序排序,得到最终启用的中间件列表:第一个中间件离引擎最近,最后一个离爬虫最近。换句话说,每个中间件的 process_spider_input() 方法将按中间件顺序递增(100、200、300…)调用,而每个中间件的 process_spider_output() 方法将按递减顺序调用。

要决定给您的中间件分配哪个顺序,请参阅 SPIDER_MIDDLEWARES_BASE 设置,并根据您想要插入中间件的位置选择一个值。顺序很重要,因为每个中间件执行不同的操作,并且您的中间件可能依赖于某个先前(或后续)中间件的应用。

如果您想禁用一个内置中间件(在 SPIDER_MIDDLEWARES_BASE 中定义并默认启用的那些),您必须在项目的 SPIDER_MIDDLEWARES 设置中定义它,并将其值设为 None。例如,如果您想禁用站外中间件

SPIDER_MIDDLEWARES = {
    "scrapy.spidermiddlewares.referer.RefererMiddleware": None,
    "myproject.middlewares.CustomRefererSpiderMiddleware": 700,
}

最后,请记住,某些中间件可能需要通过特定设置启用。请参阅每个中间件的文档以获取更多信息。

编写自己的爬虫中间件

每个爬虫中间件都是一个组件,它定义了一个或多个以下方法

class scrapy.spidermiddlewares.SpiderMiddleware
async process_start(start: AsyncIterator[Any], /) AsyncIterator[Any]

迭代 start() 的输出,或早期爬虫中间件的 process_start() 方法的输出,并覆盖它。例如

async def process_start(self, start):
    async for item_or_request in start:
        yield item_or_request

您可以生成与 start() 相同类型的对象。

要编写适用于 Scrapy 2.13 以下版本的爬虫中间件,还需要定义一个返回可迭代对象的同步 process_start_requests() 方法。例如

def process_start_requests(self, start, spider):
    yield from start
process_spider_input(response)

此方法针对每个经过爬虫中间件并进入爬虫进行处理的响应调用。

process_spider_input() 应该返回 None 或抛出异常。

如果它返回 None,Scrapy 将继续处理此响应,执行所有其他中间件,直到最终将响应交给爬虫进行处理。

如果它抛出异常,Scrapy 将不再调用任何其他爬虫中间件的 process_spider_input() 方法,并且如果存在请求错误回调,则会调用它,否则将启动 process_spider_exception() 链。错误回调的输出将反向链接回 process_spider_output() 进行处理,如果它也抛出异常,则链接回 process_spider_exception()

参数:

response (Response 对象) – 正在处理的响应

async process_spider_output(response, result)

此方法是一个异步生成器,在爬虫处理完响应后,会使用爬虫的结果调用它。

另请参阅

通用爬虫中间件.

参数:
async process_spider_output_async(response, result)

实现通用爬虫中间件时,process_spider_output() 的替代名称。

process_spider_exception(response, exception)

当爬虫或 process_spider_output() 方法(来自前一个爬虫中间件)抛出异常时,会调用此方法。

process_spider_exception() 应该返回 None 或一个包含 Request数据项对象的迭代器。

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

如果它返回一个迭代器,则 process_spider_output() 管道将从下一个爬虫中间件开始启动,并且不会调用其他 process_spider_exception()

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

  • exception (Exception 对象) – 抛出的异常

通用爬虫中间件

在 Scrapy 2.6.3 及更低版本中,process_spider_output() 必须是一个同步生成器。

为了在同一个中间件中支持这些版本和更高的 Scrapy 版本,请将您的异步 process_spider_output() 方法重命名为 process_spider_output_async(),并定义一个供 2.6.3 及更低版本使用的同步 process_spider_output() 方法。

例如

class UniversalSpiderMiddleware:
    async def process_spider_output_async(self, response, result):
        async for r in result:
            # ... do something with r
            yield r

    def process_spider_output(self, response, result):
        for r in result:
            # ... do something with r
            yield r

自定义爬虫中间件的基类

Scrapy 提供了一个自定义爬虫中间件的基类。虽然不是强制要求使用,但它可以帮助简化中间件的实现。

class scrapy.spidermiddlewares.base.BaseSpiderMiddleware(crawler: Crawler)[source]

爬虫中间件的可选基类。

2.13 版本中新增。

这个类为异步 process_spider_output()process_start() 方法提供了辅助方法。不具备这些方法的中间件不需要使用这个类。

您可以覆盖 get_processed_request() 方法来添加请求的处理代码,并覆盖 get_processed_item() 方法来添加数据项的处理代码。这些方法从爬虫输出的可迭代对象中获取单个请求或数据项,并返回一个请求或数据项(相同或新的),或者返回 None 以将其从处理中移除。

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

从爬虫输出中返回一个已处理的数据项。

此方法会接收来自 start() 或爬虫输出的单个数据项。它应该返回相同或不同的数据项,或者返回 None 以忽略它。

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

  • response (Response 对象,或对于启动数据项为 None) – 正在处理的响应

返回:

已处理的数据项或 None

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

从爬虫输出中返回一个已处理的请求。

此方法会接收来自 start() 或爬虫输出的单个请求。它应该返回相同或不同的请求,或者返回 None 以忽略它。

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

  • response (Response 对象,或对于启动请求为 None) – 正在处理的响应

返回:

已处理的请求或 None

内置爬虫中间件参考

本页描述了 Scrapy 附带的所有爬虫中间件组件。有关如何使用它们以及如何编写自己的爬虫中间件的信息,请参阅爬虫中间件使用指南

有关默认启用组件(及其顺序)的列表,请参阅 SPIDER_MIDDLEWARES_BASE 设置。

DepthMiddleware

class scrapy.spidermiddlewares.depth.DepthMiddleware[source]

DepthMiddleware 用于跟踪正在抓取网站中每个 Request 的深度。它的工作原理是:当 request.meta['depth'] 没有预设值时(通常是第一个 Request),将其设置为 0,否则将其递增 1。

它可用于限制最大抓取深度,根据请求深度控制请求优先级等。

DepthMiddleware 可以通过以下设置进行配置(有关更多信息,请参阅设置文档)

  • DEPTH_LIMIT - 允许抓取任何站点的最大深度。如果为零,则不施加限制。

  • DEPTH_STATS_VERBOSE - 是否收集每个深度的请求数量。

  • DEPTH_PRIORITY - 是否根据请求的深度设置其优先级。

HttpErrorMiddleware

class scrapy.spidermiddlewares.httperror.HttpErrorMiddleware[source]

过滤掉不成功的(错误的)HTTP 响应,这样爬虫就不必处理它们,这(大多数时候)会增加开销,消耗更多资源,并使爬虫逻辑更复杂。

根据 HTTP 标准,成功的响应是那些状态码在 200-300 范围内的响应。

如果您仍然想处理该范围之外的响应代码,您可以使用 handle_httpstatus_list 爬虫属性或 HTTPERROR_ALLOWED_CODES 设置来指定爬虫能够处理的响应代码。

例如,如果您希望您的爬虫处理 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]

根据生成它的响应的 URL,填充请求的 Referer 请求头。

RefererMiddleware 设置

REFERER_ENABLED

默认值:True

是否启用 referer 中间件。

REFERRER_POLICY

默认值:'scrapy.spidermiddlewares.referer.DefaultReferrerPolicy'

填充请求 “Referer” 头时应用的Referer 策略

注意

您还可以通过使用特殊的 "referrer_policy" Request.meta 键,为每个请求设置 Referer 策略,其可接受值与 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.ReferrerPolicy[source]

Referer策略的抽象基类。

class scrapy.spidermiddlewares.referer.DefaultReferrerPolicy[source]

“no-referrer-when-downgrade” 的一个变体,额外增加了如果父请求使用 file://s3:// 方案,则不发送 “Referer” 头。

警告

Scrapy 的默认 Referer 策略——就像 “no-referrer-when-downgrade”(W3C 为浏览器推荐的值)一样——将从任何 http(s):// URL 向任何 https:// URL 发送一个非空的 “Referer” 头,即使域名不同。

如果您希望为跨域请求移除 referrer 信息,“same-origin” 可能是一个更好的选择。

class scrapy.spidermiddlewares.referer.NoReferrerPolicy[source]

https://w3org.cn/TR/referrer-policy/#referrer-policy-no-referrer

最简单的策略是“no-referrer”,它指定从特定请求客户端向任何源发出的请求不发送任何 referrer 信息。此头将被完全省略。

class scrapy.spidermiddlewares.referer.NoReferrerWhenDowngradePolicy[source]

https://w3org.cn/TR/referrer-policy/#referrer-policy-no-referrer-when-downgrade

“no-referrer-when-downgrade” 策略会在从受 TLS 保护的环境设置对象向潜在可信 URL 发出的请求中,以及从不受 TLS 保护的客户端向任何源发出的请求中,发送完整的 URL。

另一方面,从受 TLS 保护的客户端向非潜在可信 URL 发出的请求将不包含任何 referrer 信息。不会发送 Referer HTTP 头。

如果未另外指定策略,这是用户代理的默认行为。

注意

“no-referrer-when-downgrade” 策略是 W3C 推荐的默认值,并被主要网络浏览器使用。

然而,它不是 Scrapy 的默认 Referer 策略(请参阅 DefaultReferrerPolicy)。

class scrapy.spidermiddlewares.referer.SameOriginPolicy[source]

https://w3org.cn/TR/referrer-policy/#referrer-policy-same-origin

“same-origin” 策略指定,当从特定请求客户端发出同源请求时,将发送一个作为 referrer 使用的完整 URL(已剥离)。

另一方面,跨源请求将不包含任何 referrer 信息。不会发送 Referer HTTP 头。

class scrapy.spidermiddlewares.referer.OriginPolicy[source]

https://w3org.cn/TR/referrer-policy/#referrer-policy-origin

“origin” 策略指定,当从特定请求客户端发出同源请求和跨源请求时,仅发送请求客户端源的 ASCII 序列化作为 referrer 信息。

class scrapy.spidermiddlewares.referer.StrictOriginPolicy[source]

https://w3org.cn/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://w3org.cn/TR/referrer-policy/#referrer-policy-origin-when-cross-origin

“origin-when-cross-origin” 策略指定,当从特定请求客户端发出同源请求时,将发送一个作为 referrer 使用的完整 URL(已剥离),而当从特定请求客户端发出跨源请求时,仅发送请求客户端源的 ASCII 序列化作为 referrer 信息。

class scrapy.spidermiddlewares.referer.StrictOriginWhenCrossOriginPolicy[source]

https://w3org.cn/TR/referrer-policy/#referrer-policy-strict-origin-when-cross-origin

“strict-origin-when-cross-origin” 策略指定,当从特定请求客户端发出同源请求时,将发送一个作为 referrer 使用的完整 URL(已剥离),而当发出跨源请求时,仅发送请求客户端源的 ASCII 序列化,具体如下:

  • 从受 TLS 保护的环境设置对象向潜在可信 URL 发出时,以及

  • 从非 TLS 保护的环境设置对象向任何源发出时。

另一方面,从受 TLS 保护的客户端向非潜在可信 URL 发出的请求将不包含任何 referrer 信息。不会发送 Referer HTTP 头。

class scrapy.spidermiddlewares.referer.UnsafeUrlPolicy[source]

https://w3org.cn/TR/referrer-policy/#referrer-policy-unsafe-url

“unsafe-url” 策略指定,当从特定请求客户端发出跨源请求和同源请求时,都会发送一个作为 referrer 使用的完整 URL(已剥离)。

注意:此策略的名称并非虚言;它不安全。此策略会将 TLS 保护资源的源和路径泄露给不安全的源。请仔细考虑为潜在敏感文档设置此类策略的影响。

警告

不推荐使用“unsafe-url”策略。

REFERRER_POLICIES

版本 2.14.2 中新增。

默认值:{}

一个字典,将策略名称映射到 scrapy.spidermiddlewares.referer.ReferrerPolicy 子类的导入路径,或者 None 以禁用对给定策略名称的支持。

这允许覆盖由 Referrer-Policy 响应头触发的策略。

使用 "" 来覆盖没有 referrer 策略的响应的策略。

StartSpiderMiddleware

class scrapy.spidermiddlewares.start.StartSpiderMiddleware(crawler: Crawler)[source]

设置 is_start_request

is_start_request

启动请求中设置为 Truemeta 键,允许您区分启动请求和其他请求,例如在下载器中间件中。

UrlLengthMiddleware

class scrapy.spidermiddlewares.urllength.UrlLengthMiddleware[source]

过滤掉 URL 长度超过 URLLENGTH_LIMIT 的请求

UrlLengthMiddleware 可以通过以下设置进行配置(有关更多信息,请参阅设置文档)