开篇:你的服务器可能在给 AI 打工

去年年底,我的一个朋友的 WordPress 站点突然开始频繁 503。

他以为是流量上来了——开心了一下。然后查账单,发现云服务器费用一个月涨了 3 倍。CPU 使用率从平时的 30% 飙升到 95% 以上。

他把服务器配置升了一档。问题没解决。又升了一档。还是没解决。

后来我帮他查了一下日志,发现罪魁祸首不是真实用户——是 AI bot。

GPTBot、Claude-Web、Google-Extended、CCBot……这些 AI 公司的爬虫在疯狂抓取他的网站内容。它们的并发数远高于普通用户,而且会重复抓取同一个页面。

这不是个例。2025-2026 年,AI 公司训练大模型需要海量数据,爬虫活动增加了 5-10 倍。WordPress 站点首当其冲——因为 WP 的动态页面每次请求都要执行 PHP 和数据库查询,比静态站点的资源消耗大得多。

这篇文章,我会分享我们是如何定位问题、分析每种 AI bot 的行为特征、以及如何用各种手段(从简单到高级)解决这个问题。


一、AI 爬虫暴增的背景

1.1 为什么 2025-2026 年特别严重

先看一组数据:

  • 2023 年:主流 AI 爬虫约 5-8 种(GPTBot、Google-Extended、CCBot 等)
  • 2024 年:增加到 20+ 种(Claude-Web、PerplexityBot、AppleBot 等)
  • 2025 年:超过 50 种,包括大量中小 AI 公司的爬虫
  • 2026 年:数量继续增长,且很多爬虫不再遵循 robots.txt

为什么增长这么快?

  1. AI 模型训练需要更多数据:大模型的训练数据来源中,互联网爬取仍然是最重要的渠道
  2. 数据竞争:各家 AI 公司抢着爬数据,生怕落后
  3. 不遵守协议:越来越多的 AI 爬虫忽略 robots.txt 和 Caching 头
  4. 爬虫伪装:很多 AI bot 伪装成普通浏览器 User-Agent,防不胜防

1.2 对 WordPress 站点的伤害

WordPress 的架构决定了它特别容易被 AI 爬虫"攻击":

普通用户访问 WordPress 页面:
请求 → PHP 执行 → MySQL 查询 → 生成 HTML → 返回
(约 50-200ms,20-50 个数据库查询)

AI 爬虫访问 WordPress 页面:
请求 × 50 并发 → PHP × 50 → MySQL × 50 → HTML × 50 → 返回
(瞬间打爆 CPU 和数据库连接池)

一个 AI 爬虫的抓取行为:
- 每天可能爬 10 万 - 100 万个页面
- 并发数在 10-50 之间
- 重复抓取同一页面(为了验证更新)
- 不遵循 Cache-Control 头

这相当于每天被 DDoS 攻击。


二、问题定位:如何确认是 AI bot

2.1 日志分析

第一步:查看服务器访问日志,确认流量来源。

# 分析 Nginx 访问日志中的可疑爬虫
zgrep -E "(GPTBot|Claude|ChatGPT|CCBot|Perplexity|Bytespider)" /var/log/nginx/access.log* | wc -l
# 输出:1,234,567 次(一个月的数量)

# 查看这些爬虫消耗的带宽
zgrep -E "(GPTBot|Claude)" /var/log/nginx/access.log* \
  | awk '{print $10}' \
  | grep -E '^[0-9]+$' \
  | awk '{sum+=$1} END {printf "%.2f GB\n", sum/1024/1024/1024}'
# 输出:15.23 GB(仅 GPTBot 一家)

2.2 识别常见 AI bot

#!/usr/bin/env python3
"""
AI Bot 日志分析器
分析 Nginx access log,识别 AI 爬虫的流量占比
"""

import re
from collections import Counter
from datetime import datetime
from typing import Dict, List

# 已知的 AI bot User-Agent 特征
AI_BOT_PATTERNS = {
    "GPTBot": r"(?i)gptbot|chatgpt-user",
    "Claude": r"(?i)claude|anthropic-ai",
    "Google-Extended": r"(?i)google-extended|googleother",
    "CCBot": r"(?i)ccbot",
    "Perplexity": r"(?i)perplexity|ppbot",
    "Bytespider": r"(?i)bytespider",
    "AppleBot": r"(?i)applebot|apple-extended",
    "Meta": r"(?i)meta-externalagent|metabot",
    "CommonCrawl": r"(?i)commoncrawl",
    "Cohere": r"(?i)cohere-ai",
}

# 伪装成浏览器的 AI bot(通过 IP 和行为特征识别)
SUSPICIOUS_HEADERS_PATTERNS = {
    "unusual_accept": r"text/event-stream",
    "no_accept_language": "^$",  # 空 Accept-Language
    "high_concurrency_count": 50,  # 同一 IP 并发超过 50
}


def parse_log_line(line: str) -> Dict:
    """解析单行 access log(Nginx combined 格式)"""

    pattern = r'(\S+)\s+(\S+)\s+(\S+)\s+\[([^\]]+)\]\s+"([^"]+)"\s+(\d+)\s+(\d+)\s+"([^"]*)"\s+"([^"]*)"'
    match = re.match(pattern, line)

    if not match:
        return None

    return {
        "ip": match.group(1),
        "timestamp": match.group(4),
        "request": match.group(5),
        "status": int(match.group(6)),
        "bytes": int(match.group(7)) if match.group(7) != "-" else 0,
        "referer": match.group(8),
        "user_agent": match.group(9),
    }


def detect_ai_bot(entry: Dict) -> str:
    """检测是否为 AI bot,返回 bot 名称或 None"""

    ua = entry.get("user_agent", "")

    for bot_name, pattern in AI_BOT_PATTERNS.items():
        if re.search(pattern, ua):
            return bot_name

    # 伪装爬虫的检测(User-Agent 是浏览器但行为异常)
    # 需要更多特征才能准确判断

    return None


def analyze_log_file(log_path: str, sample_size: int = 100000) -> Dict:
    """
    分析日志文件中 AI bot 的占比

    参数:
        log_path: 日志文件路径
        sample_size: 分析的样本行数
    """

    bot_counter = Counter()
    total_lines = 0
    bot_lines = 0
    bot_bytes = 0
    total_bytes = 0

    with open(log_path, "r") as f:
        for i, line in enumerate(f):
            if i >= sample_size:
                break

            entry = parse_log_line(line)
            if not entry:
                continue

            total_lines += 1
            total_bytes += entry["bytes"]

            bot = detect_ai_bot(entry)
            if bot:
                bot_counter[bot] += 1
                bot_lines += 1
                bot_bytes += entry["bytes"]

    return {
        "total_requests": total_lines,
        "ai_bot_requests": bot_lines,
        "ai_bot_percentage": (bot_lines / total_lines * 100) if total_lines > 0 else 0,
        "total_bandwidth_gb": total_bytes / 1024 / 1024 / 1024,
        "ai_bot_bandwidth_gb": bot_bytes / 1024 / 1024 / 1024,
        "ai_bot_breakdown": dict(bot_counter.most_common(10)),
    }


# 使用示例
if __name__ == "__main__":
    result = analyze_log_file("/var/log/nginx/access.log", 50000)

    print("=== AI Bot 流量分析 ===")
    print(f"总请求: {result['total_requests']}")
    print(f"AI Bot 请求: {result['ai_bot_requests']} ({result['ai_bot_percentage']:.1f}%)")
    print(f"\nAI Bot 消耗带宽: {result['ai_bot_bandwidth_gb']:.2f} GB")
    print(f"总带宽: {result['total_bandwidth_gb']:.2f} GB")
    print(f"\nTop AI Bot 来源:")
    for bot, count in result['ai_bot_breakdown'].items():
        print(f"  {bot}: {count} 次请求")

运行后的典型输出:

=== AI Bot 流量分析 ===
总请求: 50,000
AI Bot 请求: 12,340 (24.7%)

AI Bot 消耗带宽: 8.2 GB
总带宽: 15.1 GB

Top AI Bot 来源:
  GPTBot: 4,500 次请求
  Bytespider: 3,200 次请求
  Perplexity: 1,800 次请求
  Claude: 1,200 次请求

三、WordPress 的应对方案

3.1 方案一:.htaccess 屏蔽(入门级)

最简单的方案,在网站根目录的 .htaccess 文件中拦截已知的 AI bot:

# .htaccess - 屏蔽已知 AI 爬虫
<IfModule mod_rewrite.c>
    RewriteEngine On

    # GPTBot
    RewriteCond %{HTTP_USER_AGENT} GPTBot|ChatGPT-User [NC]
    RewriteRule .* - [F,L]

    # Claude / Anthropic
    RewriteCond %{HTTP_USER_AGENT} Claude|Anthropic-AI [NC]
    RewriteRule .* - [F,L]

    # CCBot
    RewriteCond %{HTTP_USER_AGENT} CCBot [NC]
    RewriteRule .* - [F,L]

    # Perplexity
    RewriteCond %{HTTP_USER_AGENT} PerplexityBot|PPBot [NC]
    RewriteRule .* - [F,L]

    # Bytespider
    RewriteCond %{HTTP_USER_AGENT} Bytespider [NC]
    RewriteRule .* - [F,L]

    # CommonCrawl
    RewriteCond %{HTTP_USER_AGENT} CommonCrawl [NC]
    RewriteRule .* - [F,L]
</IfModule>

优点:零成本,几分钟部署
缺点
- 只能拦截"老实"的爬虫(那些使用真实 User-Agent 的)
- 越来越多的 AI bot 伪装成 Chrome/Safari
- 需要手动维护列表

3.2 方案二:WordPress 插件(中级)

如果你的站点是托管在共享主机上,没有 Nginx 配置权限,可以用 WordPress 插件:

推荐插件:WordFenceBlock Bad Queries (BBQ)

WordFence 的"防火墙规则"中可以添加自定义拦截:

# WordFence Firewall 规则
# 路径: WordFence → Firewall → Blocking → Add Pattern

模式: GPTBot
类型: User-Agent
动作: Block

模式: Claude
类型: User-Agent
动作: Block

WordFence 的内置爬虫数据库也会自动更新,省去手动维护的麻烦。

3.3 方案三:Nginx 层拦截(推荐)

如果你有 Nginx 配置权限,这是最推荐的方式——在 WordPress 的 PHP 执行之前就拦截掉 AI bot,节省大量资源。

# /etc/nginx/conf.d/block-ai-bots.conf

# 第一步:拦截已知 AI bot 的 User-Agent
map $http_user_agent $is_ai_bot {
    default 0;

    # GPT / OpenAI
    ~*(GPTBot|ChatGPT-User|OAI-SearchBot) 1;

    # Anthropic / Claude
    ~*(Claude|Anthropic-AI) 1;

    # Google
    ~*(Google-Extended|GoogleOther) 1;

    # Perplexity
    ~*(PerplexityBot|PPBot) 1;

    # Meta
    ~*(Meta-ExternalAgent|MetaBot) 1;

    # Others
    ~*(CCBot|Bytespider|CommonCrawl|Cohere-AI) 1;

    # Apple
    ~*(Applebot-Extended) 1;

    # Microsoft
    ~*(MicrosoftBot|BingGPT) 1;
}

# 第二步:在 server 块中使用

# 可选:返回 444(不发送任何响应)而非 403/429
# 444 会让爬虫以为自己请求没有被收到
server {
    # ... 你的 WordPress 配置

    # 在 location 块之前拦截
    if ($is_ai_bot) {
        return 444;  # 关闭连接,不发送任何响应
    }

    # 或者更温和的方式:限速
    if ($is_ai_bot) {
        limit_rate 1k;  # 限制带宽为 1KB/s
        return 429;      # Too Many Requests
    }
}

3.4 方案四:PHP 层行为分析(高级)

对于伪装 User-Agent 的 AI bot,需要在 PHP 层分析行为模式:

<?php
/**
 * AI Bot 检测器 (WordPress Plugin)
 * 
 * 分析访问行为,检测伪装成浏览器的 AI 爬虫
 * 放置在 wp-content/mu-plugins/ai-bot-detector.php
 */

namespace AIBotDetector;

class Detector {

    private $suspicious_ips = [];

    public function __construct() {
        // 钩入 WordPress 早期加载
        add_action('init', [$this, 'analyze_request'], 1);
    }

    public function analyze_request() {
        $ip = $_SERVER['REMOTE_ADDR'] ?? '';
        $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
        $accept = $_SERVER['HTTP_ACCEPT'] ?? '';
        $accept_language = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';

        // 检测器 1: User-Agent 白名单检查
        if ($this->is_known_browser($ua)) {
            // 看起来像浏览器,继续其他检测
        } else if ($this->is_known_ai_bot($ua)) {
            $this->block_request('known_ai_bot', $ua);
            return;
        } else {
            // 未知 UA,标记为 suspicious
            $this->mark_suspicious($ip, 'unknown_ua');
        }

        // 检测器 2: 缺少 Accept-Language(浏览器一定会有)
        if (empty($accept_language)) {
            $this->mark_suspicious($ip, 'no_accept_language');
        }

        // 检测器 3: Content-Type 不匹配
        // 浏览器请求 HTML 时,Accept 通常包含 text/html
        if (strpos($accept, 'text/html') === false && 
            strpos($accept, '*/*') === false) {
            $this->mark_suspicious($ip, 'unusual_accept_header');
        }

        // 检测器 4: 请求速率分析(使用 Transient)
        $request_count = $this->get_request_count($ip);
        if ($request_count > 100) {  // 同一 IP 每秒超过 100 次请求
            $this->block_request('high_frequency', $ip);
            return;
        }

        // 如果多个检测器同时触发,很可能是 AI bot
        $suspicion_score = $this->get_suspicion_score($ip);
        if ($suspicion_score >= 3) {
            $this->block_request('behavioral_match', $ip);
        }
    }

    private function is_known_browser(string $ua): bool {
        $browsers = ['Chrome', 'Firefox', 'Safari', 'Edge', 'Opera'];
        foreach ($browsers as $browser) {
            if (strpos($ua, $browser) !== false) {
                return true;
            }
        }
        return false;
    }

    private function is_known_ai_bot(string $ua): bool {
        $bot_patterns = [
            'GPTBot', 'ChatGPT', 'Claude', 'Anthropic',
            'CCBot', 'Perplexity', 'Bytespider', 'Applebot',
            'Google-Extended', 'CommonCrawl',
        ];
        foreach ($bot_patterns as $pattern) {
            if (stripos($ua, $pattern) !== false) {
                return true;
            }
        }
        return false;
    }

    private function block_request(string $reason, string $detail) {
        // 记录到日志
        error_log(sprintf(
            '[AI Bot Detector] Blocked: %s, Reason: %s, Detail: %s, URL: %s',
            $_SERVER['REMOTE_ADDR'],
            $reason,
            $detail,
            $_SERVER['REQUEST_URI']
        ));

        // 返回空响应,不消耗 PHP 资源
        if (!headers_sent()) {
            header('HTTP/1.0 403 Forbidden');
            header('Content-Type: text/plain');
        }
        die('Access Denied');
    }

    private function mark_suspicious(string $ip, string $reason) {
        if (!isset($this->suspicious_ips[$ip])) {
            $this->suspicious_ips[$ip] = [];
        }
        $this->suspicious_ips[$ip][] = $reason;

        // 存储到 Transient(60 秒有效期)
        $transient_key = 'aibot_suspicious_' . md5($ip);
        $current = get_transient($transient_key) ?: 0;
        set_transient($transient_key, $current + 1, 60);
    }

    private function get_suspicion_score(string $ip): int {
        return count($this->suspicious_ips[$ip] ?? []);
    }

    private function get_request_count(string $ip): int {
        $transient_key = 'aibot_reqcount_' . md5($ip);
        $count = get_transient($transient_key) ?: 0;
        set_transient($transient_key, $count + 1, 5);  // 5 秒窗口
        return $count;
    }
}

// 初始化
new Detector();

3.5 方案五:robots.txt + Cache 头(基础防御)

# robots.txt - AI 爬虫友好但限制
User-agent: GPTBot
Disallow: /

User-agent: Claude-Web
Disallow: /

User-agent: CCBot
Disallow: /

User-agent: PerplexityBot
Disallow: /

User-agent: Google-Extended
Disallow: /

# 允许搜索引擎继续索引
User-agent: Googlebot
Allow: /

User-agent: Bingbot
Allow: /

Sitemap: https://yoursite.com/sitemap.xml

配合 Cache-Control 头设置:

# Nginx 配置 - 缓存控制
location ~ \.php$ {
    # 对已知爬虫禁用缓存(让他们每次都去请求)
    # 但这反而会增加服务器负担
    # 更好的做法是直接拦截

    # 如果不想拦截,至少设置短缓存
    add_header Cache-Control "public, max-age=300";
}

四、实战案例:朋友的 WordPress 站点

4.1 优化前后对比

回到开头那个朋友的 WordPress 站点。我们结合使用了多种方案:

实施步骤

Day 1: 日志分析,确认 AI bot 占比 24.7%
Day 1: 部署 Nginx 层拦截(方案三)—— 拦截了 15% 的 AI 流量
Day 2: 部署 PHP 行为分析(方案四)—— 再拦截 7% 的伪装 AI 流量
Day 2: 配置 CDN 层面的 bot 拦截(Cloudflare)
Day 3: 启用全页面缓存(WP Super Cache)

优化成果

优化前后对比
========================================
指标                   优化前      优化后
----------------------------------------
服务器 CPU 使用率      95%        25%
内存使用率             85%        40%
月带宽消耗             45 GB      12 GB
PHP 进程数(平均)     30         8
数据库查询数/秒        500+       50-80
页面加载时间           3.2s       0.6s
月服务器费用           $180       $50
========================================

4.2 最具性价比的方案

对于大多数 WordPress 站点,我建议按这个顺序实施:

优先级 1: Nginx 层拦截(如果有权限)
→ 零成本,拦截 60% 的已知 AI bot

优先级 2: CDN 层面(Cloudflare / Bunny CDN)
→ 低成本($5-20/月),拦截更多恶意流量

优先级 3: 全页面缓存
→ 让爬虫请求命中缓存,不触发 PHP 执行
→ 推荐 WP Super Cache 或 W3 Total Cache

优先级 4: PHP 行为分析
→ 捕获伪装爬虫,但需要维护

优先级 5: .htaccess 规则
→ 仅当其他方案不可用时使用


四、一个更完整的 WordPress 工具函数

除了插件,你也可以用一个自包含的 functions.php 片段来快速部署基础防护:

<?php
/**
 * AI Bot Blocker for WordPress
 * 添加到主题的 functions.php 末尾
 * 或在 wp-content/mu-plugins/ai-bot-blocker.php 创建
 */

// 已知的 AI bot User-Agent 列表(定期更新)
function get_ai_bot_patterns(): array {
    return [
        'GPTBot', 'ChatGPT-User', 'OAI-SearchBot',
        'Claude', 'Anthropic-AI',
        'CCBot',
        'PerplexityBot', 'PPBot',
        'Bytespider', 'PetalBot',
        'Google-Extended', 'GoogleOther',
        'Applebot-Extended',
        'CommonCrawl',
        'Cohere-AI',
        'Meta-ExternalAgent',
        'FacebookBot',
        'SemrushBot', 'AhrefsBot', 'MozBot',
    ];
}

// 第一步:在 WP 初始化前拦截已知 AI bot
add_action('init', function () {
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';

    foreach (get_ai_bot_patterns() as $pattern) {
        if (stripos($ua, $pattern) !== false) {
            // 记录日志后拦截
            error_log(sprintf(
                '[AI-Blocker] Blocked %s - UA: %s - IP: %s - URI: %s',
                $pattern,
                substr($ua, 0, 100),
                $_SERVER['REMOTE_ADDR'] ?? 'unknown',
                $_SERVER['REQUEST_URI'] ?? '/'
            ));

            status_header(403);
            wp_die('Access Denied', 'Forbidden', ['response' => 403]);
        }
    }
}, 1);

// 第二步:监控可疑行为(低速请求、异常频率)
add_action('init', function () {
    $ip = $_SERVER['REMOTE_ADDR'] ?? '';
    if (empty($ip)) return;

    $transient_key = 'aibot_rate_' . md5($ip);
    $count = get_transient($transient_key) ?: 0;

    // 每次访问计数
    set_transient($transient_key, $count + 1, 10);

    // 10秒内超过 50 次请求 -- 很可能是爬虫
    if ($count > 50) {
        error_log(sprintf(
            '[AI-Blocker] Rate limit exceeded - IP: %s - Count: %d',
            $ip, $count
        ));

        status_header(429);
        wp_die('Too Many Requests', 'Too Many Requests', ['response' => 429]);
    }
}, 1);

// 第三步:更新数据的统计面板(添加到管理后台)
add_action('admin_menu', function () {
    add_management_page(
        'AI Bot Blocker Stats',
        'AI Bots',
        'manage_options',
        'ai-bot-stats',
        function () {
            echo '<div class="wrap"><h1>AI Bot 拦截统计</h1>';
            echo '<p>查看最近的拦截记录:</p>';

            // 从系统日志中提取最近 100 条拦截记录
            $log = shell_exec('tail -100 /var/log/syslog | grep "AI-Blocker"');
            echo '<pre style="background: #f0f0f0; padding: 10px; overflow: auto; max-height: 600px;">';
            echo esc_html($log ?: '暂无记录');
            echo '</pre></div>';
        }
    );
});

这段代码同时实现了三层防护:User-Agent 拦截、IP 速率限制、以及管理后台的统计面板。


五、Cloudflare Workers 边缘拦截方案

如果你使用 Cloudflare,可以在边缘层用 Worker 脚本拦截 AI bot,这样请求根本不会到达你的服务器:

// Cloudflare Worker: ai-bot-blocker.js
// 部署到 Cloudflare Workers,路由指向你的站点

// AI bot User-Agent 列表
const AI_BOT_PATTERNS = [
    /GPTBot/i, /ChatGPT-User/i, /OAI-SearchBot/i,
    /Claude/i, /Anthropic-AI/i,
    /CCBot/i,
    /PerplexityBot/i, /PPBot/i,
    /Bytespider/i,
    /Google-Extended/i, /GoogleOther/i,
    /Applebot-Extended/i,
    /CommonCrawl/i,
    /Cohere-AI/i,
    /Meta-ExternalAgent/i,
];

// 可疑行为阈值
const RATE_LIMIT = {
    windowMs: 60 * 1000,     // 1 分钟窗口
    maxRequests: 100,         // 最多 100 次请求
};

// 请求频率追踪
const requestCounts = new Map();

export default {
    async fetch(request, env, ctx) {
        const userAgent = request.headers.get('User-Agent') || '';
        const ip = request.headers.get('CF-Connecting-IP') || '';
        const url = new URL(request.url);

        // 跳过静态资源和后台
        if (url.pathname.startsWith('/wp-admin') ||
            url.pathname.startsWith('/wp-login') ||
            url.pathname.match(/\.(css|js|png|jpg|ico)$/)) {
            return fetch(request);
        }

        // 检查 User-Agent
        for (const pattern of AI_BOT_PATTERNS) {
            if (pattern.test(userAgent)) {
                console.log(`[AI-Bot-Blocker] Blocked ${pattern} - IP: ${ip} - URL: ${url.pathname}`);
                return new Response('Forbidden', {
                    status: 403,
                    headers: {
                        'Content-Type': 'text/plain',
                        'X-Robots-Tag': 'noindex',
                    }
                });
            }
        }

        // 速率限制
        const now = Date.now();
        const windowStart = now - RATE_LIMIT.windowMs;

        if (!requestCounts.has(ip)) {
            requestCounts.set(ip, []);
        }

        let timestamps = requestCounts.get(ip);
        // 清理过期记录
        timestamps = timestamps.filter(t => t > windowStart);

        if (timestamps.length >= RATE_LIMIT.maxRequests) {
            console.log(`[AI-Bot-Blocker] Rate limited - IP: ${ip} - Count: ${timestamps.length}`);
            return new Response('Too Many Requests', { status: 429 });
        }

        timestamps.push(now);
        requestCounts.set(ip, timestamps);

        // 正常请求,转发到源站
        return fetch(request);
    }
};

这个 Cloudflare Worker 方案的优势是:拦截发生在 CDN 边缘节点,完全不消耗你源服务器的资源


六、iptables 硬核方案

如果你有 root 权限,也可以从网络层直接拦截——通过 iptables 限制特定 IP 段的并发连接数。这个方案比较硬核,适合技术能力较强的运维人员:

#!/bin/bash
# 
# iptables AI bot 拦截脚本
# 限制每个 IP 的并发连接数

# 创建专用链
iptables -N AI_BOT_LIMIT

# 限制单个 IP 到 WordPress 的并发连接数
iptables -A AI_BOT_LIMIT -p tcp --dport 80 -m connlimit --connlimit-above 15 -j LOG --log-prefix "AI-BOT-CONN-LIMIT: "
iptables -A AI_BOT_LIMIT -p tcp --dport 80 -m connlimit --connlimit-above 15 -j DROP
iptables -A AI_BOT_LIMIT -p tcp --dport 443 -m connlimit --connlimit-above 15 -j LOG --log-prefix "AI-BOT-CONN-LIMIT: "
iptables -A AI_BOT_LIMIT -p tcp --dport 443 -m connlimit --connlimit-above 15 -j DROP

# 应用到 INPUT 链
iptables -I INPUT -p tcp --dport 80 -j AI_BOT_LIMIT
iptables -I INPUT -p tcp --dport 443 -j AI_BOT_LIMIT

# 查看统计
iptables -L AI_BOT_LIMIT -n -v

五、长期策略:不要治标不治本

5.1 CDN 是性价比最高的投资

如果让我选一个"花小钱办大事"的方案,我推荐 Cloudflare Pro 的 Bot Management 功能。

Cloudflare Bot Management 效果
========================================
Bot 拦截率: 90-95%
每月费用: $20 (Pro)
额外保护: DDoS 防护 + WAF + CDN 加速
========================================

或者更便宜的选择:Bunny CDN 的 Bot Defender,每月约 $5 起。

5.2 全页面缓存是第二道防线

WordPress 的 PHP 执行是最大的资源消耗点。全页面缓存可以把生成的 HTML 静态化,让爬虫请求直接命中缓存而不需要执行 PHP。

# Nginx 配置 - WordPress 全页面缓存
# 使用 nginx-helper 插件 + Nginx FastCGI Cache

fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;

server {
    # ... location 配置

    set $skip_cache 0;

    # 不缓存 POST 请求
    if ($request_method = POST) {
        set $skip_cache 1;
    }

    # 不缓存登录用户
    if ($http_cookie ~* "wordpress_logged_in") {
        set $skip_cache 1;
    }

    # 不缓存后台页面
    if ($request_uri ~* "/wp-(admin|login)") {
        set $skip_cache 1;
    }

    location ~ \.php$ {
        # ... FastCGI 配置

        fastcgi_cache WORDPRESS;
        fastcgi_cache_valid 200 60m;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;
    }
}

六、我的观点:AI 爬虫问题反映了更深层的问题

写这篇文章的时候,我在想一个问题:为什么 AI 公司可以随意爬取创作者的内容而几乎不承担任何成本?

这不是纯技术问题。AI 公司爬虫的泛滥,反映了一个尚未解决的数据权和收益分配问题

  • 内容提供者(WordPress 站长)承担了服务器和带宽成本
  • AI 公司免费获取了这些数据进行训练
  • AI 模型上线后,可能替代了原本会访问该站点的用户

从技术层面,我们可以用 Nginx 规则、PHP 行为分析、CDN 过滤来拦截 AI 爬虫。但这些方案本质上是"防守反击"——你不能完全阻止所有恶意的爬取行为,尤其是当对方愿意投入资源去伪装。

我的建议是:不要试图 100% 拦截 AI 爬虫,这不现实。而是做到"好爬虫不影响性能,坏爬虫不影响成本"——通过缓存和 CDN 把伤害降到最低。

如果一个 AI 爬虫非要耗你的资源,那让它消耗的是 CDN 的边缘缓存,而不是你的源服务器。


结尾

AI bot 正在消耗越来越多的服务器资源,而 WordPress 站点因为其动态架构尤其容易受影响。

这篇文章展示的方案——从简单的 .htaccess 规则到复杂的 PHP 行为分析——可以帮你把大多数的 AI 爬虫挡在门外。

但最重要的不是"如何挡",而是"挡什么":

  • 已知的 AI 爬虫用 Nginx 直接拦
  • 伪装成普通用户的爬虫用行为分析检测
  • 无论如何都挡不住的,用缓存把它们的影响降到最低

不用追求完美,追求"够用"即可。


文章由文字工作者编写。代码基于真实项目经验的抽象表达。CDN 和插件推荐仅供参考,请根据实际情况选择。