You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrapy中失败请求重试下载中间件的报错修复问题

问题修复方案

核心错误分析

  1. 中间件继承错误:下载中间件应继承scrapy.downloadermiddlewares.DownloaderMiddleware而非Spider,继承Spider会导致中间件逻辑完全混乱。
  2. process_response返回值违规:该方法不支持yield生成器,必须返回单个Response/Request对象,或抛出IgnoreRequest,原代码循环yield请求直接违反规则。
  3. 状态码判断逻辑失效:response.status是整数类型,原代码用字符串列表['401','403','410']判断,永远无法匹配。
  4. 重试逻辑设计错误:手动循环发送请求不符合Scrapy的请求调度机制,应利用框架原生的重试参数或request.meta控制重试次数。
  5. 错误的Spider调用方式:直接实例化XxxSpider()调用parse_event会绕过Scrapy引擎调度,无法正确处理响应。

修复后的代码实现

from scrapy import Request
from scrapy.exceptions import IgnoreRequest

class NegativeResponsesDownloaderMiddleware:
    # 定义需要拦截的错误状态码(整数类型)
    FILTERED_STATUSES = {401, 403, 410}

    def process_response(self, request, response, spider):
        # 获取配置的最大重试次数,默认3次
        max_retry_times = spider.settings.getint('ERROR_HANDLING_ATTACK_RATE', 3)
        # 获取当前已重试次数,默认0
        current_retry = request.meta.get('retry_times', 0)

        if response.status in self.FILTERED_STATUSES:
            spider.logger.warning(f"拦截错误状态码 {response.status} | URL: {response.url} | 已重试 {current_retry} 次")
            
            if current_retry < max_retry_times:
                # 复制原请求,保留headers、回调、cookies等参数
                retry_request = request.copy()
                retry_request.meta['retry_times'] = current_retry + 1
                retry_request.dont_filter = True  # 避免被去重机制过滤
                return retry_request
            else:
                # 达到最大重试次数,记录错误并终止请求
                spider.logger.error(f"URL {response.url} 重试 {max_retry_times} 次仍失败 | 状态码: {response.status}")
                raise IgnoreRequest(f"URL {response.url} 重试次数耗尽")
        
        # 状态码正常,返回原响应给爬虫
        return response

关键优化说明

  • 遵循框架规则:通过request.meta['retry_times']跟踪重试次数,返回单个重试请求,符合process_response的返回要求。
  • 请求复用:用request.copy()复制原请求,避免手动构造请求时丢失原有参数(如headers、回调函数)。
  • 日志规范化:用Spider内置logger替代print,便于Scrapy日志统一管理和排查问题。
  • 去重控制:设置dont_filter=True,确保重试请求不会被Scrapy的去重机制拦截。

额外配置建议

在settings.py中添加重试次数配置:

# 错误状态码的最大重试次数
ERROR_HANDLING_ATTACK_RATE = 3

如果需要更精细的重试策略(如不同状态码对应不同重试次数),可以结合Scrapy自带的RetryMiddleware进行扩展,无需完全自定义中间件。

内容的提问来源于stack exchange,提问作者avakado0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 07:36:18