Python requests请求返回403 开启Charles代理可正常访问是什么原因
问题核心原因
1. TLS指纹校验触发拦截
当前主流反爬系统普遍会校验客户端TLS握手阶段生成的JA3指纹:
- requests依赖的urllib3库默认TLS配置的加密套件、扩展参数特征辨识度极高,会被直接标记为爬虫,返回403
- Charles内置的TLS栈指纹与主流浏览器高度相似,大部分站点不会对其做拦截,因此走Charles代理时请求可正常通过
- Fiddler默认TLS配置的指纹同样属于爬虫高频特征,因此走Fiddler代理仍会被拦截
2. HTTP协议版本差异
requests默认仅支持HTTP/1.1协议,现在多数站点已强制要求HTTP/2访问:
- Charles转发请求时默认会自动与目标站点协商使用HTTP/2协议,符合站点访问要求
- Fiddler默认使用HTTP/1.1转发请求,不符合站点要求触发403
3. 隐性请求参数补全差异
Charles转发请求时会自动补全浏览器默认携带的隐性请求头、Cookie等参数,而Fiddler默认不会做这类补全,requests手动配置的请求头通常也会缺失这类隐性参数,导致被拦截。
可落地解决方案
- 直接替换requests为支持自定义TLS指纹的HTTP库,例如
tls-client、httpx[http2],可直接模拟Chrome的JA3指纹和HTTP/2协议,绕过指纹校验 - 抓取Charles转发的完整请求报文,与requests直接发送的报文做对比,补全缺失的请求头、Cookie、查询参数等信息
- 若需要继续使用requests,可自定义urllib3的SSL上下文,调整加密套件顺序、TLS扩展配置,模拟浏览器的TLS指纹特征
示例代码(基于tls-client模拟Chrome请求)
import tls_client def get_test(): session = tls_client.Session( client_identifier="chrome_114", random_tls_extension_order=True ) url = "你的目标URL" my_header={ 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,ja;q=0.6,zh-HK;q=0.5', 'cache-control': 'max-age=0', 'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-dest': 'document', 'sec-fetch-mode': 'navigate', 'sec-fetch-site': 'none', 'sec-fetch-user': '?1', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', } rsp = session.get(url=url, headers=my_header) print(rsp.status_code) if __name__ == '__main__': get_test()
内容的提问来源于stack exchange,提问作者blues
相关产品推荐
相关产品推荐

