2.6 Middleware (中间件)


文档摘要

2.6 Middleware (中间件) 2.6 Middleware (中间件) 在 Scrapy 中,中间件 (Middleware) 扮演着“管道”的角色,它允许你自定义 Scrapy 处理请求 (Request) 和响应 (Response) 的流程。你可以使用中间件来修改请求、过滤响应、处理异常等,从而实现各种强大的功能。Scrapy 中间件分为两种类型: Spider Middlewares (爬虫中间件): 处理 Scrapy 引擎和 Spiders 之间的交互。 Downloader Middlewares (下载器中间件): 处理 Scrapy 引擎和 Downloader 之间的交互。 2.6.

2.6 Middleware (中间件)

2.6 Middleware (中间件)

在 Scrapy 中,中间件 (Middleware) 扮演着“管道”的角色,它允许你自定义 Scrapy 处理请求 (Request) 和响应 (Response) 的流程。你可以使用中间件来修改请求、过滤响应、处理异常等,从而实现各种强大的功能。Scrapy 中间件分为两种类型:

  • Spider Middlewares (爬虫中间件): 处理 Scrapy 引擎和 Spiders 之间的交互。

  • Downloader Middlewares (下载器中间件): 处理 Scrapy 引擎和 Downloader 之间的交互。

2.6.1 Middleware 的作用

中间件的主要作用包括:

  • 修改请求 (Request): 在请求发送到 Downloader 之前,可以修改请求的 Headers、Cookies、Proxy 等。

  • 过滤响应 (Response): 在响应返回给 Spider 之前,可以根据状态码、内容类型等过滤响应。

  • 处理异常: 捕获并处理 Downloader 或 Spider 抛出的异常,例如重试失败的请求。

  • 实现通用功能: 比如处理重定向、设置 User-Agent、进行身份验证等。

2.6.2 Middleware 的工作流程

以下是 Downloader Middleware 和 Spider Middleware 在 Scrapy 中的工作流程图:

  • Downloader Middlewares:

    • 当 Engine 调度一个 Request 时,它会依次通过 Downloader Middlewares 的 process_request 方法。

    • Downloader 处理完 Request 后,生成一个 Response,Response 会依次通过 Downloader Middlewares 的 process_response 方法。

    • 如果在 Downloader 或 process_request 过程中发生异常,会调用 Downloader Middlewares 的 process_exception 方法。

  • Spider Middlewares:

    • 当 Downloader 返回 Response 给 Engine 后,Engine 会将 Response 传递给 Spider Middlewares 的 process_spider_input 方法。

    • Spider 处理完 Response 后,生成 Item 或 Request,这些 Item 或 Request 会依次通过 Spider Middlewares 的 process_spider_output 方法。

    • 如果在 Spider 或 process_spider_input 过程中发生异常,会调用 Spider Middlewares 的 process_spider_exception 方法。

2.6.3 编写自定义 Middleware

要编写自定义 Middleware,你需要创建一个类,并实现以下一个或多个方法:

Downloader Middleware:

  • process_request(request, spider): 在请求发送到 Downloader 之前调用。

  • process_response(request, response, spider): 在 Downloader 返回响应之后调用。

  • process_exception(request, exception, spider): 当 Downloader 或 process_request 抛出异常时调用。

Spider Middleware:

  • process_spider_input(response, spider): 在 Response 进入 Spider 之前调用。

  • process_spider_output(response, result, spider): 在 Spider 处理完 Response 后调用。

  • process_spider_exception(response, exception, spider): 当 Spider 或 process_spider_input 抛出异常时调用。

  • process_start_requests(start_requests, spider): 处理 start_requests,必须返回一个可迭代对象。

示例:Downloader Middleware - User-Agent 轮换

import random from scrapy import signals class RandomUserAgentMiddleware: def __init__(self, user_agent_list): self.user_agent_list = user_agent_list @classmethod def from_crawler(cls, crawler): return cls(crawler.settings.getlist('USER_AGENT_LIST')) def process_request(self, request, spider): ua = random.choice(self.user_agent_list) request.headers['User-Agent'] = ua

示例:Downloader Middleware - 代理 IP 轮换

import random class ProxyMiddleware: def __init__(self, proxy_list): self.proxy_list = proxy_list @classmethod def from_crawler(cls, crawler): return cls(crawler.settings.getlist('PROXY_LIST')) def process_request(self, request, spider): proxy = random.choice(self.proxy_list) request.meta['proxy'] = proxy

示例:Spider Middleware - 处理无效 Item

class ValidationMiddleware: def process_spider_output(self, response, result, spider): for item in result: if not isinstance(item, dict) or not item.get('title'): # 假设 title 是必须的 print(f"Invalid item found, skipping: {item}") continue # Skip the item yield item

方法详解:

  • process_request(request, spider):

    • request: scrapy.Request 对象,代表即将发送的请求。

    • spider: 处理该请求的 Spider 对象。

    • 返回值:

      • None: Scrapy 将继续处理该请求,继续执行其他的downloader middleware直到request到达downloader。

      • Response 对象: Scrapy 将不会继续处理该请求,直接返回该 Response。

      • Request 对象: Scrapy 将停止处理该请求,并重新调度该 Request。

      • IgnoreRequest 异常: Scrapy 将忽略该请求。

  • process_response(request, response, spider):

    • request: scrapy.Request 对象,代表生成该响应的请求。

    • response: scrapy.Response 对象,代表 Downloader 返回的响应。

    • spider: 处理该响应的 Spider 对象。

    • 返回值:

      • Response 对象: Scrapy 将继续处理该响应,继续执行其他的downloader middleware直到response到达spider。

      • Request 对象: Scrapy 将停止处理该响应,并重新调度该 Request。

  • process_exception(request, exception, spider):

    • request: scrapy.Request 对象,代表发生异常的请求。

    • exception: 发生的异常对象。

    • spider: 处理该请求的 Spider 对象。

    • 返回值:

      • None: Scrapy 将继续处理该异常,继续执行其他的downloader middleware直到异常被处理。

      • Response 对象: Scrapy 将使用该 Response 来代替原来的异常。

      • Request 对象: Scrapy 将重新调度该 Request。

  • process_spider_input(response, spider):

    • response: scrapy.Response 对象,代表 Downloader 返回的响应。

    • spider: 处理该响应的 Spider 对象。

    • 返回值:

      • 必须返回 None 或者抛出一个异常。如果返回 None,Scrapy 将继续处理该响应,并将它传递给 Spider。如果抛出一个异常,Scrapy 将调用 process_spider_exception 方法。
  • process_spider_output(response, result, spider):

    • response: scrapy.Response 对象,代表 Spider 处理的响应。

    • result: 一个可迭代对象,包含 Spider 生成的 Item 或 Request。

    • spider: 处理该响应的 Spider 对象。

    • 返回值:

      • 必须返回一个可迭代对象,包含 Item 或 Request。
  • process_spider_exception(response, exception, spider):

    • response: scrapy.Response 对象,代表发生异常的响应。

    • exception: 发生的异常对象。

    • spider: 处理该响应的 Spider 对象。

    • 返回值:

      • 应该返回 None 或者一个可迭代对象,包含 Item 或 Request。如果返回 None,Scrapy 将继续处理该异常,并将它传递给其他的 Spider Middleware。如果返回一个可迭代对象,Scrapy 将停止处理该异常,并将该可迭代对象传递给 Engine。
  • process_start_requests(start_requests, spider):

    • start_requests: 一个包含 start requests 的可迭代对象。

    • spider: 启动请求的 Spider 对象。

    • 返回值:

      • 必须返回一个包含 Request 对象的可迭代对象。

2.6.4 启用 Middleware

要启用自定义 Middleware,需要在 settings.py 文件中进行配置。 使用 DOWNLOADER_MIDDLEWARESSPIDER_MIDDLEWARES 字典来配置中间件。 键是中间件类的路径,值是中间件的优先级。

示例:

DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.RandomUserAgentMiddleware': 543, 'myproject.middlewares.ProxyMiddleware': 750, } SPIDER_MIDDLEWARES = { 'myproject.middlewares.ValidationMiddleware': 800, } # 设置 User-Agent 列表 (在 settings.py 中) USER_AGENT_LIST = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0', ] # 设置代理 IP 列表 (在 settings.py 中) PROXY_LIST = [ 'http://10.10.1.10:3128', 'http://10.10.1.11:1080', ]

优先级:

  • 数值越小,优先级越高。

  • Scrapy 默认的 Middleware 优先级范围是 0-1000。

  • 自定义 Middleware 的优先级应该在这个范围内。

2.6.5 实践案例

1. RetryMiddleware (重试中间件): Scrapy 内置的 RetryMiddleware 可以自动重试失败的请求。你可以在 settings.py 中启用它,并配置重试次数、重试状态码等。

DOWNLOADER_MIDDLEWARES = { 'scrapy.downloadermiddlewares.retry.RetryMiddleware': 90, } RETRY_ENABLED = True RETRY_TIMES = 3 RETRY_HTTP_CODES = [500, 502, 503, 504, 400, 408]

2. HttpProxyMiddleware (代理中间件): Scrapy 内置的 HttpProxyMiddleware 可以使用代理 IP。你可以在 settings.py 中启用它,并配置代理 IP。 也可以使用上面的自定义 ProxyMiddleware 实现更灵活的代理轮换策略。

DOWNLOADER_MIDDLEWARES = { 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110, } # 在 Request 中设置代理 def start_requests(self): yield scrapy.Request(url='http://example.com', meta={'proxy': 'http://some.proxy.com:8080'})

3. CookiesMiddleware (Cookies 中间件): Scrapy 内置的 CookiesMiddleware 可以处理 Cookies。 默认情况下,Scrapy 会自动处理 Cookies。 你可以自定义 CookiesMiddleware 来实现更复杂的 Cookies 管理。

2.6.6 注意事项

  • Middleware 的顺序很重要,它决定了 Middleware 的执行顺序。

  • 不要在 Middleware 中执行耗时的操作,这会影响 Scrapy 的性能。

  • 使用 Middleware 时,要仔细测试,确保它不会引入新的问题。

  • 合理使用 Middleware 可以提高 Scrapy 的灵活性和可扩展性。

  • from_crawler 方法是可选的,但建议使用,它可以让你访问 Scrapy 的设置。

2.6.7 总结

Middleware 是 Scrapy 中一个非常强大的组件,它允许你自定义 Scrapy 的请求和响应处理流程。通过编写自定义 Middleware,你可以实现各种强大的功能,例如 User-Agent 轮换、代理 IP 轮换、Cookies 管理、重试失败的请求等。 掌握 Middleware 的使用,可以让你更好地控制 Scrapy 的行为,并构建更强大的爬虫。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U