
凌晨两点我盯着监控后台那条近乎垂直上升的曲线第一反应是服务器被攻击了。但翻了一圈错误日志没有数据库异常也没有应用报错CPU负载也平稳——这说明访问确实到了站只是没有触发业务逻辑。问题出在访问来源上我在HN一个海外知名技术社区发了一篇关于某个开源项目的介绍帖帖子上了首页然后我的网站就被AI bot流量淹没了。准确说是连续几天被各种各样的爬虫轮番扫。HN本身能给个人站点带来真实用户流量这是很多人梦寐以求的曝光但很少有人会提前告诉你帖子一旦上榜紧随其后涌进来的不只是读者还有成建制的AI训练爬虫、SEO抓取工具、内容采集程序。这篇博文我想把完整的经历写下来——流量从哪来、怎么识别、怎么拦截、拦截之后效果如何以及踩过哪些想当然的坑。无论是自建博客、个人项目页还是小公司官网只要你想公开某个URL这份日志都有参考价值。1. 一篇HN帖子引发的流量风暴先从数据异常说起1.1 发布前的预期与发布后的现实发帖之前我是有心理准备的。HN的读者群体对技术内容向来热情帖子上首页后短时间内涌入几千个PV都属于正常操作。所以当时我甚至提前给nginx多开了几个worker进程想的是别让静态页面的响应速度拖后腿。帖子发出后的头几个小时数据确实符合预期来源主要是HN的跳转用户分布在全球各地访问路径集中在项目主页、GitHub链接和文档页。但到了后半夜情况开始不对了。访问量没有像正常用户流量那样衰减反而保持着一个诡异的平稳高位更像是一台机器在匀速压测。真正让我警觉的是页面停留时长。真实用户从HN进来就算随便扫一眼也会停留几十秒但那一大堆会话几乎全部是打开主页-然后立刻离开持续时长普遍不到5秒部分甚至不到2秒。再看跳出率直接逼近100%。这个模式太整齐了整齐得像程序里跑出来的。1.2 监控后台显示的第一个异常信号我的监控栈比较简单nginx日志配合一个实时分析面板外加几行定时脚本统计top访问来源IP。异常出现时面板上最显眼的是某个IP段在半小时内贡献了超过6000次请求命中路径全是同一个URL——那正是我在HN帖子里贴的主页地址。单IP高频率请求其实不一定有问题搜索引擎的爬虫也会这样。但高峰期挤进来的一批IP段归属地分布很有规律一整个C段都来自同一家云服务商而且AS号高度集中。正常HN用户基本都走家庭宽带或移动网络不可能清一色来自数据中心。到这一步我基本确定这些不是来看帖子的人而是顺着HN露出的链接过来抓内容的机器。1.3 为什么HN会成为AI爬虫的高发入口后来我仔细想了想这个场景其实很好理解。HN有实时性、有内容权重、有大量外部链接天然就是一个发现新URL的窗口。AI训练爬虫的任务就是尽可能多地发现新页面、抓取并归档内容它们当然会优先盯这种信息聚合地。更关键的是HN域名本身的权重会让新发布的URL更快进入各种爬虫队列。你在自己的博客上发一篇文章可能要过很久才会被某些bot抓到但同一篇文章通过HN露出后等于给了所有爬虫一个明显的信号这里有一个新的、可能值得抓取的页面。于是GPTBot、ClaudeBot、Bytespider、PerplexityBot这些叫得上名字的还有大量叫不上名字的采集程序几乎会在同一时间段涌进来。这个过程我后来和朋友复盘时给了他一个比喻HN帖子就像烧烤摊上刚端出来的肉串爬虫就是闻到味道的猫。肉串放在那里一分钟整条街的猫都知道了。2. AI bot流量画像我是怎么从访问日志里认出它们的2.1 第一层识别User-Agent里明晃晃的自报家门最常规的识别方式就是看User-Agent以下简称UA。有些爬虫非常老实UA里直接写着自己是干什么的。爬虫标识UA片段里的关键词通常抓取内容GPTBotGPTBot, OAI-SearchBot模型训练语料、搜索索引ClaudeBotClaudeBot模型训练语料BytespiderBytespider模型训练语料、网页存档PerplexityBotPerplexityBot实时问答知识库CCBotCCBotCommon Crawl数据集archive.orgia_archiver网页存档AmazonbotAmazonbot产品数据、内容聚合Google-ExtendedGoogle-ExtendedAI训练控制扩展我在日志里筛了一遍仅GPTBot这一个UA一晚上就打了几百次请求。它访问的路径和真实用户高度重合主页、文档、博客归档、静态资源。除了不加载图片和CSS它几乎会把每个HTML页面都抓一遍。2.2 第二层识别伪装成浏览器的爬虫怎么找出来光看UA会漏掉相当一部分流量。我遇到的情况里有大约三成请求的UA和正常Chrome浏览器完全一样甚至连版本号都是最新的。这些伪装的bot如果只看UA几乎不可能和真实用户区分开。但它们会在别的地方露馅。首先是TLS指纹正规浏览器和常见的爬虫框架例如某些Python的HTTP客户端在用TLS握手时协商参数分布区间明显不一样。其次是行为模式真实用户打开页面后会加载静态资源而这些伪装bot通常只请求HTML、不拉js和css或者拉取顺序和正常浏览器完全相反。我在日志分析里加了一个简单规则如果某个IP请求的页面全部是text/html类型而图片、样式表、脚本的请求数为0就标记为可疑。这个规则抓出了不少伪装bot。它们把像是访客演了个开头却没耐心把静态资源请求也演完。2.3 第三层识别IP行为模式的规律性破绽IP层面的特征更容易总结。真实用户群体访问时间的分布是松散的有人半夜来有人早上来没有一个统一的节奏。而AI爬虫不一样它们会把抓取任务切成并发队列表现为短时间内集中请求、然后停一段时间、再集中请求——像潮水一样有规律地拍打服务器。我统计了高峰期最活跃的十几个IP段发现它们普遍具备以下特征归属都是知名云服务商或数据中心没有家庭宽带类IP请求频率呈均匀间隔分布部分间隔精确到毫秒级同一IP会在几小时内反复抓取同一个页面几乎不访问站内搜索、登录、评论等动态接口把这些行为综合起来之后剩下的基本就能实锤是bot了。我后来给分析脚本加了三个阈值单位时间请求数、HTML请求占比、静态资源请求比例。三个条件同时命中就自动把相关UA和IP段追加到封禁名单里。2.4 流量占比的真实数据比想象中严重得多被淹没这个说法一点不夸张。我把完整一周的nginx日志做了聚合对比了HN引流前一周和后一周的访问数据。指标发帖前一周均值发帖后一周均值单日总请求数2.3万11.8万疑似AI bot请求占比约10%约67%人工浏览器请求占比约90%约28%单日独立IP数1,2008,400AI bot流量在一周内超过了全部正常流量的总和而且是在帖子热度已经回落之后仍然持续。这说明爬虫的抓取任务一旦排上不会因为你帖子掉下首页就停止。3. 应对方案实测从robots.txt到强制验证的层层加码3.1 第一道防线robots.txt能不能挡住它们很多人的第一反应是修改robots.txt直接在文件里声明AI爬虫不要抓我。这个方案成本最低但效果非常依赖对方守不守规矩。我在robots.txt里加的内容是这样的User-agent: GPTBot Disallow: / User-agent: OAI-SearchBot Disallow: / User-agent: ClaudeBot Disallow: / User-agent: Bytespider Disallow: /效果如何有一半的爬虫确实退了。GPTBot和ClaudeBot在更新队列之后明显地停止了对我的站点抓取。但另一半根本不在乎robots.txt尤其是那些伪装成浏览器UA的采集程序它们压根不会去读这个文件。所以我在日志里观察到一个有趣的现象robots.txt的请求量很高但请求之后服务器压力一点没减。3.2 第二道防线在nginx层面直接拦截与其指望对方自觉不如直接在入口处拒绝。我在nginx里加了一段判断逻辑根据UA关键字直接返回403。map $http_user_agent $is_ai_bot { default 0; ~*GPTBot 1; ~*ClaudeBot 1; ~*Bytespider 1; ~*PerplexityBot 1; ~*CCBot 1; ~*Amazonbot 1; ~*imagesift 1; ~*dataforseo 1; } server { # ...其他配置... if ($is_ai_bot) { return 403; } }这段配置上线后大约四成的AI bot流量在入口处被直接挡掉。注意我把if写法放在了server块里放到location块里容易和rewrite规则产生冲突这是nginx一个老坑了。不过UA拦截对伪装bot无效。它们用的是浏览器UA完全绕过这个规则。于是我又加了IP层面的封禁。3.3 动态封禁把行为异常IP段拉进黑名单我写了一个小脚本每10分钟跑一次做的事情很简单分析最近10分钟的nginx日志找出请求数超过阈值且HTML请求占比超过80%的IP然后把这些IP段追加到nginx的deny配置里。#!/bin/bash # 简易bot封禁脚本每10分钟运行一次 ACCESS_LOG/var/log/nginx/access.log BLOCKLIST/etc/nginx/bot-ip.conf tail -n 5000 $ACCESS_LOG \ | awk {print $1, $7} \ | sort \ | uniq -c \ | sort -rn \ | awk $1 200 { split($2, ip, :) print deny ip[1] ; } \ | sort -u $BLOCKLIST nginx -s reload这脚本糙是糙了点但胜在直观。它把单位时间内访问量巨大的IP直接拒之门外。不过这里有个教训如果IP前端套了CDNdeny操作会把CDN节点的正常流量也一并误杀。我因为没注意这个中途误伤过一段时间的真实访客。后来加了白名单机制只对非CDN来源IP做动态封禁。3.4 第三道防线请求频率限制与JS挑战纯静态页面即使被高频请求对服务器压力也算可控。真正麻烦的是动态接口和搜索接口被爬虫调起来。我的项目页有一个数据统计接口每次调用会查一次数据库bots的频繁请求直接把这个接口的响应时间拉高了数倍。给动态接口加限速是最直接的办法。我在nginx里配置了请求频率限制按IP维度控制。limit_req_zone $binary_remote_addr zoneapi_limit:10m rate5r/s; server { location /api/ { limit_req zoneapi_limit burst10 nodelay; proxy_pass http://backend; } }这个配置表示每个IP每秒最多5个请求允许突发10个请求。对正常使用来说完全够用但能有效遏制bot的集中抓取。JS挑战是更彻底的手段。通过CDN层开启Managed Challenge对可疑访问先弹一个JavaScript验证通过后才放行。真实浏览器几乎无感知而大部分爬虫不会执行JS会直接卡在验证环节。我用这个方案解决掉了剩余的大部分伪装bot。3.5 四层方案的实际效果对比防护层拦截方式流量下降比例误伤风险robots.txt声明协商式靠对方自觉约30%极低UA过滤入口直接拒绝约40%低偶尔有兼容问题IP动态封禁行为触发封禁约50%中容易误伤CDN频率限制JS挑战动态限速、计算验证约70%低但影响部分老旧浏览器分层叠加之后AI bot流量被挡住了大约九成。日志里还能看到它们在尝试访问主页但大多数请求被策略拦截已不构成实质压力。4. 数据污染和成本问题比流量上涨更值得重视的隐患4.1 AI bot流量会让你的数据报表彻底失真如果只是服务器多扛一点流量这事还算不上多严重。真正让我头疼的是数据变得不可信了。那段时间站点分析工具里的访客数暴涨但如果直接拿这个数据去做内容复盘会得出帖子带来巨大真实流量的错误结论。我把HN引来的真实用户流量单独拆分出来后发现真实用户规模大约是原始统计数字的三分之一。这个偏差足以让任何基于数据的决策跑偏。更要命的是那些伪装的bot也在消耗数据分析。它们不会触发页面事件但会拉高PV数、拉低停留时长、拉高跳出率。久而久之你对自己忠实读者规模、内容受欢迎程度的判断都会被污染。4.2 成本账单带宽费虽然不多但积少成多个人站点的图片、PDF、文档这些静态资源每被完整抓取一次就会产生真金白银的带宽成本。我用的服务器带宽包月有流量限额那天晚上异常流量直接让我当月的流量配额用掉了七成。我特意算了一下那些bot对我主页和几个核心HTML页面的抓取总量并不算特别夸张但如果它们把每篇文章附带的图片也全部拉一遍成本就会快速上升。幸运的是大部分爬虫对图片兴趣有限主要抓HTML。但确实有那类整站镜像型爬虫会毫不留情地把所有资源都下载走。遇到那种爬虫一个月流量配额可能在几个小时内清零。所以我的建议是高流量时段提前在CDN控制台设置临时缓存规则并要求静态资源走CDN回源避免bot回源源站。4.3 内容被拿去训练模型一个绕不开的策略思考流量问题解决到一半我更纠结的问题浮出水面这些内容真的愿意被别人抓走去当语料吗我项目里的不少技术文档是我花时间整理的有的还包含独家的调试思路和踩坑记录。它们被AI模型收录后相当于成了公开训练语料。这个问题没有标准答案有人在网上公开内容就是希望被引用被传播有人则介意自己的原创内容成为别人产品的一部分。我的处理方式分了两层。公开的技术分享文章完全不介意被收录本来写出来就是给大家看的。但涉及内部细节的内容比如特定项目的部署方案、带敏感信息的代码片段我已经做了登录可见处理。这样即使爬虫来了也只能看到公开展示的部分进不了受限区。这也算是在开放和保守之间给自己留了一个缓冲地带。4.4 认清一个现实没有任何措施能100%挡住所有bot我花了将近一周的时间调整各种策略到最后发现一个无奈的事实永远会有新的爬虫程序绕过你的防线。它们更新UA、模拟浏览器行为、使用分布式IP池技术上防不胜防。但这不意味着前面的工作白做了。真实目的明确过滤掉那些讲规矩的爬虫让UA过滤承担最大的拦截量用行为识别抓出伪装bot压缩它们的攻击窗口用限速策略压制单个IP的请求频率防止单点瞬间打垮服务让站点的真实统计回归可信区间这套组合下来你的站点对一般规模的AI bot流量就能做到基本免疫。真正的价值不是把bot清零而是让服务器负载回到你可以掌控的状态。5. 现在我会怎么做一张长效运维清单经历了这场流量风波之后我再也没有裸奔过。现在我的习惯是每次对外发布内容之前先检查一遍防护配置并且给自己定了一份简单的清单。第一确认robots.txt是否覆盖最新出现的AI爬虫关键字。爬虫的种类更新很快每季度我会重新搜一遍有哪些新出现的知名bot把它们加进deny名单。第二nginx的UA拦截规则要持续更新。因为新bot出现速度很快我把UA关键字列表单独放了一个配置文件方便随时新增不用动主配置。第三频率限制规则要覆盖所有动态接口而不只是首页。爬虫最难驯服的地方在于它会反复访问同一个动态接口只要把接口的限速做好服务器压力就能被兜住。第四定期看日志里的UA分布和IP分布。我每个月固定抽一小时把上个月的访问日志拉出来看看重点对比AI bot请求量占比有没有上升。如果占比超过了五成就说明防护策略需要重新调整了。第五建立正确的流量预期。HN或其他社区带来的真实流量是脉冲式的来了很快会回落。如果一段时间内流量持续稳定却整齐划一先别高兴太早很可能拜访你的不是人而是机器。第六在站点分析工具里把已知bot的流量单独过滤掉。现在我的面板默认只看真实用户解释的数据bot流量只作为后台参考避免它干扰内容趋势判断。最后说说我的体会。一开始看到流量暴增我内心是有点惊喜的一度觉得是不是真的火了。冷静下来看到统计里那93%的跳出率和接近零的页面停留时间才意识到来的都是机器人。处理完这波bot流量后我反而对流量这件事有了更清醒的认识当一个页面被公开到某个高流量入口后服务器账单和日志里呈现的数据很可能只代表了机器人的热情而不是读者的热情。真正的指标永远是那些愿意在你页面停留超过10秒、愿意点击链接继续翻下一页的真实访客。