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

如何避免Scrapy请求URL被重定向?爬取遇验证及连接问题求助

解决Scrapy爬取被重定向人机验证+代理/UA失效问题

看来你在Scrapy爬取时遇到了挺棘手的反爬困境啊——一会儿能正常跑一会儿直接失效,还被强制重定向到人机验证页面,折腾了免费代理和UA轮换也没搞定,还一堆TCP超时、连接丢失的错误,太闹心了!我来帮你拆解下问题,给你几个实用的解决方案:


先分析核心问题

  1. 免费代理质量太差:free-proxy-list.net上的免费代理大多是公开共享的,要么已经失效、速度慢,要么早就被目标网站拉黑了,用它们大概率会出现超时、连接丢失,甚至直接触发更严格的反爬。
  2. UA轮换有bug:你的RotateUserAgentMiddleware里第一个UA字符串末尾少了个逗号!这会导致第一个和第二个UA直接拼接成无效字符串,等于UA轮换根本没正常工作。
  3. 请求特征太机械:除了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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 13:52:50