Lzh on GitHub

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

激活爬虫中间件

要激活一个爬虫中间件组件,请将其添加到 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, spider)

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

process_spider_input() 应该返回 None 或引发异常。

  • 如果它返回 None,Scrapy 将继续处理此响应,执行所有其他中间件,直到最终将响应交给爬虫进行处理。
  • 如果它引发异常,Scrapy 将不会调用任何其他爬虫中间件的 process_spider_input(),如果存在请求 errback,则将调用它,否则将启动 process_spider_exception() 链。errback 的输出将沿另一个方向链接回 process_spider_output() 进行处理,如果它引发异常,则由 process_spider_exception() 处理。

参数:

  • response (Response 对象) – 正在处理的响应
  • spider (Spider 对象) – 此响应所属的爬虫

process_spider_output(response, result, spider)

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

process_spider_output() 必须返回 Request 对象和 item 对象的迭代器。

版本 2.7 中的变化: 此方法可以定义为异步生成器,在这种情况下 result 是一个异步迭代器。

考虑将此方法定义为异步生成器,这将是 Scrapy 未来版本中的要求。但是,如果你打算与其他人共享你的爬虫中间件,请考虑强制将 Scrapy 2.7 作为你的爬虫中间件的最低要求,或者使你的爬虫中间件通用,以便它与 Scrapy 2.7 之前的版本一起工作。

参数:

  • response (Response 对象) – 爬虫生成此输出的响应
  • result (Request 对象和 item 对象的迭代器) – 爬虫返回的结果
  • spider (Spider 对象) – 正在处理其结果的爬虫

async process_spider_output_async(response, result, spider)

版本 2.7 新增。

如果定义,此方法必须是异步生成器,如果 result 是一个异步迭代器,则将调用此方法而不是 process_spider_output()

process_spider_exception(response, exception, spider)

当爬虫或 process_spider_output() 方法(来自上一个爬虫中间件)引发异常时,将调用此方法。

process_spider_exception() 应该返回 NoneRequestitem 对象的迭代器。

  • 如果它返回 None,Scrapy 将继续处理此异常,执行后续中间件组件中的任何其他 process_spider_exception(),直到没有中间件组件留下并且异常到达引擎(在那里它被记录和丢弃)。
  • 如果它返回一个可迭代对象,process_spider_output() 管道将启动,从下一个爬虫中间件开始,并且不会调用其他 process_spider_exception()

参数:

  • response (Response 对象) – 异常引发时正在处理的响应
  • exception (Exception 对象) – 引发的异常
  • spider (Spider 对象) – 引发异常的爬虫

自定义爬虫中间件的基类

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]

从爬虫输出返回已处理的项目。

此方法从启动种子或爬虫输出中获取单个项目。它应该返回相同或不同的项目,或者返回 None 以忽略它。

参数:

  • item (项目对象) – 输入项目
  • response (Response 对象或 None 用于启动种子) – 正在处理的响应

返回:

已处理的项目或 None

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

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

此方法从启动种子或爬虫输出中获取单个请求。它应该返回相同或不同的请求,或者返回 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.HttpErrorMiddlewaresource

过滤掉不成功的(错误的)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.RefererMiddlewaresource

根据生成它的 Response 的 URL 填充 RequestReferer 头。

RefererMiddleware 设置

  • REFERER_ENABLED
    • 默认值:True
    • 是否启用 referer 中间件。
  • REFERRER_POLICY
    • 默认值:'scrapy.spidermiddlewares.referer.DefaultReferrerPolicy'
    • 填充 Request “Referer” 头时要应用的 Referrer Policy。

注意: 你也可以使用特殊的 "referrer_policy" Request.meta 键按请求设置 Referrer Policy,其可接受值与 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 policy——就像 “no-referrer-when-downgrade”,W3C 推荐的浏览器值一样——将从任何 http(s):// 向任何 https:// URL 发送一个非空的 “Referer” 头,即使域名不同。如果你希望删除跨域请求的 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 policy(请参阅 DefaultReferrerPolicy)。

class scrapy.spidermiddlewares.referer.SameOriginPolicy[source]

https://www.w3.org/TR/referrer-policy/#referrer-policy-same-origin

“same-origin” 策略指定,当从特定请求客户端发出同源请求时,发送一个完整的 URL(为用作 referrer 而剥离)作为 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” 策略指定,当从特定请求客户端发出同源请求时,发送一个完整的 URL(为用作 referrer 而剥离)作为 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” 策略指定,当从特定请求客户端发出同源请求时,发送一个完整的 URL(为用作 referrer 而剥离)作为 referrer 信息;当从受 TLS 保护的环境设置对象到可能可信的 URL,以及从非 TLS 保护的环境设置对象到任何来源的跨源请求时,仅发送请求客户端起源的 ASCII 序列化。

另一方面,从受 TLS 保护的客户端到非可能可信的 URL 的请求将不包含 referrer 信息。将不发送 Referer HTTP 头。

class scrapy.spidermiddlewares.referer.UnsafeUrlPolicy[source]

https://www.w3.org/TR/referrer-policy/#referrer-policy-unsafe-url

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

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

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

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

  • URLLENGTH_LIMIT - 允许抓取 URL 的最大 URL 长度。