本文目录导读:

在PHP项目中识别和应对爬虫访问的频率限制(即反爬虫机制中的“限流”),通常需要从请求特征分析和行为模式检测两个维度入手。
以下是系统性的识别与应对方案,分为被动识别(被限制时的现象)和主动预防(模拟正常行为)两部分。
被动识别:如何判断被限制频率
当爬虫被目标网站识别并限制时,通常会出现以下特征,代码中可以通过检查响应来发现:
HTTP状态码异常
- 429 Too Many Requests:最直接的限流标志,大部分网站会使用此状态码。
- 503 Service Unavailable:服务器端主动拒绝连接,可能是限流后的临时封禁。
- 403 Forbidden:IP或User-Agent被加入黑名单。
- 302/301重定向:部分网站(如知乎、小红书)会将爬虫请求重定向到验证页面或登录页。
包含提示
- 返回HTML中包含“访问过于频繁”、“请稍后再试”、“输入验证码”等中英文关键词。
- 返回JSON中包含
"ret": -1、"msg": "rate limit"、"code": 4011等自定义错误码。
请求延迟或超时
- 请求耗时突然增加(从200ms变为10s以上),可能是服务器故意延迟响应(慢速攻击防御)。
- cURL错误:
CURLE_OPERATION_TIMEDOUT(28号错误)。
代码示例(检测限制):
$response = $client->request('GET', 'https://target.com/api');
$status = $response->getStatusCode();
$body = $response->getBody()->getContents();
if ($status === 429 || $status === 503) {
// 触发限流,进入等待或切换代理逻辑
handleRateLimit();
}
if (strpos($body, '操作太频繁') !== false) {
handleRateLimit();
}
主动预防:模拟正常用户行为
关键在于降低请求密度并隐藏爬虫特征。
控制请求间隔(最基本且有效)
不要使用固定间隔,而是使用随机间隔。
// 错误做法:固定1秒 sleep(1); // 正确做法:随机延迟,模拟人类操作 $delay = rand(1500, 3500) / 1000; // 1.5秒到3.5秒之间随机 usleep($delay * 1000000);
请求头伪装
- User-Agent:必须轮换,使用真实浏览器版本(Chrome 120+、Edge 110+)。
- Referer:模拟从其他页面点击进入(如从百度搜索进入)。
- Accept-Language:保持固定且合理(如
zh-CN,zh;q=0.9)。 - Cookies:模拟浏览器携带的完整Cookie(包括
__cfduid、_ga等)。
$headers = [
'User-Agent' => getRandomUserAgent(),
'Referer' => 'https://www.google.com/search?q=keyword',
'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',
];
IP代理轮换(核心抗封手段)
单个IP频繁请求极易触发限流,使用代理池是长周期爬虫的必备策略。
$proxyList = [
'http://user:pass@proxy1.com:8080',
'http://user:pass@proxy2.com:8080',
'http://user:pass@proxy3.com:8080',
];
$proxy = $proxyList[array_rand($proxyList)];
$client = new GuzzleHttp\Client([
'proxy' => $proxy,
'timeout' => 10,
'headers' => $headers,
]);
注意:免费代理稳定性差,建议使用付费住宅代理或数据中心代理。
请求频率控制(令牌桶算法)
避免瞬时爆发请求,使用令牌桶控制整体的QPS(每秒查询数)。
class RateLimiter {
private $rate; // 每秒令牌数
private $lastTime;
private $tokens;
public function __construct($rate) {
$this->rate = $rate;
$this->lastTime = microtime(true);
$this->tokens = $rate;
}
public function acquire() {
$now = microtime(true);
$this->tokens += ($now - $this->lastTime) * $this->rate;
$this->tokens = min($this->tokens, $this->rate);
$this->lastTime = $now;
if ($this->tokens < 1) {
$sleepTime = (1 - $this->tokens) / $this->rate;
usleep($sleepTime * 1000000);
$this->tokens = 0;
} else {
$this->tokens -= 1;
}
}
}
$limiter = new RateLimiter(0.5); // 每2秒1个请求
$limiter->acquire(); // 阻塞直到可以发送
浏览器指纹模拟(高级反反爬)
部分网站(如抖音、淘宝)会检测WebGL、Canvas、字体列表等指纹,PHP原生无法模拟,需要借助无头浏览器。
- 方案:使用
headless-chromium-php或puppeteer(通过Node.js子进程)驱动真实浏览器访问。 - 优点:特征完全与真实用户一致。
- 缺点:速度慢,消耗资源大。
// 使用如 headless-chromium-php 库执行JS
use HeadlessChromium\BrowserFactory;
$browserFactory = new BrowserFactory('chromium-browser');
$browser = $browserFactory->createBrowser([
'headless' => true,
'windowSize' => [1920, 1080],
]);
$page = $browser->createPage();
$page->navigate('https://target.com')->waitForNavigation();
$html = $page->getHtml();
高级识别与应对策略
动态Token与签名(Anti-Spider Token)
大型网站(如淘宝、大众点评)的API请求需要携带加密的签名、时间戳、Cookie中的_csrf等,需要:
- 分析JS代码:使用浏览器开发者工具,找到签名的生成逻辑。
- 模拟生成:在PHP中重写该签名算法(通常需要阅读混淆后的JS)。
- 方案:如果JS逻辑复杂,直接使用
V8Js扩展执行JS,或通过Puppeteer获取签名。
请求间隔的智能分布
- 基础频率:每页面抓取间隔3-8秒。
- 高峰期:避开目标网站的高峰时段(如晚上8-10点)。
- 失败重试:遇到429时,使用指数退避。
function requestWithRetry($url) {
$maxRetries = 3;
for ($i = 0; $i < $maxRetries; $i++) {
$response = sendRequest($url);
if ($response->getStatusCode() === 429) {
$wait = pow(2, $i) * rand(10, 30); // 等待 10-60秒
sleep($wait);
continue;
}
return $response;
}
throw new Exception('Max retries reached');
}
分布式爬虫协调
如果使用多个服务器或PHP进程同时爬取,需要一个中心化的代理IP池管理和请求计数器(推荐使用Redis):
- Redis计数器:记录每IP/每5分钟的请求次数,超过阈值自动切换代理IP。
- 队列消费:使用Gearman或Redis List进行任务分配,控制整体整体并发数。
实战建议
| 场景 | 核心策略 | 工具/库 |
|---|---|---|
| 简单页面抓取 | 随机间隔 + User-Agent轮换 + 代理IP | GuzzleHttp + faker (生成随机UA) |
| 中等难度API | 固定QPS + 签名伪造 + Cookie维持 | GuzzleHttp + 定制签名模块 |
| 强反爬网站 | 无头浏览器模拟 + 行为延迟 + 住宅代理 | headless-chromium-php + Puppeteer |
| 大型分布式抓取 | Redis速率控制 + 代理自动切换 + 队列 | Redis + RabbitMQ + Scrapy (如用Python) |
最后提醒:在PHP项目中进行爬虫访问,务必遵守目标网站的robots.txt协议并设置合理的抓取速度,过度请求不仅会被封IP,还可能涉及法律风险,如果需要稳定、长周期抓取,建议使用成熟的代理服务商(如BrightData、Oxylabs),它们提供自动轮转IP和请求频率控制。