共计 2763 个字符,预计需要花费 7 分钟才能阅读完成。
典型错误现象
最近在尝试用 ChatGPT 的 API 抓取某电商网站数据时,连续收到 403 Forbidden 响应。通过 Chrome 开发者工具抓包发现,实际请求根本没有到达目标服务器——在 TCP 握手阶段就被阻断了。这不是个案,类似现象还出现在:

- 直接返回
503 Service Unavailable并附带验证页面 - 请求头包含
cf-mitigated: challenge的 Cloudflare 拦截 - 响应体中包含
distil_r_captcha等反爬标识
技术原理解析
自动化工具检测机制
- User-Agent 验证:
- 网站会维护已知自动化工具的 UA 黑名单(如包含
Python-urllib、HeadlessChrome等) -
最新检测趋势是验证 UA 与浏览器版本、操作系统是否匹配(RFC 7231#section-5.5.3)
-
行为指纹检测:
- 鼠标移动轨迹是否符合贝塞尔曲线(Human-like 运动有随机抖动)
- 请求间隔时间是否呈泊松分布(机械请求常为固定间隔)
-
页面停留时间是否短于人类阅读速度
-
TLS 指纹识别:
- 不同 HTTP 库的 TLS 握手特征不同(如 cURL 的
CHLO报文顺序) - 可通过 JA3 算法生成指纹(参考 Cloudflare 博客《Fingerprinting with JA3》)
Cloudflare 防护逻辑
- 五层拦截体系:
- IP 信誉库(Project Honeypot 数据)
- 浏览器完整性检查(通过 JS 生成加密 Token)
- 流量异常检测(突发高频请求触发质询)
- WAF 规则匹配(SQLi/XSS 等特征)
-
人机验证(CAPTCHA 或 hCaptcha)
-
质询流程:
- 首次访问返回
202 Accepted+cf_clearanceCookie - 需要执行 JS 计算验证参数(约耗时 3 - 5 秒)
- 通过后 cookie 有效期通常为 30 分钟
实战解决方案
Python 请求伪装
import requests
from fake_useragent import UserAgent
# 伪造桌面浏览器环境
headers = {'User-Agent': UserAgent().chrome,
'Accept-Language': 'en-US,en;q=0.9',
'Sec-Ch-Ua': '"Chromium";v="92", "Not A;Brand";v="99"',
'Cache-Control': 'no-cache'
}
# 处理 Cloudflare Cookie
cookies = {
'__cf_bm': '生成的 Base64 值', # 需要动态更新
'cf_clearance': '通过 JS 验证后获取'
}
response = requests.get(
'https://target.com/api/data',
headers=headers,
cookies=cookies,
timeout=10
)
Nginx 反向代理配置
server {
listen 443 ssl;
server_name yourproxy.domain;
location / {
proxy_pass https://target.com;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For random.ip.here; # 伪造源 IP
proxy_set_header Accept-Language "en-US";
proxy_ssl_server_name on;
proxy_ssl_protocols TLSv1.2 TLSv1.3;
}
}
Puppeteer 行为模拟
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
(async () => {
const browser = await puppeteer.launch({
headless: false,
args: ['--disable-web-security']
});
const page = await browser.newPage();
await page.setViewport({width: 1366, height: 768});
// 模拟人类鼠标移动
await page.mouse.move(100, 100, { steps: 20});
await page.mouse.move(200, 300, { steps: 5});
await page.goto('https://target.com', {
waitUntil: 'networkidle2',
timeout: 30000
});
// 随机延迟点击
await page.waitForTimeout(2000 + Math.random() * 3000);
await page.click('#loginBtn');
})();
生产环境注意事项
请求频率控制
from threading import Semaphore
import time
class RequestLimiter:
def __init__(self, rate=5, per=60):
self.semaphore = Semaphore(rate)
self.rate = rate
self.per = per
def acquire(self):
with self.semaphore:
time.sleep(self.per / self.rate)
# 使用示例
limiter = RequestLimiter(rate=10, per=300)
for url in urls:
limiter.acquire()
make_request(url)
IP 轮换策略
- 住宅代理池维护:
- 使用 Luminati/StormProxies 等服务
- 每个请求随机选择出口 IP
-
失败 IP 自动加入冷却名单(至少 30 分钟)
-
AWS Lambda 热切换:
- 每个函数实例使用不同 NAT 网关
- 通过 VPC Endpoint 隐藏真实 IP
- 配合 API Gateway 做请求分发
扩展思考
机器学习在流量识别中的应用
- 基于 LSTM 的流量时序分析(检测请求间隔模式)
- 浏览器指纹聚类(通过 WebGL 渲染等 300+ 特征)
- 强化学习的动态规则生成(参考 Akamai 的 AI WAF)
平衡之道
- 合规性建议:
- 遵守 robots.txt 中 Crawl-delay 指令
- 为显著降低 QPS(建议 <1req/s)
-
设置清晰的 User-Agent 标识
-
技术伦理边界:
- 避免绕过付费 API 的认证
- 不抓取明确禁止的个人数据
- 考虑使用官方提供的开发者接口
最后提醒:所有技术方案都应建立在合法合规的前提下,本文仅作技术研究交流使用。遇到复杂反爬系统时,优先考虑与目标网站协商正规数据接入方式。
正文完
发表至: 技术分享
近两天内
