ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

User Agent 详解:从结构解析到实战 UA 池与轮换技巧

User Agent 详解:从结构解析到实战 UA 池与轮换技巧 1. 从一个不起眼的字符串说起为什么我们需要认识 User Agent如果你做过爬虫、写过接口自动化测试、或者只是单纯在浏览器里按过 F12 看过 Network 面板那你一定见过那一长串看起来像乱码的字符串——Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36。这就是User Agent简称 UA。它本质上就是客户端在发起 HTTP 请求时主动贴在脑门上的一张“自我介绍便签”告诉服务端“我是谁、我来自哪里、我大概能干什么”。很多人第一次接触 UA 是因为遇到了“同一个页面浏览器打开正常代码请求却返回一堆乱码或者直接 403”。这背后的核心原因往往就是服务端根据 UA 做了内容协商或者访问控制。UA 能做的事情远比想象中多它决定了服务端返回桌面版还是移动版页面、决定是否触发反爬策略、影响 CDN 缓存命中、甚至影响某些前端库的兼容性分支。可以说UA 是客户端与服务端之间最廉价、最普遍、也最容易被忽视的“身份凭证”。这篇文章适合三类人看第一类是刚入门爬虫和数据采集的朋友经常被 UA 卡住却不知道从哪下手第二类是做前端兼容和自动化测试的工程师需要模拟不同设备环境第三类是对 HTTP 协议细节感兴趣、想把“知其所以然”补齐的开发者。我会从 UA 的结构讲起把常见 UA 拆开揉碎再给出可直接复用的 UA 列表、构造方法和实战避坑经验。读完你至少能做到看到一串 UA 能立刻判断出浏览器内核、操作系统、设备类型并且知道在什么场景下该用哪一类 UA。2. User Agent 的结构拆解一串字符里到底藏了多少信息2.1 UA 的历史包袱与字段构成UA 字符串之所以看起来又长又乱是因为它背负了三十年的历史包袱。最早的浏览器叫 Mosaic后来 Netscape 的浏览器代号是 Mozilla为了兼容只认 Mozilla 的服务器后来的浏览器纷纷在 UA 开头加上Mozilla/5.0来“伪装”自己。这个传统一直延续到今天所以你会看到 Chrome、Edge、Safari 的 UA 全都以Mozilla/5.0开头这纯粹是历史遗留的兼容性妥协跟 Mozilla 本身已经没什么关系了。一个典型的现代 UA 大致由以下几段组成用空格和括号分隔Mozilla/5.0历史兼容前缀几乎所有主流浏览器都保留。(操作系统标识; 加密等级标识; 浏览器语言)括号内是平台信息比如Windows NT 10.0; Win64; x64表示 64 位 Windows 10。AppleWebKit/537.36渲染引擎标识WebKit 系内核的通用标记。(KHTML, like Gecko)又一处历史兼容标记表示“我像 Gecko 一样渲染”。Chrome/120.0.0.0真正的浏览器名称和版本号。Safari/537.36为了兼容 Safari 检测而保留的尾巴。理解这个结构之后你就能像读身份证一样读 UA 了。比如看到iPhone; CPU iPhone OS 17_0就知道是 iOS 17 的 iPhone看到Android 13; Pixel 7就知道是安卓 13 的某款设备。这种“逐段解析”的能力是后面所有实战操作的基础。2.2 主流浏览器 UA 的差异对比不同浏览器厂商在 UA 里塞的东西并不一样这直接影响了服务端的判断逻辑。我整理了一张对比表把几个主流桌面浏览器的 UA 关键字段列出来方便你快速对照浏览器内核标识典型版本字段特殊标记ChromeAppleWebKit/537.36Chrome/120.0.0.0无EdgeAppleWebKit/537.36Edg/120.0.0.0注意是Edg不是EdgeFirefoxGecko/20100101Firefox/121.0不含 AppleWebKitSafariAppleWebKit/605.1.15Version/17.0含 Safari/605.1.15这里有个非常容易踩的坑Edge 的 UA 里写的是Edg/而不是Edge/。早期 Edge 用的是Edge/后来为了和某些老检测逻辑区分改成了Edg/。如果你写正则去匹配 Edge用Edge会漏掉一大批新版本。同理Firefox 的 UA 里根本没有AppleWebKit如果你用“是否包含 AppleWebKit”来判断是不是现代浏览器Firefox 会被误判。这些细节在写兼容逻辑时都是实打实的坑。2.3 移动端 UA 的识别要点移动端 UA 比桌面端更复杂因为设备碎片化严重。但抓住几个关键词就能覆盖绝大多数情况iPhone包含iPhone系统字段形如CPU iPhone OS 17_0 like Mac OS X。iPad包含iPad注意 iPadOS 13 之后默认请求桌面版 UA需要额外处理。Android 手机包含Android和Mobile比如Android 13; Pixel 7 Build/...。Android 平板包含Android但通常不含Mobile这是区分手机和平板的关键。微信内置浏览器包含MicroMessenger这个标记在做微信生态适配时极其重要。提示判断移动端时不要只匹配Mobile一个词。有些安卓平板 UA 里也会出现Mobile稳妥做法是结合Android和屏幕尺寸信息综合判断。3. 常见 User Agent 实战清单可直接抄作业的 UA 库3.1 桌面端高频 UA 推荐在实际做数据采集时最省事的做法是维护一个 UA 池每次请求随机挑一个。下面这些是我实测下来比较稳定、不容易被识别为异常的桌面 UA你可以直接拿去用DESKTOP_UA_POOL [ # Chrome on Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, # Chrome on macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, # Firefox on Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0, # Safari on macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15, # Edge on Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0, ]选这些 UA 的逻辑是它们都是当前主流版本覆盖面广且版本号不会太旧。版本号太旧是常见失误——你用一个 Chrome 80 的 UA 去请求服务端一看就知道这是“老古董”很容易触发风控。所以 UA 池需要定期更新建议每季度检查一次主流版本号。3.2 移动端 UA 与设备模拟移动端采集或者做响应式测试时需要模拟具体设备。下面这组覆盖了 iOS、Android、微信等高频场景MOBILE_UA_POOL [ # iPhone Safari Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1, # Android Chrome Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36, # 微信内置浏览器 Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.44, # Android 平板 Mozilla/5.0 (Linux; Android 13; SM-X700) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, ]这里要特别说明微信 UA 的用法。微信内置浏览器的 UA 里带MicroMessenger很多做微信分享、H5 页面适配的逻辑都依赖这个标记。如果你要测试“在微信里打开是什么效果”就必须把 UA 换成带MicroMessenger的否则服务端会返回普通浏览器版本测出来的结果完全不对。3.3 特殊场景 UA搜索引擎与爬虫标识除了浏览器还有一类 UA 是搜索引擎爬虫和自动化工具的。这类 UA 的特点是“自报家门”比如GooglebotMozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)BingbotMozilla/5.0 (compatible; bingbot/2.0; http://www.bing.com/bingbot.htm)通用爬虫python-requests/2.31.0、curl/8.4.0、Go-http-client/1.1这里有个关键认知用python-requests这种默认 UA 去请求等于直接告诉服务端“我是脚本”。绝大多数有风控的站点会第一时间拦截。所以做采集时第一件事就是把默认 UA 换掉。反过来如果你自己写服务端想识别爬虫也可以从这些默认 UA 入手做基础过滤。4. 动手实操构造、解析与轮换 UA 的完整流程4.1 用 Python 构造和发送自定义 UA最基础的用法是在请求头里手动指定 UA。以requests库为例import requests 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-Language: zh-CN,zh;q0.9,en;q0.8, } resp requests.get(https://example.com, headersheaders, timeout10) print(resp.status_code)注意我同时加了Accept-Language。只改 UA 不改其他头是很容易被识破的。因为一个真实的 Chrome 请求除了 UA 还会带Accept、Accept-Language、Accept-Encoding、Connection等一系列头。如果你的请求只有 UA 像浏览器其他头都是 requests 默认值风控系统一眼就能看出破绽。所以正确的做法是“成套伪装”把常用请求头一起补上。4.2 用正则解析 UA 提取关键信息有时候我们需要反过来从一串 UA 里提取浏览器、系统、设备信息。用正则是最直接的方式import re def parse_ua(ua: str) - dict: result {browser: Unknown, os: Unknown, device: Desktop} # 浏览器识别注意顺序Edge 要在 Chrome 之前判断 if Edg/ in ua: result[browser] Edge elif Firefox/ in ua: result[browser] Firefox elif Chrome/ in ua: result[browser] Chrome elif Safari/ in ua: result[browser] Safari # 系统识别 if Windows NT in ua: result[os] Windows elif Mac OS X in ua: result[os] macOS elif Android in ua: result[os] Android elif iPhone in ua or iPad in ua: result[os] iOS # 设备类型 if Mobile in ua or iPhone in ua: result[device] Mobile elif iPad in ua or (Android in ua and Mobile not in ua): result[device] Tablet return result ua Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0 print(parse_ua(ua)) # {browser: Edge, os: Windows, device: Desktop}这段代码里最关键的是判断顺序。Edge 的 UA 里同时包含Chrome/和Edg/如果你先判断 ChromeEdge 就会被误判成 Chrome。同理很多国产浏览器 UA 里也带Chrome/需要根据额外标记区分。这个“先特殊后一般”的判断顺序是写 UA 解析逻辑的铁律。4.3 构建可轮换的 UA 中间件在规模化采集时单个 UA 反复请求同一个站点很容易被限流。这时候需要 UA 轮换。下面是一个简单的轮换中间件思路import random class UARotator: def __init__(self, ua_pool): self.ua_pool ua_pool self._last_ua None def get(self): # 避免连续两次拿到同一个 UA candidates [ua for ua in self.ua_pool if ua ! self._last_ua] ua random.choice(candidates) self._last_ua ua return ua rotator UARotator(DESKTOP_UA_POOL) for _ in range(3): print(rotator.get()[:60], ...)这个实现里我加了一个“避免连续重复”的小逻辑。原因是如果随机池里只有 5 个 UA纯随机很容易连续两次抽到同一个而连续相同 UA 的请求模式反而更可疑。这个细节在常规教程里很少提但实测下来对降低触发风控的概率有帮助。5. 常见问题与排查技巧实录5.1 UA 相关的典型报错与解决思路做采集和接口调试时跟 UA 相关的问题主要集中在下面几类。我整理成速查表遇到问题可以直接对照现象可能原因排查与解决返回 403 ForbiddenUA 被识别为脚本换成主流浏览器 UA补齐其他请求头返回内容为移动版UA 被判定为移动设备检查 UA 是否含 Mobile换成桌面 UA返回乱码或空内容服务端按 UA 返回了不同编码检查响应头 Content-Type确认 UA 与预期一致页面元素定位失败服务端返回了不同版本页面固定 UA确保每次请求环境一致登录态频繁失效UA 变化导致会话校验失败同一会话内保持 UA 不变这里重点说“登录态失效”这一条。很多站点的会话校验会把 UA 作为指纹的一部分如果你在同一个会话里换了 UA服务端会认为“换人了”直接踢掉登录态。所以UA 轮换只适合无状态请求涉及登录的会话必须固定 UA。这个坑我在早期做自动化时踩过排查了大半天才定位到是 UA 变了。5.2 那些文档里不会写的避坑经验第一个经验不要迷信“最新版本 UA 最好”。有些站点的风控规则是“只允许最近 N 个版本”你用一个刚发布没几天的版本号反而可能因为规则库还没更新而被拦。稳妥做法是用“当前主流版本往前推一到两个大版本”比如现在主流是 120你用 118 或 119 通常更安全。第二个经验UA 要和 IP、时区、语言保持一致。如果你用美国 IP却配一个zh-CN的语言头和中文系统 UA这种“地理矛盾”很容易被识别。做海外采集时UA 里的系统语言、请求头的Accept-Language、出口 IP 的地理位置三者最好能对上。第三个经验移动端 UA 不要随便混用。比如你用一个 iPhone 的 UA但请求头里Accept写的是桌面浏览器的值或者屏幕分辨率参数对不上也会露馅。真要做移动端模拟建议直接用成熟的设备模拟方案把 UA、视口、触摸事件等一整套都配齐而不是只改一个 UA 字符串。注意UA 只是客户端指纹的一部分。现代风控还会看 TLS 指纹、Canvas 指纹、鼠标轨迹等。UA 能解决大部分“低级拦截”但面对高级风控单靠 UA 是不够的。认清这一点能帮你少走很多弯路。5.3 服务端视角如何正确使用 UA 做判断如果你站在服务端想用 UA 做设备适配有几点建议。首先优先用响应式设计和特性检测而不是 UA 判断。UA 判断是出了名的脆弱浏览器版本一更新、UA 一改你的判断逻辑就可能失效。其次如果非要用 UA一定要做“优雅降级”——判断不出来时返回通用版本而不是直接报错。最后不要把 UA 当作安全边界。UA 是客户端可以随意伪造的任何基于 UA 的“权限控制”都是纸糊的真正的安全校验必须放在服务端会话和令牌层面。6. 关于 UA 的一些个人体会我做了这么多年采集和自动化UA 这个看似最简单的东西反而是最容易被低估的。新手往往觉得“随便填一个就行”结果卡在 403 上半天找不到原因老手则容易过度依赖 UA 池忽略了请求头一致性、会话固定这些更本质的问题。我的建议是把 UA 当成整个请求指纹体系的一环来对待而不是孤立的一个字段。维护一个定期更新的 UA 池配合一致的请求头、合理的请求频率基本能覆盖 80% 的常规场景。剩下那 20% 的硬骨头靠的是对目标站点行为的细致观察而不是堆砌更多的 UA。这个内容后续还可以往“客户端指纹体系”方向扩展把 TLS、Canvas、字体列表这些维度串起来看会更有意思。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表