curl_setopt设置user-agent必须在curl_exec前调用curlopt_useragent,不可用curlopt_httpheader伪造;轮换需模拟真实用户分布,配合referer、accept-language及随机延迟才有效。

curl_setopt 设置 User-Agent 的基础写法
PHP 的 curl_setopt 必须在 curl_exec 前设置好 CURLOPT_USERAGENT,否则无效。UA 字符串本身没有特殊格式要求,但需符合常见浏览器标识规范,否则目标站可能直接 403 或返回空内容。
常见错误是把 UA 写死在循环外、或误用 CURLOPT_HTTPHEADER 拼接 User-Agent: —— 这种方式不推荐,因为会和 CURLOPT_USERAGENT 冲突,且部分服务端只认后者。
正确做法:
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://example.com'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'); curl_exec($ch);
轮换 UA 列表的三种实用方式
真实反爬场景中,单一 UA 长时间高频请求极易被识别。轮换不是“随机挑一个”,而是要模拟真实用户分布:Windows + Chrome 占比高,Mac + Safari 次之,移动端需带 Mobile 关键字。
立即学习“PHP免费学习笔记(深入)”;
- 静态数组 +
array_rand:适合小批量请求,简单可靠 - 文件读取(如
file('ua_list.txt')):UA 数量多、需频繁更新时更灵活 - 数据库查表 + 缓存(如 Redis):高并发场景下避免重复 UA 短期集中出现
注意:array_rand 返回键名,不是值,别漏掉二次取值:
$uas = ['Mozilla/5.0 (Win)...', 'Mozilla/5.0 (Mac)...']; $key = array_rand($uas); curl_setopt($ch, CURLOPT_USERAGENT, $uas[$key]);
配合 Referer、Accept-Language 和延迟更有效
只换 UA 是最低限度操作。多数中等防护站点会校验请求头组合逻辑:比如 Chrome UA 却没 Accept-Language: zh-CN,zh;q=0.9,或 Referer 为空但请求的是二级页面,都容易触发风控。
建议每次请求至少同步设置三项:
-
CURLOPT_USERAGENT:从列表中轮换 -
CURLOPT_REFERER:设为该站点首页或上一页 URL(非必须,但有更好) -
CURLOPT_HTTPHEADER:加入Accept-Language和Accept,例如['Accept-Language: zh-CN,zh;q=0.9', 'Accept: text/html,application/xhtml+xml']
另外,usleep(rand(500000, 1500000))(500ms–1500ms)比固定 sleep 更难建模,别省这一步。
UA 轮换失效的典型信号与应对
如果轮换后仍频繁 403 / 503 / 返回验证码,说明对方已升级检测维度:不只是 UA,还在追踪 IP 行为、TLS 指纹、HTTP/2 请求顺序、甚至 JS 渲染环境。
此时单纯换 UA 没用,需检查:
- 是否所有请求共用同一个
curl_init()句柄?复用句柄会继承上次的 Cookie 和连接状态,应每次新建或显式curl_reset($ch) - 是否漏了
CURLOPT_SSL_VERIFYPEER和CURLOPT_SSL_VERIFYHOST?设为 false 虽能绕过证书错误,但某些 WAF 会标记“异常 TLS 握手” - 响应体里是否有
data-selenium、window._phantom类字段?说明对方在做前端环境探测,后端 curl 无法绕过
真遇到这种层级,就得考虑 Puppeteer 或 Playwright 驱动真实浏览器,curl 就不是合适工具了。











