PHP项目怎么应对爬虫

wen PHP项目 2

本文目录导读:

PHP项目怎么应对爬虫

  1. 第一层:基础检测与拦截(防小白/低端爬虫)
  2. 第二层:频率控制与限流(防高并发暴力抓取)
  3. 第三层:行为分析(防模拟浏览器的高级爬虫)
  4. 第四层:签名与混淆(动态请求令牌)
  5. 第五层:被动验证(强制人机验证)
  6. 生产环境落地建议(PHP 代码示例)
  7. 核心误区与警告(必读)
  8. 应对不同场景的策略选择

在 PHP 项目中应对爬虫,需要根据爬虫的友好程度(善意搜索引擎 vs 恶意采集)和攻击强度(简单请求 vs 高并发)采取分层防御策略。

以下是针对 PHP 项目的实战防御方案,从“温和”到“强硬”分为五个层级:


第一层:基础检测与拦截(防小白/低端爬虫)

这一层主要针对不伪装 UA(User-Agent)或明显异常的请求。

  1. 校验 User-Agent(UA):

    • 封禁空 UA 或包含 python-requestsGo-http-clientScrapy 等关键字。
    • 注意: 高段位爬虫会伪装成 Chrome,所以这只是基础门槛。
  2. IP 黑白名单:

    • nginx 或 应用层封禁已知的恶意 IP 段(如某些 IDC 机房 IP)。
    • 使用 PHP 获取 $_SERVER['REMOTE_ADDR'] 进行数据库查询判断。
  3. HTTP 请求头校验:

    • 检查 Accept-LanguageReferer 是否符合常规浏览器逻辑。
  4. JS 渲染检测:

    • 这是区分浏览器和 Curl 最有效的方式之一。
    • PHP 输出页面时,通过 Set-Cookie 设置一个由 JS 生成的加密值,如果后续请求没有携带这个 Cookie,判定为爬虫(meta refresh 跳转或 返回 403)。

第二层:频率控制与限流(防高并发暴力抓取)

单纯靠 UA 和 IP 封禁不够,因为爬虫可以拨号换 IP,最核心的机制是 限流

  1. Redis 计数器(滑动窗口):

    • 针对 IP + URL 设定单位时间访问上限。
    • 代码逻辑(伪代码):
      $key = "rate_limit:{$ip}:{$url}";
      $count = $redis->incr($key);
      if ($count == 1) { $redis->expire($key, 60); }
      if ($count > 30) { http_response_code(429); exit('Too Many Requests'); }
  2. 并发数控制(令牌桶):

    • 防止爬虫开启 100 线程并发请求。
    • 使用 Redis 的 INCR 记录当前正在处理的单 IP 请求数,超过阈值(如 5)直接拒绝。
  3. Tarpit(慢速陷阱):

    • 识别出疑似爬虫的 IP 后,不直接拒绝,而是让 PHP sleep(5) 再返回,消耗爬虫的线程池和网络连接数,降低其抓取效率。

第三层:行为分析(防模拟浏览器的高级爬虫)

高级爬虫会携带正确的 Cookie、模拟浏览器行为,但其点击路径与人类不同

  1. 鼠标轨迹与点击事件:

    • 在前端埋点,记录用户从 mousedownmouseup 的轨迹坐标和时长。
    • 将加密的数据 POST 给后端 PHP 接口,如果请求数据为空或坐标杂乱,判定为爬虫。
  2. Cookie 存活期追踪:

    • 人类用户访问 A 页面后,会隔几秒再访问 B 页面。
    • 爬虫通常是毫秒级连续请求,PHP 可以计算两次请求的时间差($_SERVER['REQUEST_TIME_FLOAT'] 差值),如果单 IP 的请求间隔普遍小于 200ms,且无 mousemove 事件,则标记为爬虫。
  3. 蜜罐页面(Honeypot):

    • 在页面 HTML 中放置一个 CSS display:nonevisibility:hidden 的链接(/hidden-link-123)。
    • 正常用户看不到,永远不会点击,爬虫抓取该页面时,会顺着链接爬到蜜罐。
    • robots.txt不要屏蔽这个链接,一旦有 IP 请求了蜜罐链接,PHP 记录该 IP 并永久封禁。

第四层:签名与混淆(动态请求令牌)

这一层主要防止爬虫直接调用你的 API 接口(接口被扒)。

  1. 动态 Token(HMAC 签名):

    • 前端每次请求前,通过 JS 生成一个 sign(包含时间戳 + 随机数 + 通过 JS 算法处理后的密钥)。
    • 后端 PHP 校验 sign 是否有效以及时间戳是否过期(允许 5 分钟误差)。
    • 防御对象: 能有效阻止只会用 file_get_contents 拉取 HTML 的爬虫。
  2. CSS 字体反爬(针对文本内容):

    • 如果网站是小说站或招聘站,将数字或特定字符映射到自定义字体文件(@font-face)。
    • 浏览器显示正常,但爬虫拿到的 HTML 源码是乱码。

第五层:被动验证(强制人机验证)

当服务器已经“高度怀疑”对方是爬虫时,API 不应直接返回数据,而是强制下发验证码。

  • 滑块验证 / 点击验证:
    • 在 PHP 后端实现一个接口逻辑:/api/need_captcha
    • 当异常流量阈值被触发,PHP 接口返回 JSON 字段 "need_captcha": true,前端必须展示验证码。
    • 使用 Google reCAPTCHA v3 或 极验等云服务商,PHP 端只需要调用他们的验证 API,无需自己实现图形识别。

生产环境落地建议(PHP 代码示例)

入口文件 index.php 拦截逻辑:

// 引入检测类
require_once 'src/BotDetector.php';
$detector = new BotDetector($redis);
$result = $detector->check();
if ($result === 'block') {
    header('HTTP/1.1 403 Forbidden', true, 403);
    header('Content-Type: text/plain; charset=utf-8');
    exit('拒绝访问');
}
if ($result === 'captcha') {
    // 前端 JS 展示验证码,并携带 token 重新请求
    header('Content-Type: application/json');
    echo json_encode(['need_captcha' => true, 'msg' => '请完成人机验证']);
    exit;
}
// 正常逻辑...
require 'router.php';

核心 BotDetector 类实现(伪代码):

class BotDetector
{
    public function check()
    {
        $ip = $_SERVER['REMOTE_ADDR'];
        $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
        $now = time();
        // 1. 封禁已知恶意 IP
        if ($this->isBlackListed($ip)) return 'block';
        // 2. 基础 UA 过滤
        if (empty($ua) || preg_match('/Python|curl|wget|Go-http-client/i', $ua)) {
            $this->recordMark($ip, 3); // 加重标记
        }
        // 3. 蜜罐 IP 检测
        if ($this->isHoneypotHit($ip)) return 'block';
        // 4. 高并发限流(Redis)
        $count = $this->redis->incr("rate:{$ip}");
        if ($count == 1) $this->redis->expire("rate:{$ip}", 60);
        if ($count > 50) return 'block'; // 60秒内50次请求,太可疑
        // 5. 判断是否需要验证码(异常标记 >= 2 分)
        if ($this->getRiskScore($ip) >= 2) return 'captcha';
        return 'pass';
    }
}

核心误区与警告(必读)

  1. 不要完全依赖 IP 封禁: 爬虫多使用代理池,误封会导致整个局域网的正常用户无法访问。
  2. 防御重点在于“接口”而非“HTML”: App 端或前端 JS 调用的是同一个 /api/get_data.php,建议在 API 层(可能是 MVC 的 Controller 前)加 Request Sign 验证,而不要只防页面展示层。
  3. 区分搜索引擎蜘蛛: 记得放行 GooglebotBaiduspiderBingbot,否则网站 SEO 会受损,放行时反向验证 DNS 解析(通过 gethostbyaddr 反查 IP 是否属于 Google/百度官方 IP 段),防止伪造蜘蛛 UA。

应对不同场景的策略选择

攻击类型 推荐策略 实施成本
数据被全量爬走 行为分析 + 蜜罐 + 字体反爬 中高
服务器 CPU/带宽被打满 Nginx 层 IP 限流limit_req_zone)+PHP 层 Redis 计数
登录接口被撞库 极验/腾讯防水墙(第三方验证码)
接口被刷(无页面) HMAC 签名 + 时间戳校验

最简方案: 如果你只有半天时间,建议先做 UA 拦截 + Redis 限流 + 强制 JS Cookie 验证,这能挡住市面上 90% 的初级爬虫。

抱歉,评论功能暂时关闭!