如何避免Scrapy请求URL被重定向?爬取遇验证及连接问题求助
解决Scrapy爬取被重定向人机验证+代理/UA失效问题
看来你在Scrapy爬取时遇到了挺棘手的反爬困境啊——一会儿能正常跑一会儿直接失效,还被强制重定向到人机验证页面,折腾了免费代理和UA轮换也没搞定,还一堆TCP超时、连接丢失的错误,太闹心了!我来帮你拆解下问题,给你几个实用的解决方案:
先分析核心问题
- 免费代理质量太差:
free-proxy-list.net上的免费代理大多是公开共享的,要么已经失效、速度慢,要么早就被目标网站拉黑了,用它们大概率会出现超时、连接丢失,甚至直接触发更严格的反爬。 - UA轮换有bug:你的
RotateUserAgentMiddleware里第一个UA字符串末尾少了个逗号!这会导致第一个和第二个UA直接拼接成无效字符串,等于UA轮换根本没正常工作。 - 请求特征太机械:除了UA,请求头不全、会话管理缺失(比如禁用了Cookie)、爬取节奏太固定,都容易被网站识别为爬虫。
针对性解决方案
1. 修复UA轮换的bug
把RotateUserAgentMiddleware里的user_agent_list第一个UA末尾补上逗号,确保每个UA都是独立的字符串:
class RotateUserAgentMiddleware(UserAgentMiddleware): def __init__(self, user_agent=''): self.user_agent = user_agent def process_request(self, request, spider): ua = random.choice(self.user_agent_list) if ua: request.headers.setdefault('User-Agent', ua) user_agent_list = [ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", # 这里补上逗号! "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", # ... 其他UA保持不变 ]
同时在settings.py里禁用默认的UA中间件,避免冲突:
DOWNLOADER_MIDDLEWARES = { 'example.middlewares.DianpingScrapeDownloaderMiddleware': 543, 'example.middlewares.RotateUserAgentMiddleware': 400, # 调整优先级,比默认UA中间件高 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, # 禁用默认UA中间件 }
2. 替换/优化代理方案
- 放弃免费代理:直接改用付费代理池(比如国内的阿布云、国外的BrightData),付费代理的可用性和匿名性都远高于免费代理,能大幅降低超时和被拉黑的概率。
- 自建代理验证机制:如果坚持用免费代理,一定要加代理有效性验证——在使用前先测试代理是否能正常访问目标网站,无效的直接丢弃。比如在获取代理后加个检测函数:
def test_proxy(self, proxy): try: response = requests.get('https://www.example.com', proxies={'https': proxy}, timeout=5) return response.status_code == 200 and 'verify.example.com' not in response.url except: return False def get_proxies(self, empty): # ... 原获取代理代码 valid_proxies = [p for p in list_ip if self.test_proxy(p)] return valid_proxies
3. 模拟更真实的请求行为
- 启用Cookie管理:目标网站可能通过Cookie识别合法会话,在
settings.py里开启Cookie:COOKIES_ENABLED = True - 补全请求头:除了UA,添加真人浏览器常用的请求头,让请求更逼真:
DEFAULT_REQUEST_HEADERS = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Referer': 'https://www.example.com/', 'Upgrade-Insecure-Requests': '1' } - 放缓爬取节奏:把
DOWNLOAD_DELAY调到3-5秒,同时启用AutoThrottle让Scrapy自动适配网站响应速度:DOWNLOAD_DELAY = 4 AUTOTHROTTLE_ENABLED = True AUTOTHROTTLE_START_DELAY = 2 AUTOTHROTTLE_MAX_DELAY = 10
4. 处理人机验证重定向
在下载中间件里检测响应URL,如果被重定向到验证页面,就丢弃当前代理并重新发起请求:
class AntiRedirectMiddleware: def process_response(self, request, response, spider): # 检测是否被重定向到验证页面 if 'verify.example.com' in response.url: # 标记当前代理失效,重新请求(换代理或用本机IP) request.meta.pop('proxy', None) return request.replace(dont_filter=True) # 绕过去重 return response
然后在settings.py里注册这个中间件:
DOWNLOADER_MIDDLEWARES = { # ... 其他中间件 'example.middlewares.AntiRedirectMiddleware': 600, }
5. 启用重试机制
针对TCP超时、连接丢失的错误,让Scrapy自动重试失败的请求:
# settings.py RETRY_TIMES = 3 RETRY_HTTP_CODES = [500, 502, 503, 504, 408, 429, 110]
最后,如果以上方法都不行
如果目标网站用了JS渲染的人机验证(比如滑块、验证码),普通的Scrapy请求很难绕过,这时可以考虑用Scrapy-Splash或Playwright中间件,模拟真实浏览器的渲染行为,直接绕过这类验证。
内容的提问来源于stack exchange,提问作者Stefani Johnsson
相关产品推荐
相关产品推荐

