fake-useragent 不实时联网获取 ua,而是读取本地缓存文件,长期不更新会导致 ua 过期、sec-ch-ua 等现代请求头缺失,易触发反爬风控;需手动更新并匹配完整请求头。

fake-useragent 的数据源不是实时联网获取的
很多人误以为 UserAgent() 每次调用都会去网上抓最新 UA,其实不是。它默认从本地缓存文件(fake_useragent.json)读取,这个文件只在首次安装或手动更新时生成。如果几个月没更新,里面可能还存着 Chrome 90、Firefox 78 这类早已淘汰的 UA 字符串——而目标网站的反爬系统早就不认这些“过期身份证”了。
真实情况是:浏览器版本迭代快,UA 字符串随之变化;服务器会把长期未见的 UA 当作可疑信号,尤其当它和 Accept、Sec-Ch-Ua 等现代请求头不匹配时,反而更容易触发风控。
- 首次使用时自动下载一次数据,之后不再自动刷新
- 缓存路径通常为
~/.fake_useragent.json(Linux/macOS)或%USERPROFILE%\.fake_useragent.json(Windows) - 手动更新命令是
fakeuseragent --update或代码中调用ua.update()
固定 UA 池 + 长期不更新 = 请求指纹固化
即使你用了 ua.random,如果整个池子都是 2022 年的老 UA,那所有请求的 UA、Accept、Accept-Language 组合就高度趋同——服务器一看:“这堆请求都来自‘Chrome/91 on Win10’,但没人用这个版本了”,立刻标记为异常流量。
更麻烦的是,现代反爬已不单看 UA,而是综合 Sec-Ch-Ua、Sec-Ch-Ua-Mobile、Sec-Ch-Ua-Platform 这些 Chromium 新增头字段。老版 fake-useragent 根本不生成这些字段,导致请求头残缺,等于主动递上“我是爬虫”的证据。
- 新版 Chrome(v115+)默认发送
Sec-Ch-Ua头,值类似"Not.A/Brand";v="8", "Chromium";v="120" - 旧 UA 字符串无法对应生成合法的 Sec-Ch-Ua 值,requests 直接发空或错配,触发风控
- 建议搭配
requests-html或手动补全 Sec-* 头,而非依赖 UA 字符串本身
不同网站对 UA 新鲜度的容忍阈值差异很大
电商、新闻类站点更新 UA 黑名单较慢,可能容忍半年前的 UA;但 SaaS 后台、金融平台、Google/Bing 搜索接口几乎实时校验 UA 有效性。你在爬某招聘网站时用 Chrome/102 可能没事,但一访问 LinkedIn 就直接 403。
这不是库的问题,而是反爬策略分层的结果:低敏感站点靠 UA 做粗筛,高敏感站点用 UA + 时间戳 + TLS 指纹 + JS 环境做细筛。你池子里的 UA 越老,在后者面前越容易暴露。
- 测试方法:用
ua.chrome获取一个 UA,手动构造请求,对比响应头中的Server和X-Frame-Options是否异常 - 观察是否返回
cf-chl-bypass或__cf_bmCookie——这是 Cloudflare 开始深度验证的信号 - 真正可靠的 UA 更新周期不是“每月一次”,而是“每次上线新业务前必须更新”
更新不等于万事大吉:要注意 UA 与请求上下文的匹配性
就算你刚执行了 ua.update(),拿到最新的 Chrome/126 UA,但如果请求里还带着 Accept: */* 或空 Referer,照样会被打标。UA 是“脸”,但整套请求头才是“人设”。
一个 Chrome UA 却发 application/json 请求到 HTML 页面,或者用移动端 UA 访问桌面端专属接口,这种 mismatch 比 UA 本身过期更危险——它暴露的是逻辑错误,而非技术滞后。
- 优先复用真实浏览器抓包得到的完整请求头(含 Sec-*、Accept-Encoding、DNT)
- 避免混用:不要用 Safari UA + Chrome 特有的头字段
- 分布式场景下,确保各节点使用的 UA 缓存文件版本一致,否则出现“同一 UA 在不同机器上表现不同”的调试灾难
真实世界里,UA 库更新只是防封链条中最表层的一环。真正卡住你的,往往是那个没补上的 Sec-Ch-Ua-Platform,或是连续三次请求都带同样的 Referer。别只盯着库版本号,多看一眼自己发出去的完整请求头。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











