在使用 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. 替换 requests 为 curl_cffi 或 tls_client
标准的 requests 库使用的 TLS 握手特征非常独特,很容易被识别。使用基于 cffi 或 go 重写的库可以模拟真实浏览器的 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。
方案:先用
Selenium或Playwright无头运行一次,获取生成的 Cookie,然后提取出来赋值给requests或curl_cffi的 Session。注意:Cookie 有有效期,需定期更新。
第三阶段:终极方案(解决强验证码/Cloudflare 5s盾)
如果出现了 Google reCAPTCHA v2/v3, hCaptcha, 或 Cloudflare 的 "Checking your browser" 循环,纯 requests 方案基本宣告失效。此时必须引入浏览器自动化或第三方解码服务。
方案 A:接入打码平台 (最快解决)
如果你必须用 requests 流程,可以将遇到的验证码图片发送给第三方打码平台,获取答案后再提交。
服务商:2Captcha, Capsolver, YesCaptchas 等。
流程:
检测到返回内容包含验证码图片/链接。
调用打码平台 API 上传图片。
等待平台返回文本答案(如 "A7B9" 或 Token)。
将答案填入表单或作为参数再次请求。
缺点:需要付费,且有延迟;对于复杂的滑块或点选验证码,成功率不稳定。
方案 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 | 很高 | 很高 |
核心建议:
先尝试
curl_cffi:它保留了requests的简洁语法,但能解决 80% 的指纹问题。不要死磕
requests:如果网站强制弹出滑块或点选验证码,立刻切换到Playwright。试图用requests去破解现代验证码是得不偿失的。IP 是关键:无论用什么库,如果没有高质量的住宅代理 IP,任何技术手段都很难长期稳定运行。
合规性:请确保你的采集行为符合目标网站的
robots.txt协议及当地法律法规,不要对服务器造成过载。