爬虫请求头伪装全攻略:从User-Agent到TLS指纹的完整伪装链
发布时间: 2026-05-15 10:00:12
阅读量: 18 人次
你以为改了UA就安全了?真正的伪装要从第一行请求头开始
很多爬虫初学者认为,只要把User-Agent改成Chrome的,就能绕过反爬。然而在2026年,反爬系统会检查请求头的每一个字段——包括字段的顺序、大小写、字段之间的逻辑一致性。一个不完整的请求头集合,或者不同浏览器特征的混用,都会在几百毫秒内被识别为机器人。本文系统讲解如何构造一个“以假乱真”的浏览器请求头,以及容易被忽视的细节陷阱。
一、为什么请求头是反爬的第一道防线?
当你的请求到达目标服务器时,最先被解析的就是HTTP请求头。反爬系统会根据请求头中的数十个字段判断请求是否来自真实浏览器。常用的检测维度包括:
• 字段是否存在(浏览器会发送十几个头,爬虫往往只发三四个)
• 字段的顺序(不同浏览器的头顺序有固定模式)
• 字段的大小写(Chrome用小写,某些库用首字母大写)
• 字段值的合理性(如Accept-Language与IP地理位置是否匹配)
• 字段之间的逻辑一致性(如UA声明Windows但Sec-CH-UA-Platform提示macOS)
任何一项异常都会降低信任评分,累积到阈值后触发验证码或直接拒绝。因此,请求头伪装不能只改一个UA,而是要构造完整的、自洽的请求头集合。
• 字段是否存在(浏览器会发送十几个头,爬虫往往只发三四个)
• 字段的顺序(不同浏览器的头顺序有固定模式)
• 字段的大小写(Chrome用小写,某些库用首字母大写)
• 字段值的合理性(如Accept-Language与IP地理位置是否匹配)
• 字段之间的逻辑一致性(如UA声明Windows但Sec-CH-UA-Platform提示macOS)
任何一项异常都会降低信任评分,累积到阈值后触发验证码或直接拒绝。因此,请求头伪装不能只改一个UA,而是要构造完整的、自洽的请求头集合。
二、Chrome浏览器发送的完整请求头示例(2026)
一个真实的Chrome 124请求包含以下典型头部(按实际顺序列出):
GET / HTTP/1.1
Host: www.example.com
Connection: keep-alive
sec-ch-ua: "Chrome";v="124", "Chromium";v="124"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
注意:字段的排列顺序、大小写、以及Sec-*系列头的存在是Chrome的典型特征。很多爬虫缺少`Sec-Fetch-*`和`sec-ch-ua`头,直接暴露了自己。
GET / HTTP/1.1
Host: www.example.com
Connection: keep-alive
sec-ch-ua: "Chrome";v="124", "Chromium";v="124"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
注意:字段的排列顺序、大小写、以及Sec-*系列头的存在是Chrome的典型特征。很多爬虫缺少`Sec-Fetch-*`和`sec-ch-ua`头,直接暴露了自己。
三、请求头伪装的七大核心维度
1. User-Agent:不仅要有,还要配合其他头
维护一个UA池(至少10-20个最新版本的Chrome、Edge、Firefox UA)。但仅轮换UA不够,必须确保`sec-ch-ua`和`sec-ch-ua-platform`与UA中的操作系统、浏览器版本完全一致。例如UA声明Windows,`sec-ch-ua-platform`必须是"Windows"。
2. Accept系列:浏览器与爬虫差异最大的地方
真实浏览器的Accept头包含多种媒体类型及权重(q值),而爬虫往往是`*/*`。建议从真实浏览器复制完整的Accept值。`Accept-Encoding`应包含`gzip, deflate, br`(Brotli压缩)。`Accept-Language`应与IP地理位置相匹配,美国IP使用`en-US`,中国IP使用`zh-CN`。
3. Sec-*系列头:现代浏览器的身份证(2026年必检)
Sec-Fetch-*和Sec-CH-UA-*是Chrome和Edge的强制头字段,缺失等于告诉网站“我是脚本”。必须完整添加:`Sec-Fetch-Site`, `Sec-Fetch-Mode`, `Sec-Fetch-Dest`, `Sec-Fetch-User`(仅导航请求)。对于XHR请求,`Sec-Fetch-Mode`应为`cors`或`no-cors`。
4. Referer:链路的完整性
真实访问行为有完整的Referer链路。直接访问首页时Referer为空;点击链接跳转后Referer为前一页。爬虫如果直接请求内页而Referer缺失或错误,会被判定为直接请求。建议:第一级请求不设Referer,后续请求设为上一页URL。
5. Cookie和Session:连续性的证明
首次访问时服务器会下发Cookie,后续请求必须携带。很多爬虫忽略Cookie,导致每次请求都被当作新会话。使用requests.Session或手动管理Cookie容器可以解决。
6. 请求头顺序:容易被忽略的细节
某些风控系统会检查头字段的顺序。Python的requests库默认按字典顺序发送,可能改变原始顺序。解决方法:使用`OrderedDict`或切换到能保持顺序的HTTP客户端(如httpx)。curl_cffi默认按添加顺序发送,更易控制。
7. 大小写一致性
浏览器通常发送小写头字段名(`user-agent`)或首字母大写(`User-Agent`)。不同浏览器有微妙差异。建议使用浏览器原始格式,避免统一转为小写或大写。
维护一个UA池(至少10-20个最新版本的Chrome、Edge、Firefox UA)。但仅轮换UA不够,必须确保`sec-ch-ua`和`sec-ch-ua-platform`与UA中的操作系统、浏览器版本完全一致。例如UA声明Windows,`sec-ch-ua-platform`必须是"Windows"。
2. Accept系列:浏览器与爬虫差异最大的地方
真实浏览器的Accept头包含多种媒体类型及权重(q值),而爬虫往往是`*/*`。建议从真实浏览器复制完整的Accept值。`Accept-Encoding`应包含`gzip, deflate, br`(Brotli压缩)。`Accept-Language`应与IP地理位置相匹配,美国IP使用`en-US`,中国IP使用`zh-CN`。
3. Sec-*系列头:现代浏览器的身份证(2026年必检)
Sec-Fetch-*和Sec-CH-UA-*是Chrome和Edge的强制头字段,缺失等于告诉网站“我是脚本”。必须完整添加:`Sec-Fetch-Site`, `Sec-Fetch-Mode`, `Sec-Fetch-Dest`, `Sec-Fetch-User`(仅导航请求)。对于XHR请求,`Sec-Fetch-Mode`应为`cors`或`no-cors`。
4. Referer:链路的完整性
真实访问行为有完整的Referer链路。直接访问首页时Referer为空;点击链接跳转后Referer为前一页。爬虫如果直接请求内页而Referer缺失或错误,会被判定为直接请求。建议:第一级请求不设Referer,后续请求设为上一页URL。
5. Cookie和Session:连续性的证明
首次访问时服务器会下发Cookie,后续请求必须携带。很多爬虫忽略Cookie,导致每次请求都被当作新会话。使用requests.Session或手动管理Cookie容器可以解决。
6. 请求头顺序:容易被忽略的细节
某些风控系统会检查头字段的顺序。Python的requests库默认按字典顺序发送,可能改变原始顺序。解决方法:使用`OrderedDict`或切换到能保持顺序的HTTP客户端(如httpx)。curl_cffi默认按添加顺序发送,更易控制。
7. 大小写一致性
浏览器通常发送小写头字段名(`user-agent`)或首字母大写(`User-Agent`)。不同浏览器有微妙差异。建议使用浏览器原始格式,避免统一转为小写或大写。
四、不同请求类型的头差异:页面、API、资源
爬虫常需要区分不同资源类型的请求头:
• HTML页面请求:使用上述完整头,`Accept`为`text/html`优先,`Sec-Fetch-Dest`为`document`。
• AJAX/API请求:`Accept`通常为`application/json`,`Sec-Fetch-Mode`为`cors`,`X-Requested-With`可选(但已逐渐淘汰)。有时需要携带特定的API密钥或token。
• 静态资源(图片/CSS/JS):`Accept`为对应的MIME类型,`Referer`为页面URL,`Sec-Fetch-Dest`为`image`或`script`。
• HTML页面请求:使用上述完整头,`Accept`为`text/html`优先,`Sec-Fetch-Dest`为`document`。
• AJAX/API请求:`Accept`通常为`application/json`,`Sec-Fetch-Mode`为`cors`,`X-Requested-With`可选(但已逐渐淘汰)。有时需要携带特定的API密钥或token。
• 静态资源(图片/CSS/JS):`Accept`为对应的MIME类型,`Referer`为页面URL,`Sec-Fetch-Dest`为`image`或`script`。
五、实战:使用curl_cffi构造完美请求头
curl_cffi不仅模拟TLS指纹,还支持自定义请求头并保持顺序。示例代码:
from curl_cffi import requests
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Sec-Ch-Ua": '"Chrome";v="124", "Chromium";v="124"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Windows"',
"Sec-Fetch-Site": "none",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Upgrade-Insecure-Requests": "1",
"Connection": "keep-alive",
}
response = requests.get("https://example.com", headers=headers, impersonate="chrome124")
`impersonate="chrome124"`参数会同时设置TLS指纹和自动补充缺失的Sec-*头(如果headers中未提供)。这是目前最简便的完美伪装方案。
from curl_cffi import requests
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Sec-Ch-Ua": '"Chrome";v="124", "Chromium";v="124"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Windows"',
"Sec-Fetch-Site": "none",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Upgrade-Insecure-Requests": "1",
"Connection": "keep-alive",
}
response = requests.get("https://example.com", headers=headers, impersonate="chrome124")
`impersonate="chrome124"`参数会同时设置TLS指纹和自动补充缺失的Sec-*头(如果headers中未提供)。这是目前最简便的完美伪装方案。
六、常见错误与调试技巧
错误1:头字段值包含不规范的空白或换行
导致请求被服务器拒绝。使用`strip()`清理。
错误2:混合不同浏览器的特征
UA是Chrome,但Accept-Language是日文,而IP在德国,造成逻辑不一致。解决方法:为每个代理IP绑定一组一致的地理相关头。
错误3:固定不变的请求头
长时间使用完全相同的一组请求头,会被机器学习模型识别为固定模式。应定期(如每次会话或每100次请求)轮换UA和Accept-Language。
调试技巧
使用中间人代理(如mitmproxy)拦截真实浏览器的请求,对照你的爬虫请求头,逐一比对差异。特别关注缺失的字段和字段值的细微不同。
导致请求被服务器拒绝。使用`strip()`清理。
错误2:混合不同浏览器的特征
UA是Chrome,但Accept-Language是日文,而IP在德国,造成逻辑不一致。解决方法:为每个代理IP绑定一组一致的地理相关头。
错误3:固定不变的请求头
长时间使用完全相同的一组请求头,会被机器学习模型识别为固定模式。应定期(如每次会话或每100次请求)轮换UA和Accept-Language。
调试技巧
使用中间人代理(如mitmproxy)拦截真实浏览器的请求,对照你的爬虫请求头,逐一比对差异。特别关注缺失的字段和字段值的细微不同。
七、2026年请求头检测的新趋势
反爬系统正在将请求头检测与行为分析、TLS指纹深度绑定。单一的请求头完美伪装已不足以保证完全通过,但它是基础防线。新趋势包括:
• 检测`Accept-Encoding`中的`br`是否真实支持(Brotli算法)
• 检测`Sec-CH-UA-*`与真实浏览器的版本号是否在合理范围内
• 跨请求头字段的一致性校验(例如不同请求中的相同头字段值应保持稳定)
建议爬虫开发者至少每季度更新一次头字段模板,参考最新版Chrome/Firefox的实发请求。
• 检测`Accept-Encoding`中的`br`是否真实支持(Brotli算法)
• 检测`Sec-CH-UA-*`与真实浏览器的版本号是否在合理范围内
• 跨请求头字段的一致性校验(例如不同请求中的相同头字段值应保持稳定)
建议爬虫开发者至少每季度更新一次头字段模板,参考最新版Chrome/Firefox的实发请求。
总结
请求头伪装是爬虫对抗反爬的基础但极其重要的一环。从User-Agent到Sec-*系列头,从字段值到顺序和大小写,每一个细节都影响成功率。在2026年,单一UA轮换已彻底失效,必须构造完整、自洽、动态的请求头集合。结合TLS指纹模拟(如curl_cffi)和合理的限流策略,才能在高防护网站上保持稳定采集。


黑公网安备 23100002000084号