使用python requests采集商品数据时,总是跳出验证码怎么办?

阿里云服务器

在使用 Python requests 采集商品数据时遇到验证码(CAPTCHA),本质上是因为你的请求特征被目标网站识别为“非人类行为”requests 是一个纯粹的 HTTP 库,它不会执行 JavaScript,也不会像浏览器那样自动处理 Cookie、指纹或渲染页面,因此非常容易被反爬机制(如 Cloudflare, Akamai, PerimeterX 等)拦截。

以下是从低成本规避高成本对抗的分级解决方案:

第一阶段:基础伪装(解决简单拦截)

如果网站只是进行简单的 User-Agent 检查或频率限制,这些方法通常有效。

1. 完善请求头 (Headers)

不要只改 User-Agent,要构造一个完整的浏览器指纹头。

import requests
import random

# 真实的浏览器 Headers 模板
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
    'Accept-Encoding': 'gzip, deflate, br',
    'Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1',
    'Sec-Ch-Ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    'Sec-Ch-Ua-Mobile': '?0',
    'Sec-Ch-Ua-Platform': '"Windows"',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'none',
    'Sec-Fetch-User': '?1'
}

session = requests.Session()
session.headers.update(headers)

# 关键:先访问首页获取 Cookie,再访问商品页
session.get('https://target-website.com') 
response = session.get('https://target-website.com/product/123')

2. 控制请求频率与随机延迟

绝对不要以固定间隔(如每 1 秒一次)发送请求。

import time
import random

urls = [...] # 商品列表

for url in urls:
    try:
        response = session.get(url)
        if response.status_code == 200:
            print(f"成功: {url}")
        else:
            print(f"失败状态码: {response.status_code}")
            
        # 随机延迟 2-5 秒,模拟人类阅读时间
        time.sleep(random.uniform(2, 5))
    except Exception as e:
        print(f"错误: {e}")
        time.sleep(10) # 出错后延长等待

3. 使用高质量代理 IP (Proxy)

如果单 IP 请求过多,会被直接封禁。必须使用代理池。

  • 住宅代理 (Residential Proxy):最推荐。IP 来自真实家庭宽带,极难被识别为爬虫。

  • 移动代理 (Mobile Proxy):来自 4G/5G 网络,信誉度最高,但价格昂贵。

  • 避免使用免费代理:免费代理几乎 100% 会被标记,导致秒出验证码。

proxies = {
    'http': 'http://user:pass@ip_address:port',
    'https': 'http://user:pass@ip_address:port',
}
response = session.get(url, proxies=proxies)

第二阶段:进阶对抗(解决中级防护)

如果基础伪装无效,说明网站使用了更高级的指纹识别(TLS 指纹、JA3 指纹等)。

1. 替换 requestscurl_cffitls_client

标准的 requests 库使用的 TLS 握手特征非常独特,很容易被识别。使用基于 cffigo 重写的库可以模拟真实浏览器的 TLS 指纹。

推荐方案:curl_cffi (目前 Python 界最强替代者)

pip install curl_cffi
from curl_cffi import requests as c_requests

# 模拟 Chrome 120 的 TLS 指纹
response = c_requests.get(
    "https://target-website.com/product/123",
    impersonate="chrome120" 
)
print(response.text)

效果:能绕过大部分基于 TLS 指纹的检测(如 Cloudflare 的低级防御)。

2. 处理动态 Cookie 和 Token

很多电商网站在加载页面前会执行一段 JS 生成加密 Token(如 _gcl_au, __cf_bm 等)。requests 无法执行 JS。

  • 方案:先用 SeleniumPlaywright 无头运行一次,获取生成的 Cookie,然后提取出来赋值给 requestscurl_cffi 的 Session。

  • 注意:Cookie 有有效期,需定期更新。


第三阶段:终极方案(解决强验证码/Cloudflare 5s盾)

如果出现了 Google reCAPTCHA v2/v3, hCaptcha, 或 Cloudflare 的 "Checking your browser" 循环,requests 方案基本宣告失效。此时必须引入浏览器自动化或第三方解码服务。

方案 A:接入打码平台 (最快解决)

如果你必须用 requests 流程,可以将遇到的验证码图片发送给第三方打码平台,获取答案后再提交。

  • 服务商:2Captcha, Capsolver, YesCaptchas 等。

  • 流程

    1. 检测到返回内容包含验证码图片/链接。

    2. 调用打码平台 API 上传图片。

    3. 等待平台返回文本答案(如 "A7B9" 或 Token)。

    4. 将答案填入表单或作为参数再次请求。

  • 缺点:需要付费,且有延迟;对于复杂的滑块或点选验证码,成功率不稳定。

方案 B:切换至浏览器自动化 (Playwright/Selenium) —— 强烈推荐

既然 requests 搞不定,就直接上浏览器。现在的 Playwright 已经非常高效,且配合 stealth 插件可以极大降低被检测率。

pip install playwright
playwright install
pip install playwright-stealth
from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync

def fetch_with_playwright(url):
    with sync_playwright() as p:
        # 启动浏览器 (headless=True 隐藏界面,但容易被测,建议 headless="new")
        browser = p.chromium.launch(headless="new")
        context = browser.new_context(
            user_agent="Mozilla/5.0 ...", # 同上
            viewport={"width": 1920, "height": 1080}
        )
        page = context.new_page()
        
        # 注入 Stealth 脚本,隐藏自动化特征
        stealth_sync(page)
        
        page.goto(url, wait_until="networkidle")
        
        # 如果在这里出现验证码,Playwright 可以配合人工介入或自动识别插件
        # 例如:page.screenshot(path="cap.png") -> 送去打码
        
        content = page.content()
        browser.close()
        return content

html = fetch_with_playwright("https://target-website.com/product/123")

方案 C:使用专门的爬虫 API 服务 (最省心)

如果不想维护复杂的反爬代码,直接使用封装好的 API。你只需发送 URL,他们返回 HTML。

  • 服务商:ScraperAPI, ZenRows, Bright Data (Web Unlocker), Oxylabs。

  • 原理:他们在后端拥有庞大的代理池和最新的浏览器指纹库,自动处理验证码和 JS 渲染。

  • 代码示例

import requests

url = "https://target-website.com/product/123"
payload = {'api_key': 'YOUR_API_KEY', 'url': url, 'render': True} # render=True 开启JS渲染
response = requests.get('https://api.scraperapi.com', params=payload)
print(response.text)

总结与建议策略

场景推荐方案成本难度
简单网站/低频采集requests + 完整 Headers + 随机延迟
中等防护 (TLS 指纹)curl_cffi (impersonate) + 住宅代理中 (代理费)
强防护 (Cloudflare/验证码)Playwright + Stealth爬虫 API 服务高 (时间/金钱)
大规模商业采集自建 Playwright 集群 或 购买企业级 API很高很高

核心建议

  1. 先尝试 curl_cffi:它保留了 requests 的简洁语法,但能解决 80% 的指纹问题。

  2. 不要死磕 requests:如果网站强制弹出滑块或点选验证码,立刻切换到 Playwright。试图用 requests 去破解现代验证码是得不偿失的。

  3. IP 是关键:无论用什么库,如果没有高质量的住宅代理 IP,任何技术手段都很难长期稳定运行。

  4. 合规性:请确保你的采集行为符合目标网站的 robots.txt 协议及当地法律法规,不要对服务器造成过载。