在爬虫开发过程中,目标网站往往会通过请求特征识别 拦截非浏览器或非移动端 App 的访问请求。普通的爬虫请求因为请求头简单、TLS 指纹特征明显,很容易被反爬系统识别并封禁 IP。想要让爬虫请求完美伪装成手机 App 的正常请求,需要从三个核心维度入手:User-Agent 定制 、Header 头信息补全 、TLS 指纹模拟。本文将详细拆解这三个关键技术点,帮助开发者实现高隐蔽性的移动端 App 爬虫请求伪装。
一、核心原理:手机 App 的请求特征与爬虫伪装的必要性
手机 App 在与服务端通信时,会携带多层级的身份标识信息,这些信息是服务端判断请求合法性的重要依据:
- 应用标识:通过 User-Agent、AppVersion 等字段标识 App 的类型、版本、运行系统。
- 会话标识:通过 Cookie、Token、SessionId 等字段维持用户登录状态。
- 传输层特征 :通过 TLS 握手过程中的加密套件、扩展字段等形成的TLS 指纹,标识客户端的网络环境和设备类型。
而普通爬虫请求通常只携带少量必要字段,且 TLS 指纹与手机 App 存在明显差异,很容易被反爬系统判定为 "异常请求"。通过模拟手机 App 的请求头和 TLS 指纹,可以大幅降低爬虫被识别的概率。
二、第一步:定制 User-Agent,模拟手机 App 的身份标识
User-Agent(UA) 是请求头中最核心的身份标识字段,它直接告诉服务端当前请求的客户端类型(如手机型号、操作系统、App 版本)。手机 App 的 UA 格式与浏览器 UA 差异显著,开发者需要精准复刻目标 App 的 UA 格式。
1. 手机 App UA 的常见格式
不同平台(Android/iOS)的 App UA 格式存在差异,以下是典型示例:
-
Android App UA 示例 :
plaintext
Dalvik/2.1.0 (Linux; U; Android 13; Redmi K60 Build/TQ3A.230805.001) com.example.shop/3.8.2格式解析:
Dalvik版本 + 系统信息 + 手机型号 + App包名 + App版本号 -
iOS App UA 示例 :
plaintext
iOS/16.5.1 (iPhone14,3) com.example.mall/5.2.0 CFNetwork/1402.0.8 Darwin/22.5.0格式解析:
iOS版本 + 设备型号 + App包名 + App版本号 + 网络框架版本
2. 获取目标 App 的真实 UA
想要精准模拟,首先需要获取目标 App 的真实 UA,常用方法有两种:
- 抓包获取:使用 Charles、Fiddler 等抓包工具,将手机流量代理到电脑,捕获目标 App 的请求,直接从请求头中复制 UA 字段。
- 反编译获取 :对于 Android App,可以通过反编译 APK 文件,在
AndroidManifest.xml或代码中查找 UA 配置。
3. 爬虫中设置 UA 的实现(Python 示例)
在 Python 的requests或aiohttp库中,直接在请求头中配置定制的 UA:
python
运行
import requests
# 模拟Android App的UA
headers = {
"User-Agent": "Dalvik/2.1.0 (Linux; U; Android 13; Redmi K60 Build/TQ3A.230805.001) com.example.shop/3.8.2",
}
response = requests.get("https://api.example.com/data", headers=headers)
注意事项
- 避免使用通用 UA 模板,必须与目标 App 的 UA 完全一致;
- 部分 App 会在 UA 中加入设备唯一标识(如 IMEI),需要同步模拟;
- 动态更新 UA,当目标 App 版本迭代时,及时更新 UA 中的版本号。
三、第二步:补全 Header 头信息,还原手机 App 的请求上下文
手机 App 的请求头不仅包含 UA,还会携带大量辅助标识字段,这些字段共同构成了请求的 "上下文环境"。只设置 UA 而忽略其他字段,依然会被反爬系统识别。开发者需要根据抓包结果,补全所有必要的 Header 字段。
1. 手机 App 请求头的核心字段
除了 User-Agent,以下字段是手机 App 请求中高频出现的关键字段,需要重点模拟:
| 字段名 | 作用 | 示例值 |
|---|---|---|
| Host | 指定目标服务器的域名和端口 | api.example.com |
| Accept-Encoding | 标识客户端支持的压缩格式 | gzip, deflate |
| Accept-Language | 标识客户端的语言偏好 | zh-CN,zh;q=0.9 |
| Connection | 标识连接类型 | keep-alive |
| AppVersion | App 版本号(部分 App 自定义字段) | 3.8.2 |
| DeviceId | 设备唯一标识 | 868888050000000 |
| Token | 用户登录令牌 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
| Referer | 请求来源(部分 App 会校验) | https://api.example.com/home |
2. 爬虫 Header 的配置原则
- 完全复刻 :以抓包获取的请求头为基准,一字不差地复制所有字段,包括字段的顺序(部分服务端会校验字段顺序);
- 动态生成:对于 Token、DeviceId 等动态变化的字段,需要通过模拟登录或设备注册流程获取,避免使用固定值;
- 避免冗余:不要添加抓包结果中不存在的字段,多余的字段可能会暴露爬虫特征。
3. 完整 Header 配置示例(Python + requests)
python
运行
import requests
# 完全复刻抓包得到的手机App请求头
headers = {
"Host": "api.example.com",
"User-Agent": "Dalvik/2.1.0 (Linux; U; Android 13; Redmi K60 Build/TQ3A.230805.001) com.example.shop/3.8.2",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"AppVersion": "3.8.2",
"DeviceId": "868888050000000",
"Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"Referer": "https://api.example.com/home"
}
response = requests.get("https://api.example.com/data", headers=headers)
四、第三步:模拟 TLS 指纹,突破传输层的反爬检测
即使请求头完全复刻手机 App,很多反爬系统依然能通过TLS 指纹 识别爬虫。TLS 指纹是指客户端在 TLS 握手阶段,向服务端发送的加密套件列表、扩展字段、版本号等信息的组合特征。不同的客户端(如手机 App、浏览器、Python 爬虫库)的 TLS 指纹存在显著差异。
1. TLS 指纹的反爬原理
服务端会维护一个合法客户端的 TLS 指纹库,当接收到请求时,会将客户端的 TLS 指纹与库中的指纹对比:
- 如果指纹匹配,则判定为合法请求;
- 如果指纹不匹配(如 Python 的
requests库默认的 TLS 指纹),则判定为异常请求,直接拦截。
2. 爬虫 TLS 指纹模拟的核心工具
Python 中默认的requests库使用的是urllib3的 TLS 配置,指纹特征明显。想要模拟手机 App 的 TLS 指纹,需要使用定制化的 TLS 客户端库,常用工具包括:
- requests + pyOpenSSL:通过替换底层 SSL 库,自定义 TLS 加密套件和扩展字段;
- httpx:支持自定义 TLS 配置,更灵活地模拟不同客户端的 TLS 指纹;
- curl_cffi:直接调用 libcurl,支持模拟手机 App、浏览器的 TLS 指纹,是目前最推荐的工具。
3. 使用 curl_cffi 模拟手机 App 的 TLS 指纹(Python 示例)
curl_cffi可以直接模拟指定客户端的 TLS 指纹,包括手机 App、Chrome、Firefox 等,使用方法简单:
(1)安装依赖
bash
运行
pip install curl_cffi
(2)模拟 Android App 的 TLS 指纹
python
运行
from curl_cffi import requests
# 模拟Android App的TLS指纹,指定client为手机端类型
headers = {
"User-Agent": "Dalvik/2.1.0 (Linux; U; Android 13; Redmi K60 Build/TQ3A.230805.001) com.example.shop/3.8.2",
"Host": "api.example.com",
"Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
# 其他字段
}
# client参数指定模拟的客户端类型,支持android、ios等
response = requests.get(
"https://api.example.com/data",
headers=headers,
client="android" # 模拟Android App的TLS指纹
)
print(response.text)
(3)自定义 TLS 指纹
如果需要精准匹配目标 App 的 TLS 指纹,可以通过抓包获取 TLS 握手的加密套件和扩展字段,然后通过curl_cffi的ssl_options参数自定义:
python
运行
from curl_cffi import requests
from curl_cffi.const import SSL_OPTS
# 自定义加密套件和扩展字段
ssl_options = {
SSL_OPTS.CIPHERS: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256",
SSL_OPTS.VERSION: "TLSv1.3",
}
response = requests.get(
"https://api.example.com/data",
headers=headers,
ssl_options=ssl_options
)
注意事项
- TLS 指纹需要与请求头的客户端类型匹配(如 Android App 的 TLS 指纹对应 Android 的 UA);
- 避免频繁切换 TLS 指纹,否则可能被判定为异常行为;
- 部分 App 会使用证书固定(Certificate Pinning) 技术,需要提前获取 App 的证书并配置到爬虫中。
五、进阶优化:动态请求特征,提升伪装的隐蔽性
即使完成了 User-Agent、Header、TLS 指纹的模拟,固定的请求特征依然存在被识别的风险。开发者可以通过以下进阶手段,进一步提升爬虫的隐蔽性:
- 动态 UA 池:收集多个不同设备、不同版本的目标 App UA,每次请求随机选择一个;
- 请求间隔随机化:模拟手机用户的操作节奏,设置随机的请求间隔,避免高频次请求;
- Cookie 与 Token 动态更新:通过模拟登录流程,定期获取新的 Cookie 和 Token,避免使用固定值;
- IP 池轮换:结合代理 IP 池,每次请求使用不同的 IP 地址,降低单 IP 的请求频率;
- 请求体参数加密:部分 App 会对请求体参数进行加密(如 AES、RSA),需要反编译 App 获取加密算法,在爬虫中实现参数加密。
六、合规性提醒
爬虫请求伪装技术的核心目的是模拟正常用户行为,而非突破网站的访问限制。在使用相关技术时,需要严格遵守以下原则:
- 遵守目标网站的
robots.txt协议; - 不爬取涉及用户隐私、商业机密的内容;
- 控制请求频率,避免对目标网站的服务器造成压力;
- 用于商业用途时,需提前获得目标网站的授权。
七、总结
爬虫请求伪装成手机 App 的核心是 **"细节复刻"**:从应用层的 User-Agent、Header,到传输层的 TLS 指纹,都需要与目标 App 的请求特征完全一致。通过本文的方法,开发者可以实现高隐蔽性的移动端 App 爬虫请求伪装,有效规避大部分反爬系统的检测。同时,开发者需要牢记合规原则,在法律和道德的框架内使用爬虫技术。