如何处理Scrapy请求异常以避免爬虫终止并记录失败请求
问题核心原因说明
- 中间件不生效:你定义的
process_exception是下载器中间件的专属回调,如果你继承的是SpiderMiddleware基类自然不会触发;同时你自定义的1000状态码不在Scrapy默认允许的响应状态码范围内,即便中间件返回的响应不会进入parse方法。 - 爬虫自动停止:Scrapy默认不会因为单个请求失败停止整个爬虫,大概率是你配置了
CLOSESPIDER_ERRORCOUNT这类错误阈值配置,或者异常未捕获的异常直接抛出到顶层导致终止。
解决方法
方法一:直接实现errback逻辑(无需修改中间件,最简便)
你已经在Request中声明了errback=self.error_back参数,直接实现该方法即可捕获所有请求异常,同时不影响其他请求执行:
import json import scrapy def error_back(self, failure): # 记录错误信息,可自行改为写入数据库/其他存储 error_info = { "url": failure.request.url, "method": failure.request.method, "error": repr(failure.value), "body": failure.request.body.decode("utf8") if failure.request.body else "" } with open("error_pages.jsonl", "a", encoding="utf8") as f: f.write(json.dumps(error_info, ensure_ascii=False) + "\n") # 如果需要跳过当前失败页继续爬下一页,可直接构造下一页请求返回,也可以什么都不做,Scrapy会自动执行其他待调度的请求 # 示例:从meta中取当前页码构造下一页 # current_page = failure.request.meta.get("page", 1) # yield scrapy.Request( # url=f"你的分页前缀?page={current_page+1}", # callback=self.parse, # errback=self.error_back # ) def parse(self, response, **kwargs): if response.body: # 正常解析逻辑 ... yield item yield next_page_request()
方法二:修复现有下载器中间件
如果要继续使用你编写的中间件,修改3个点即可:
- 确认中间件继承自下载器中间件基类,注册路径无误:
# middlewares.py from scrapy.downloadermiddlewares import DownloaderMiddleware import json from scrapy.http import Response from scrapy.utils.python import to_bytes class MyDownloaderMiddleware(DownloaderMiddleware): def process_exception(self, request, exception, spider): body = dict(url=request.url, body=request.body.decode("utf8") if request.body else "", method=request.method, error=repr(exception)) return Response(url=request.url, status=1000, body=to_bytes(json.dumps(body)))
- 在配置中允许自定义状态码被parse接收,在
settings.py中添加配置:
HTTPERROR_ALLOWED_CODES = [1000]
- 在parse中处理异常响应,继续生成下一页请求:
def parse(self, response, **kwargs): if response.status == 1000: # 解析错误信息存储 error_info = json.loads(response.body.decode("utf8")) with open("error_pages.jsonl", "a", encoding="utf8") as f: f.write(json.dumps(error_info, ensure_ascii=False) + "\n" else: # 正常解析逻辑 if response.body: ... yield item # 无论当前页成功失败都继续爬下一页 yield next_page_request()
额外配置校验
- 确认
settings.py中没有配置CLOSESPIDER_ERRORCOUNT、CLOSESPIDER_TIMEOUT这类会提前终止爬虫的配置 - 不需要重试功能可以关闭
RETRY_ENABLED = False,避免重复请求错误页面
内容的提问来源于stack exchange,提问作者Liam lin
相关产品推荐
相关产品推荐

