Python爬虫实战:User-Agent大全与反爬策略解析
1. 项目缘起:为什么我们需要一份“User-Agent大全”?
如果你写过Python爬虫,哪怕只是写过最简单的requests.get(),大概率都见过这个错误:403 Forbidden,或者返回一堆乱码,又或者直接给你一个“请使用现代浏览器访问”的提示页面。很多时候,问题的根源不在于你的IP,也不在于你的请求频率,而在于你发出的那个请求头里,那个叫做User-Agent(简称UA)的小小字符串。
User-Agent是HTTP协议中的一个字段,它告诉服务器:“我是谁,我用什么来访问你”。对于服务器来说,一个来自python-requests/2.28.1的请求,和一个来自Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36的请求,待遇是天差地别的。前者明明白白地宣告自己是一个Python脚本,是来“爬”数据的;后者则伪装成了一个在Windows 10上运行的Chrome 114浏览器,是一个“正常用户”。
所以,准备一份详尽的、不断更新的浏览器User-Agent列表,对于爬虫开发者来说,就像战士需要一张精确的地图,厨师需要一套顺手的刀具。它不是为了炫技,而是最基础、最实用的生存技能。这份“大全”能帮你:
- 绕过基础的反爬机制:很多网站的第一道防线就是检查UA,非浏览器UA直接拒绝或返回简化版页面。
- 获取完整的页面内容:现代网站大量使用JavaScript渲染,服务器可能会根据UA决定下发哪个版本的资源(如桌面版、移动版、兼容老IE的降级版)。伪装成正确的浏览器,是拿到目标数据的前提。
- 模拟更真实的用户行为:在需要维持会话、处理复杂交互的爬虫中,一个合理的UA是构建可信HTTP客户端会话的起点。
网上确实有很多现成的UA列表,但要么年久失修,要么分类混乱,要么就是简单罗列。这篇文章,我想从一个爬虫实战者的角度,不仅给你一份整理好的、分类清晰的UA列表,更重要的是,和你深入聊聊UA背后的门道:怎么选、怎么用、怎么维护,以及那些光有列表解决不了的坑。
2. User-Agent的构成解析:不只是复制粘贴那么简单
在开始罗列清单之前,我们必须先拆解一个典型的User-Agent字符串。知其然,更要知其所以然,这样你才能在未来遇到新浏览器时,自己判断这个UA是否可用,甚至自己“组装”一个。
一个现代桌面版Chrome的UA可能是这样的:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
我们来分段解读:
Mozilla/5.0:这是一个历史遗留的兼容性标记。几乎所有现代浏览器都以此开头,源于早期的浏览器战争。可以理解为“这是一个兼容Mozilla标准的浏览器”。(Windows NT 10.0; Win64; x64):系统平台令牌。这是括号内的第一部分,包含了操作系统信息。Windows NT 10.0: 表示Windows 10操作系统。Win64和x64: 表示64位Windows系统。如果是32位,可能是WOW64(在64位系统上运行32位程序)或没有此标记。
AppleWebKit/537.36:渲染引擎标识。Chrome、Edge、Safari以及大多数现代浏览器都使用WebKit或它的分支Blink(Chrome/Edge)作为核心渲染引擎。这个版本号会随着浏览器内核更新而改变。(KHTML, like Gecko):另一个历史兼容标记,表明它兼容Gecko(Firefox的引擎)和KHTML(WebKit的前身)的渲染模式。Chrome/114.0.0.0:浏览器品牌和版本。这是最核心的标识,直接告诉服务器这是Chrome 114。Safari/537.36:为了兼容那些检测Safari的网站而添加的标记,因为WebKit最初是为Safari开发的。
理解了结构,我们就能明白,一个“好”的UA,不仅仅是版本号新,它的各个部分需要自洽。你不能用一个Windows NT 10.0的系统令牌,后面却跟着一个只支持macOS的Safari/15.0的浏览器标识,这种低级的矛盾很容易被服务器识破。
注意:移动设备的UA结构类似,但平台令牌不同。例如iOS设备会包含
iPhone或iPad以及CPU iPhone OS 13_5_1 like Mac OS X这样的信息;Android设备则会包含Linux; Android 10等。
3. 实战清单:分类整理的主流浏览器User-Agent
下面我将按照桌面端和移动端,以及浏览器品牌进行分类整理。这些UA是我从实际浏览器请求中收集、验证,并参考了最新版本信息整理的。请记住,浏览器的版本号是快速变化的,这里的列表是一个“模板”和“参考”,核心是学会如何根据这个模板去更新版本号。
3.1 桌面端浏览器
3.1.1 Google Chrome (Windows)
Chrome是目前市场份额最大的浏览器,伪装成Chrome是最常见的选择。
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36要点:
Win64; x64对应64位系统。WOW64对应在64位系统上运行的32位Chrome。- 第三个是更简化的版本,省略了位数信息。
- 将
120.0.0.0替换为最新的稳定版版本号(如121, 122等)。
3.1.2 Microsoft Edge (Windows)
Edge基于Chromium内核,其UA与Chrome高度相似,但带有Edg标识。
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要点:注意末尾的Edg/120.0.0.0。这是区分Edge和Chrome的关键。同样,版本号需要更新。
3.1.3 Mozilla Firefox (Windows)
Firefox使用Gecko渲染引擎,其UA格式独树一帜。
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0 Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/109.0要点:
rv:109.0表示Gecko的版本号,通常与Firefox主版本号一致。Gecko/20100101是一个固定日期标记,代表Gecko的渲染引擎。- 更新时主要修改
rv:109.0和Firefox/109.0中的版本号。
3.1.4 Apple Safari (macOS)
Safari是macOS的默认浏览器,其UA带有明显的苹果生态特征。
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15要点:
Macintosh; Intel Mac OS X 10_15_7表示在Intel芯片的Mac上运行macOS Catalina (10.15.7)。对于Apple Silicon芯片(M1, M2),此部分通常不变或变为Macintosh; ARM Mac OS X,但实践中多数网站不深究芯片架构。AppleWebKit/605.1.15是Safari的WebKit版本。Version/16.0是Safari的浏览器版本号。这是需要更新的主要部分。
3.2 移动端浏览器
移动端爬虫同样重要,很多网站对移动端和桌面端返回的HTML结构、API接口甚至数据都不同。
3.2.1 iOS Safari (iPhone/iPad)
Mozilla/5.0 (iPhone; CPU iPhone OS 16_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Mobile/15E148 Safari/604.1 Mozilla/5.0 (iPad; CPU OS 16_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Mobile/15E148 Safari/604.1要点:
CPU iPhone OS 16_3 like Mac OS X标识了iOS系统版本。Mobile/15E148是移动设备标识符的一部分。Version/16.3和系统版本对应。更新时需要同步修改系统版本和Safari版本。
3.2.2 Android Chrome
Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36 Mozilla/5.0 (Linux; Android 13; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36要点:
Android 10或Android 13是安卓系统版本。SM-G981B(三星Galaxy S20) 或Pixel 6是设备型号。这部分可以替换成其他流行机型,如Mi 10、VOG-AL00(华为P30)等,增加真实性。Mobile关键字表明这是移动版浏览器。- 更新Chrome版本号。
3.2.3 微信内置浏览器 (iOS/Android)
在国内爬取H5页面或公众号内容时,微信内置浏览器(XWEB)的UA非常关键。
Mozilla/5.0 (iPhone; CPU iPhone OS 16_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.40(0x1800282f) NetType/WIFI Language/zh_CN Mozilla/5.0 (Linux; Android 10; VOG-AL00 Build/HUAWEIVOG-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.99 XWEB/4313 MMWEBSDK/20220805 Mobile Safari/537.36 MMWEBID/6404 MicroMessenger/8.0.27.2220(0x28001B3D) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64要点:
- 结构复杂,包含了
MicroMessenger(微信)、NetType(网络类型)、Language(语言)等大量客户端信息。 - 安卓版还包含
XWEB(腾讯X5内核)和MMWEBSDK(微信Web SDK)信息。 - 重要:微信UA的
Chrome内核版本号往往滞后于官方Chrome。直接使用最新的Chrome移动版UA可能不如使用微信UA的特征更真实。
4. 在Python爬虫中动态管理与使用User-Agent
有了清单,下一步就是如何在代码中高效、安全地使用它们。直接硬编码在代码里是最差的做法,不利于维护和扩展。
4.1 构建一个UA池(User-Agent Pool)
最佳实践是创建一个UA池,每次请求随机选取一个,这样可以避免因短时间内大量相同UA的请求而触发反爬。
import random import requests DESKTOP_USER_AGENTS = [ ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36‘, ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36‘, ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0‘, ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15‘, ‘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‘, ] MOBILE_USER_AGENTS = [ ‘Mozilla/5.0 (iPhone; CPU iPhone OS 16_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Mobile/15E148 Safari/604.1‘, ‘Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36‘, ] def get_random_ua(platform=‘desktop‘): """随机获取一个User-Agent""" if platform == ‘mobile‘: return random.choice(MOBILE_USER_AGENTS) else: return random.choice(DESKTOP_USER_AGENTS) # 使用示例 headers = { ‘User-Agent‘: get_random_ua(), ‘Accept‘: ‘text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8‘, ‘Accept-Language‘: ‘zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2‘, ‘Accept-Encoding‘: ‘gzip, deflate, br‘, } response = requests.get(‘https://example.com‘, headers=headers)实操心得:
- 不要只用一个UA:即使你伪装成了Chrome,如果同一个IP在1分钟内用同一个Chrome UA发出100个请求,依然很可疑。随机轮换是基本操作。
- 平台匹配:如果你爬取的网站有专门的移动端适配(m.xxx.com 或响应式设计),那么使用移动端UA可能更容易获取到结构简单的页面。反之,如果需要获取桌面端的完整数据,就使用桌面端UA。最好能根据目标URL的特征动态选择。
- 维护版本号:定期(比如每月)检查一次主流浏览器的稳定版版本,更新你的UA池。过旧的UA(比如Chrome 80)可能会被服务器标记为“不安全的旧版浏览器”而限制功能。
4.2 进阶:使用fake-useragent库
手动维护UA池很麻烦。社区有一个非常流行的库叫fake-useragent,它可以动态生成看起来非常真实的UA。
pip install fake-useragentfrom fake_useragent import UserAgent import requests # 创建一个UserAgent对象 # 使用`use_cache_server=False`和`fallback`可以避免因为访问不到外部CDN而报错 ua = UserAgent(use_cache_server=False, fallback=‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...‘) headers = { ‘User-Agent‘: ua.random, # 随机生成一个 # ‘User-Agent‘: ua.chrome, # 指定生成Chrome的 # ‘User-Agent‘: ua.firefox, # 指定生成Firefox的 } response = requests.get(‘https://example.com‘, headers=headers) print(f“使用的UA: {headers[‘User-Agent‘]}“)踩坑与注意事项:
- 网络问题:
fake-useragent首次运行或定期会从远程服务器下载UA数据列表。如果网络环境受限,可能导致初始化失败或超时。这就是为什么上面代码中设置了use_cache_server=False并提供了fallback参数。更稳妥的做法是,在项目初始化时更新一次数据,然后将其缓存到本地文件。 - 生成逻辑:它生成的UA是“真实”的,但版本号可能不是最新的。对于版本号有严格要求的场景,仍需手动校验。
- 过度使用:如果一个网站的反爬策略非常严格,它可能会检测到
fake-useragent库生成的一些不常见的、或者版本号和系统信息略微不匹配的UA(虽然概率低)。在极高安全级别的场景下,手动维护一个精心挑选的、高仿真的小规模UA池可能更可靠。
5. 超越UA:反爬虫策略的对抗与伦理边界
仅仅更换UA在如今只是爬虫攻防战中最基础的一步。一个具备基本反爬能力的网站,会采用多维度检测:
请求头完整性检测:只改UA是不够的。一个正常的浏览器请求会携带一整套完整的Headers,如
Accept、Accept-Language、Accept-Encoding、Connection、Upgrade-Insecure-Requests、Sec-Fetch-*系列头等。你的爬虫也应该尽量补全这些头信息,特别是Sec-Fetch-Dest、Sec-Fetch-Mode、Sec-Fetch-Site、Sec-Fetch-User这几个用于指示请求来源和目的的头部,在现代浏览器中默认发送,缺失它们是一个明显的非浏览器信号。headers = { ‘User-Agent‘: ‘...‘, ‘Accept‘: ‘text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8‘, ‘Accept-Language‘: ‘zh-CN,zh;q=0.9,en;q=0.8‘, ‘Accept-Encoding‘: ‘gzip, deflate, br‘, ‘Connection‘: ‘keep-alive‘, ‘Upgrade-Insecure-Requests‘: ‘1‘, ‘Sec-Fetch-Dest‘: ‘document‘, ‘Sec-Fetch-Mode‘: ‘navigate‘, ‘Sec-Fetch-Site‘: ‘none‘, ‘Sec-Fetch-User‘: ‘?1‘, ‘Cache-Control‘: ‘max-age=0‘, }TLS指纹与HTTP/2指纹:高级反爬会检测客户端的加密套件、TLS版本、ALPN扩展等,形成TLS指纹;或者检测HTTP/2的连接序言和帧设置,形成HTTP/2指纹。使用标准的
requests库或aiohttp库,其指纹与Python的urllib3相关,和真实浏览器(如Chrome的boringssl)不同。对抗这个需要更底层的工具,如使用curl_cffi库(模拟浏览器TLS指纹)或直接操控浏览器自动化工具(如playwright、selenium)。浏览器环境与行为模拟:对于JavaScript重度依赖的网站,简单的HTTP请求无法执行JS,拿不到渲染后的数据。此时需要
Selenium、Playwright或Pyppeteer这类真正的浏览器自动化工具。它们启动的是一个完整的浏览器实例,拥有真实的UA、完整的HTTP头、Canvas指纹、WebGL指纹等,能通过绝大多数前端检测。但代价是资源消耗大、速度慢。from playwright.sync_api import sync_playwright with sync_playwright() as p: # 启动一个Chromium浏览器,更接近Chrome browser = p.chromium.launch(headless=False) # 调试时可设为False看界面 page = browser.new_page() page.goto(‘https://example.com‘) # 此时page.content()获取到的就是完全渲染后的HTML html = page.content() browser.close()IP频率与行为模式:这是最核心的防线。即使你伪装得天衣无缝,如果一个IP在短时间内发出成千上万的请求,也必然会被封禁。因此必须配合代理IP池、请求速率限制(如
time.sleep(random.uniform(1, 3)))、模拟人类操作间隔(点击、滚动)等策略。
关于伦理与法律的最后提醒:
- 遵守
robots.txt:在爬取前,访问网站的/robots.txt,查看对方是否明确禁止爬取某些路径。这是网络礼仪,也是一些法律诉讼中的参考依据。 - 尊重版权与数据所有权:爬取的数据用于个人学习、研究是合理的,但未经授权用于商业牟利、公开传播,可能侵犯对方的权益。
- 避免对目标网站造成负担:控制请求频率,避免DDoS式的访问,影响网站正常服务。这是基本的道德要求。
- 关注法律法规:数据安全法、个人信息保护法等法规对爬取个人信息有严格规定。切勿爬取、存储、泄露他人隐私信息。
一份好的UA列表是爬虫工程师工具箱里的螺丝刀,必不可少,但绝不是万能钥匙。真正的挑战在于理解反爬策略的完整链条,并在此基础上构建一个稳健、高效且负责任的爬虫系统。从UA出发,不断深入,这才是爬虫技术学习的正确路径。