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

Scrapy自定义下载中间件触发robotstxt递归深度超限错误如何解决

问题根因

核心问题出在你自定义中间件process_request方法的返回值不符合Scrapy规范:
Scrapy的下载中间件process_request方法如果要让请求继续向下执行后续中间件,必须返回None,而你在else分支返回了request对象。当Scrapy接收到process_request返回的Request对象时,会将该请求重新送入整个下载中间件链从头开始处理,直接导致无限循环:

  1. 爬虫启动后自动发起robots.txt请求
  2. 请求过中间件到你的自定义逻辑时,URL不在已访问集合,返回request
  3. 请求被重新送入中间件链,再次走到你的自定义逻辑,再次返回request
  4. 循环往复直到达到Python递归深度上限,抛出你看到的报错。

解决思路

1. 修复返回值(必改)

直接修改process_request方法的else分支,把return request改为return None即可,代码修改后如下:

def process_request(self, request, spider):
    if request.url in self.urls_visited:
        logging.info('url already scraped: %s', request.url)
        raise IgnoreRequest()
    # 返回None即可让后续中间件继续处理请求
    return None

2. 可选优化

  • 把存储已访问URL的容器改为set类型,in查询时间复杂度从O(n)降到O(1),如果你的已访问URL量很大,性能提升会非常明显
  • 当前你的已访问URL只在中间件初始化时从数据库拉取一次,同一次爬虫运行中新抓取的URL不会被加入到校验集合,会导致同一次运行中的重复URL无法被过滤,建议在process_response中判断请求成功后,把URL加入self.urls_visited同时写入数据库
  • 可以把自定义中间件的顺序调到RobotsTxtMiddleware之前,已抓取的URL可以直接被拦截,不需要再走robots校验、超时判断等逻辑,节省资源
  • 可以增加robots.txt请求的豁免逻辑,避免对Scrapy自动发起的系统请求做不必要的校验:
def process_request(self, request, spider):
    # 豁免robots.txt系统请求
    if request.url.endswith('robots.txt'):
        return None
    if request.url in self.urls_visited:
        logging.info('url already scraped: %s', request.url)
        raise IgnoreRequest()
    return None

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 00:45:02