Scrapy技术咨询:遇403/302状态码时如何通过中间件更换新代理?
Scrapy代理中间件优化:针对403/302状态码更换代理
先看看你当前的中间件代码:
def process_request(self, request, spider): request = self.change_proxy(request) # 设置请求代理 def process_response(self, request, response, spider): if response.status != 200: self.delete_proxy() # 删除不可用代理 return request.copy() # 将请求发送至process_request以更换代理 return response def process_exception(self, request, exception, spider): self.delete_proxy() # 删除不可用代理 # 若注释掉以下代码,我将不会遇到302状态码。
我发现几个关键问题,帮你逐个修正:
- process_request未返回请求:Scrapy的
process_request方法如果不返回request或None,请求会直接被丢弃,你的代理设置根本没生效。必须加上return request才能让设置好代理的请求继续流转。 - 非200状态范围太宽泛:你目标是处理403(访问被拒)和302(重定向,大概率是反爬策略),没必要拦截所有非200状态(比如404可能是页面本身不存在,换代理也没用)。所以要把判断改成精准匹配
if response.status in (302, 403)。 - process_exception的返回逻辑缺失:你提到注释掉这里的代码就不会碰到302,大概率是因为部分302是通过重定向异常触发的。这里需要返回重新处理的请求,同时要避免被Scrapy的去重机制过滤。
修正后的完整代码:
def process_request(self, request, spider): # 设置代理后必须返回request,否则请求会被直接丢弃 request = self.change_proxy(request) return request def process_response(self, request, response, spider): # 只针对目标状态码处理 if response.status in (302, 403): self.delete_proxy() # 复制请求并标记dont_filter,避免被去重过滤 new_request = request.copy() new_request.dont_filter = True return new_request return response def process_exception(self, request, exception, spider): self.delete_proxy() # 异常时重新生成请求,同样标记dont_filter new_request = request.copy() new_request.dont_filter = True return new_request
额外提醒:
- 记得在
settings.py里启用这个中间件,设置合适的优先级(一般比默认中间件高,比如DOWNLOADER_MIDDLEWARES = {'yourproject.middlewares.ProxyMiddleware': 543,})。 - 确保
change_proxy方法能正确给请求设置代理,比如request.meta['proxy'] = 'http://xxx.xxx.xxx.xxx:port'。 - 给重新发送的请求加上
dont_filter=True非常关键,不然Scrapy会判定为重复请求直接过滤,不会重新发起。
内容的提问来源于stack exchange,提问作者user9320130
相关产品推荐
相关产品推荐

