如何配置Scrapy对返回307响应码的URL进行重试?
解决Scrapy对Zillow 307重定向不重试的问题
我之前爬Zillow时也遇到过一模一样的反爬问题,咱们一步步拆解排查和解决:
为什么你的307重试配置没生效?
Scrapy的RedirectMiddleware(默认优先级600)会优先处理所有重定向响应(包括307),它会自动发起新请求跳转到验证码页面,导致RetryMiddleware(优先级500)根本没机会接触到原始的307响应——这就是配置失效的核心原因。
第一步:让RetryMiddleware能捕获307响应
我们需要让RedirectMiddleware忽略307重定向,把响应留给重试中间件处理。在settings.py中添加以下配置:
# 让RedirectMiddleware跳过307的自动跳转处理 REDIRECT_IGNORED_CODES = [307] # 保留你原本的重试配置 RETRY_HTTP_CODES = [500, 503, 504, 400, 408, 307, 403] RETRY_TIMES = 5
第二步:重试时强制更换代理(关键优化)
Zillow的反爬非常严格,307跳转到验证码页基本意味着当前代理已经被识别。如果重试时还用同一个代理,大概率还是会被拦截。我们需要自定义重试逻辑,每次重试都换一个新代理:
- 在你的项目中间件文件(比如
middlewares.py)中添加自定义重试中间件:
from scrapy.downloadermiddlewares.retry import RetryMiddleware from scrapy.utils.response import response_status_message class CustomRetryMiddleware(RetryMiddleware): def process_response(self, request, response, spider): # 检查是否是需要重试的响应码(包含307) if response.status in self.retry_http_codes: reason = response_status_message(response.status) # 移除当前请求绑定的代理,让代理中间件重新获取新IP request.meta.pop('proxy', None) # 发起重试请求 return self._retry(request, reason, spider) or response # 其他正常情况交给父类处理 return super().process_response(request, response, spider)
- 在
settings.py中替换默认的RetryMiddleware为自定义版本:
DOWNLOADER_MIDDLEWARES = { # 替换默认重试中间件为自定义版本 'real_estate.middlewares.CustomRetryMiddleware': 500, 'real_estate.middlewares.RealEstateDownloaderMiddleware': 100, 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110, 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, 'scrapy_fake_useragent.middleware.RandomUserAgentMiddleware': 400, }
额外的反爬优化建议
除了重试逻辑,这些操作也能大幅降低被Zillow拦截的概率:
- 补全请求头:添加
Accept-Language、Referer、Cache-Control等真实浏览器会携带的字段 - 控制爬取节奏:设置
DOWNLOAD_DELAY = 2并开启AUTOTHROTTLE_ENABLED = True - 维护高质量代理池:优先使用高匿、动态轮换的住宅IP,避免使用公开代理
- 保持会话一致性:Scrapy默认会自动处理Cookie,但可以手动确保请求携带合理的会话信息
内容的提问来源于stack exchange,提问作者Arindam Ghosh
相关产品推荐
相关产品推荐

