代理IP换了、浏览器指纹也混淆了,但网站还是能识别出你在用Python requests或curl——因为你忽略了TLS指纹。JA3指纹是SSL/TLS握手时暴露的客户端特征,Python、curl、浏览器各自的JA3指纹都不一样,把这当突破口就能识别爬虫。
JA3指纹是什么
当你访问一个HTTPS网站时,浏览器和服务器之间先做TLS握手——协商加密算法、交换密钥。握手过程中客户端发出去的”Client Hello”包包含了:支持的TLS版本、加密套件列表(按优先级排列)、椭圆曲线列表、扩展字段。这些信息的组合通过MD5哈希形成一个唯一指纹——这就是JA3。
同一个浏览器版本在不同电脑上的JA3指纹是一样的。Python的requests库用的是urllib3+OpenSSL的默认配置,JA3指纹也是固定的——”Python/urllib3″的指纹。这就是为什么即使你换了代理IP、改了User-Agent,风控系统还是能识别出你在用Python发请求。
怎么查自己的JA3指纹
用Wireshark抓包能看到Client Hello的详细内容,但手动分析太麻烦了。用在线工具ja3er.com——浏览器访问它会显示你当前浏览器的JA3指纹。Python的话抓取HTTPS请求看看是否被识别。
或者用tlsfingerprint.io查不同客户端的JA3指纹数据库——Chrome 126的指纹、Firefox 127的指纹、Python requests的指纹各是什么。
对抗JA3指纹检测
Python层面:用tls_client库代替requests,它模拟的是真实浏览器的TLS握手行为。
# pip install tls_client
import tls_client
session = tls_client.Session(
client_identifier="chrome_126", # 模拟Chrome126的TLS指纹
random_tls_extension_order=True # 随机化扩展顺序
)
resp = session.get('https://目标网站', proxy='http://代理IP:端口')curl_impersonate:这是curl的增强版,能模拟Chrome/Firefox/Safari的TLS指纹。比Python的tls_client更底层,适合命令行脚本。
天行IP的代理节点(邀请码 blsj,月付6元起)配合tls_client模拟真实浏览器指纹,比单纯requests+代理通过率高很多。
Go/Node.js等其他语言的方案
Go语言:用utls库(uTLS)代替标准crypto/tls——它能把Go的TLS握手伪装成Chrome/Firefox的行为。
Node.js:用got-scraping——got库的爬虫专用分支,内置了TLS伪装。
不管什么语言,核心思路是一样的——替换默认的TLS库,用能模拟真实浏览器TLS指纹的库。curl_impersonate是目前最接近完美的方案(因为它是从curl源码级修改的)。
JA3只是TLS指纹的开始
JA3检测的是Client Hello的特征,2026年更先进的风控系统已经在用:JA4(JA3的升级版,更精确)、HTTP/2指纹(HTTP/2连接的设置帧特征)、TLS 1.3 extensions fingerprint。对抗是持续的——风控系统升级检测方法、工具库跟进适配。追求绝对完美的方案不存在,能做的就是让检测成本高于你的采集价值。
常见问题
用了tls_client还是被识别?
JA3只是TLS层面的指纹。网站还在看——IP类型(机房还是住宅)、请求频率模式、HTTP头组合、JavaScript执行结果。TLS伪装加上前面说的浏览器指纹对抗(第31篇ID 13573)和HTTP头伪装(第41篇ID 13592),三个层面一起做才能显著降低识别率。
curl_impersonate和tls_client哪个更好?
curl_impersonate更接近真实浏览器行为(它直接修补了curl的TLS实现),通过率最高。tls_client是Python库,方便集成到Python代码里,通过率也很不错。如果追求极致效果而且能接受用命令行调用,curl_impersonate更强。
需不需要频繁更新TLS指纹配置?
需要。浏览器每6周发一个新版本,Chrome 126和127的JA3指纹不同。保持tls_client/curl_impersonate更新到最新版本以匹配最新的浏览器TLS指纹。过时的指纹同样会被标记为异常——”这个Chrome版本几个月前就退役了为什么还在用”。






