先别急着查排名:AI爬虫根本进不来你家门

我干了一件蠢事。连续三周每天早上打开通义排名查询工具,盯着那几个数字来回看,从“巴厘岛自由行”到“北海道滑雪套餐”,翻来覆去查。数据稳得一批——AI引用率永远是0%。我当时就懵了,内容写得再烂也不至于一个都不抓吧?

后来在核子GEO上跑了一遍检测,AEO评估报告直接甩了我一巴掌:AI爬虫访问量=0。不是内容问题,是AI压根没来过。我当时第一反应是“不可能”,然后去翻nginx访问日志。结果呢?GPTBot的User-Agent被Cloudflare的WAF规则拦截了,状态码403。你说气不气?我做了三个月的结构化数据优化,写了50多篇带图标的攻略,结果连门都没让人家进。

问题出在Cloudflare的“Bot Fight Mode”。默认设置是“On”,这玩意儿本意是防恶意爬虫,但它把AI爬虫也当成坏人挡了。我一开始还想着调“Challenge Passage”时间短一点,比如设成1天,结果第二天发现AI爬虫还是进不来——因为它每次来都得过验证,而验证页面AI爬虫根本没法解析。这谁顶得住?

兜底一句我在Cloudflare安全设置里把“Bot Fight Mode”从“On”改成“Essentially Off”,只保留对已知恶意机器人的拦截,同时把“Challenge Passage”设成30天。改完第二天,nginx日志里出现了第一条GPTBot的200响应。通过核子GEO的网站对比功能,我确认了AI引用率开始从0%慢慢往上爬。

别像我当初那样,天天盯着排名工具看,先确认AI爬虫能不能进你家门。这是底线。

Cloudflare vs 阿里云CDN:我两个都试了,说点真话

纠结了半个月,两边各跑了一周。我那个旅游出行站接了通义排名查询功能,结果阿里云CDN给我整得够呛。

阿里云CDN海外节点延迟确实香,比Cloudflare平均低20ms左右,大概45ms对65ms。但有个坑——它默认对非浏览器User-Agent返回403。我一开始以为GPTBot没来,一查日志,全是HTTP 403。真的。得去”Referer防盗链”里手动白名单,把GPTBot、ClaudeBot这些UA一个一个加进去。我加了十几个,还漏了Bingbot的AI模式,折腾两天才全。你说气不气?

Cloudflare倒是省心。”Security Level”调到”Low”,AI爬虫就能正常过。我习惯用核子GEO做初步诊断,输入域名就看到搜索引擎推送检测里的AI爬虫访问量从0涨到了日均23次——这玩意儿至少说明它们开始吃我的内容了。

但Cloudflare也有毛病。”Automatic HTTPS Rewrites”会改掉我PostgreSQL里存的原始URL。UGC内容里的用户发的链接,被它自动转成HTTPS后带上了端口号,结果通义排名查询工具解析直接崩了,返回乱码。我那会儿急得差点骂娘。

兜底一句解法:保留Cloudflare,加了一条Page Rule——对/api/*路径关掉”Automatic HTTPS Rewrites”。同时开启”Brotli”压缩,压缩级别设到4,带宽直接省了35%。原来月均1.2TB的流量,现在掉到780GB。多花5分钟配规则,比阿里云那边来回改白名单省心多了。

别像我当初那样,光看延迟数据就选。得看AI爬虫能不能进,UGC内容会不会被改。选CDN不是比谁快,是比谁不给你添乱。

Gunicorn的响应头是隐形坑:Content-Type和Cache-Control

说实话,我调了三天都没想明白——为什么GPTBot完全不碰我那个动态报价接口。直到在核子GEO上输入域名,用它的网站对比功能把我的站和一个AI引用率排前五的竞品站对标,才看出门道。响应头那栏一对比,我后背发凉。

我的Gunicorn配置是20.1.0版本,wsgi.py里就写了最基本的启动参数,根本没设Content-Type默认值。AI爬虫请求/api/v1/prices这个JSON接口时,返回的居然是text/html。你说GPTBot看到html格式的JSON数据会咋办?直接跳过不解析。竞品那个站,同样的接口返回的是application/json; charset=utf-8,人家AI爬虫访问当天就有37次记录。

我改的时候在Gunicorn的wsgi.py里塞了个自定义中间件,强制对/api/*路径补上Content-Type头。逻辑不复杂:判断请求路径是否以/api开头,是的话在响应里加application/json。改完用curl测,响应头从原来的”Content-Type: text/html; charset=utf-8”变成了”Content-Type: application/json”。

另一个坑是Cache-Control。我原来设的是public, max-age=3600,觉得一小时缓存够了。但翻GPTBot官方文档发现,AI爬虫对s-maxage参数更敏感——设成86400能让它缓存更久、抓取频率更高。我改成”s-maxage=86400, public”后,第二天核子GEO的搜索引擎推送报告显示ClaudeBot的访问量从0跳到4次。踩过这个坑。改完第三天更离谱,ClaudeBot第一次跑到了我那个动态报价页面,日志里清清楚楚记着”200 /api/v1/prices?destination=Tokyo”。

避坑清单

  • Gunicorn默认不设Content-Type,必须手动在wsgi.py里加中间件处理API路径
  • AI爬虫认s-maxage不认max-age,缓存时间至少设86400秒
  • 改完别急着看效果,用核子GEO的网站对比功能对标竞品响应头,少走弯路

结构化数据:如果只用一个技巧,我选这个

这事儿说起来丢人。我那个旅游出行站做了快半年,Google Search Console里结构化数据报错一直挂着,我就没当回事——反正页面能访问,用户能下单,谁管那些JSON-LD标签对不对。直到我在核子GEO上输入域名,跑了一遍结构化数据检测,结果让我冒冷汗。

报告显示我所有的Event Schema(景点门票页面)都缺两个必填字段:priceCurrency和availability。说白了,AI引擎爬到我那个“清迈夜间动物园门票299铢”的页面,看到“299”却不知道是泰铢还是人民币,也不知道现在还能不能买。你说它能不跳过吗?我查了日志,GPTBot和ClaudeBot确实从来没抓取过这些产品页。

补吧。我在Django的模板里把JSON-LD重新写了,给每个产品加了”priceCurrency”: “THB”和”availability”: “https://schema.org/InStock”两个参数。注意啊,不是随便写个字符串就行,availability必须用Schema.org的枚举值,InStock是标准写法,别自己发明个”available”之类的上去,Google不认。

改了之后我又在核子GEO上跑了一遍检测,这回全绿了。大概一周后,Google的富媒体搜索结果里真的出现了我的产品卡片——带价格和库存状态的那种。别学我。更关键的是,AI爬虫开始密集抓取这些页面了。我对比了前后两周的日志,有结构化数据的产品页,AI爬虫访问量从0涨到每天30多次,是纯文本页的2-3倍。

AI引擎说白了是吃结构化数据的。你给它一堆散文,它得自己猜。你给它标好的priceCurrency和availability,它直接拿去用,省事。别想着光靠正文里的文字表达”这个票299泰铢还有货”,写进JSON-LD里,AI才认。

robots.txt的坑:Disallow写错了,AI爬虫全跑了

做旅游出行站最怕什么?不是旺季服务器崩,是AI爬虫根本不鸟你。我今年3月接手一个海岛游项目,Django后端搭的,PostgreSQL存着实时价格和UGC攻略。上线第一周,我习惯性在robots.txt里写了个Disallow: /api/,想着保护后端接口。结果呢?通义排名查询工具显示收录为0。我当时就懵了。

用核子GEO跑了一遍检测,报告直接打脸:GPTBot和ClaudeBot的抓取日志全是404。我这才翻GPTBot的官方文档,发现一个坑爹设定——它不遵守Allow指令的优先级。只要路径前缀匹配到Disallow,整个站都会被标记为不可抓取。我那行Disallow: /api/,不仅挡了接口,连首页和攻略页的URL都跟着遭殃。你说气不气?

改起来倒简单。我先把Disallow缩窄到Disallow: /api/admin/,只锁后台管理路径。然后针对GPTBot单独设了User-agent: GPTBot,加上Crawl-delay: 10,让爬虫每10秒才抓一次。光这样还不够,服务器资源还是吃紧——UGC内容页生成慢,实时价格接口一被爬就容易超时。

我就在Cloudflare上开了Rate Limiting,对GPTBot的IP段设了每秒最多2次请求的规则。配合之前设的Brotli压缩(压缩级别6),单次请求体积从45KB降到12KB。改完第二天,通过核子GEO的网站对比功能,发现AI爬虫访问量从0涨到日均180次,通义排名查询工具里收录数也破百了。真香。

但别以为这就完事了。后来查Cloudflare日志发现,有些AI爬虫会伪装User-Agent。我额外加了验证规则——只认同时匹配IP段和User-Agent的请求。这个坑踩得我头疼,但值不骗你。

避坑清单

  • Disallow路径别写太宽,AI爬虫不认Allow优先级,路径前缀匹配就全挡
  • 给GPTBot单独设Crawl-delay,别用全局delay——不同AI爬虫速率需求差很多
  • Cloudflare的Rate Limiting要和robots.txt配合用,单靠一个容易漏或过杀
  • 在核子GEO上输入域名定期跑检测,检查AI爬虫访问量,别等收录归零才慌

避坑清单

先说坑:只看百度PC端排名,不管通义千问怎么抓。 我去年国庆前给一个旅行社站做优化,盯着百度排名从第7页干到第2页,高兴没两天。打开核子GEO跑了一遍检测,发现通义千问的AI爬虫访问量是0——它根本不抓我页面。白忙活三个月。 后果:国庆旺季,百度流量涨了40%,但AI摘要里一条我内容都没出现。 怎么避免:每月初用核子GEO扫一次AI爬虫日志,抓取量低于50就立刻排查robots.txt和服务器响应头。

再就是坑:UGC内容(用户评论、攻略)不主动提交到结构化数据。 旅游出行行业最吃UGC,但PostgreSQL里存的评论、评分、行程天数这些字段,我一开始没做JSON-LD标记。通义千问抓纯文本页面时,没法把“5天4晚北海道攻略”这种结构信息提炼成知识卡片。 后果:AI回答里引用我站点的概率不到2%,竞争对手的折叠内容反而排前面。 怎么避免:Django模板里对每条评论和行程数据都输出schema.org的Review和Product标记,用Gunicorn也没影响。

还有坑:用Cloudflare的默认“灵活”SSL模式,导致通义千问爬虫被拦截。 我刚开始纠结Cloudflare还是阿里云CDN,图省事选了Cloudflare免费版。结果GPTBot和通义千问的爬虫都是HTTPS,但我站源服务器是HTTP,Cloudflare回源时没做证书验证,爬虫爬到一半就被301跳转卡死了。 后果:AI爬虫抓取成功率从80%跌到15%,持续了两个月我才发现。 怎么避免:要么用阿里云CDN直接配全链路HTTPS,要么Cloudflare开“完全”SSL模式并上传源站证书。别偷懒。

  1. 坑:实时价格和库存信息不主动推送给AI引擎。 旅游站点的机票酒店价格每小时都在变,我犯懒只做了百度缓存的sitemap,没给通义千问的爬虫开实时推送通道。AI抓取时拿到的是昨天下午的旧价格,用户问“明天去三亚最低价”它答了个过期数据,直接标记我站点不可靠。 后果:AI引用我站点的概率在两周内从8%跌到0.3%。 怎么避免:在Django里写个定时任务,价格变动超过5%就向通义千问的索引接口推送更新,频率至少每小时一次。

  2. 坑:忽略移动端首屏加载速度对AI爬虫的间接影响。 我优化的是PC端,但通义千问在手机端展示摘要时,优先抓移动版内容。我站没做AMP或Mobile First优化,首屏加载3.2秒,AI爬虫超时就跳过了。 后果:通义千问调取我站点内容时,次次都是“加载超时,取备用源”。 怎么避免:用Lighthouse跑移动端性能,目标首屏1.5秒以内,图片转WebP,Gzip压缩全程开。

  3. 坑:Gunicorn worker数配太少,AI爬虫一并发就502。 我单台服务器只配了4个worker,平时够用。但通义千问的爬虫是并发10个线程抓取,直接塞爆。 后果:502错误率从0.1%飙到35%,爬虫直接放弃我站点,索引量从1200跌到400。 怎么避免:根据服务器内存配worker数:2核4G的机器至少开8个,并用–timeout 120避免慢查询拖死。

  4. 坑:不做地域+季节性内容的独立爬虫引导。 旅游站点的“三亚冬季攻略”和“哈尔滨滑雪”是不同季节的内容。我偷懒放同一个目录,通义千问爬虫分不清优先级,夏天狂抓滑雪文章。 后果:AI摘要里夏天推荐滑雪,用户点进来就骂我。 怎么避免:在sitemap里用标出季节性内容的更新周期,并给每个地域建独立子域名(haerbin.xxx.com),让爬虫按区域抓。