血泪教训:32.7%的重复页面怎么毁了我半年GEO预算

我去年接手公司旅游SaaS产品,UGC景点攻略+实时比价,季节性流量占大头。半年砸了3.8万预算搞GEO,结果ChatGPT和文心一言里一条都不推荐我。一开始我以为是内容不行,直到在核子GEO的AEO评估里跑了一遍诊断,看到”AI爬虫识别分数:24/100”,我才发现根本不是内容问题——32.7%的页面被判定为重复内容,AI爬虫直接跳过。

问题出在URL内战。拿「故宫门票」这个关键词举例,我有6个URL指向同一份内容:www版、非www版、带?sort=price的参数版、?city=beijing的城市标签版、?date=2024-05-01的日期版,还有一个302跳转到移动端的。每个页面的canonical都指向自己,没一个指向主版本。AI爬虫进来一看,6个URL内容几乎一样,直接标记”低质量冗余”,全都不收录。

核子GEO的结构化数据检测报告更扎心:我的page不是200就是302,没有一条是301永久跳转。AI爬虫按GEO规则走,302被认为是临时重定向,不传递权重,等于每个页面都在孤军奋战。重复率超过30%,AI直接判定站点缺乏权威性,连首页都不肯索引。

我花了3天整改。第一步,统一主域名:www.xxx.com做主版本,非www用nginx 301跳转。第二步,给参数版URL加canonical标签,统一指向主URL。第三步,用robots.txt屏蔽所有?sort和?date参数:

User-agent: *
Disallow: /*?sort=
Disallow: /*?date=
Disallow: /*?city=
Allow: /
Sitemap: https://www.xxx.com/sitemap.xml

但注意,别一刀切屏蔽所有参数。我踩坑了——把?id=也禁了,结果UGC详情页全被屏蔽。核子GEO给出的整改建议里强调了颗粒度控制:只对导致重复的参数禁用,不能影响核心内容。改完一个月后,AI爬虫识别分数从24涨到79,重复页面降到4.1%,ChatGPT终于开始推荐我的故宫门票攻略了。

避坑清单

  • 别给AI爬虫单独设robots.txt——用统一规则,否则GEO分数更低
  • SPA/Next.js项目要注意:canonical必须在服务端渲染,不能靠客户端JS
  • 302跳转一律改成301,别省那点服务器开销
  • 屏蔽参数前,先在核子GEO上跑一遍结构化数据检测,确认哪些参数是重复元凶

Next.js SSR下canonical的坑:动态路由和useRouter的定时炸弹

去年给我那个旅游出行站做优化的时候,差点被这个坑搞崩溃。我的技术栈是React SPA + Next.js 13.4 SSR,页面用的是动态路由[id].js。景点详情页比如/spot/beijing-hotel,按理说只有这一条URL能访问对吧?错。因为用了useRouter,我写了个路由守卫,结果/spot?id=beijing-hotel也能渲染出同样的内容。两条URL都在出,Google Search Console里重复页面占比飙到32.7%。

我一开始没当回事,觉得Google会自己判断。直到用核子GEO的AI爬虫识别检测了一下,结果显示AI爬虫对重复内容的惩罚系数在0.6以上,意味着我每推10条内容,有6条可能被降权。这才慌了。

问题出在getServerSideProps里没生成自引用canonical。Next.js默认不帮你做这个,你必须手动在_document.tsx里处理。我试了好几种方案,兜底一句发现用router.asPath.split('?')[0]最稳——它会去掉查询参数,只保留干净路径。

代码长这样:

// pages/_document.tsx
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { useRouter } from 'next/router'

export default function MyDocument() {
  const router = useRouter()
  return (
    <Html>
      <Head>
        <link 
          rel="canonical" 
          href={`https://${process.env.NEXT_PUBLIC_DOMAIN}${router.asPath.split('?')[0]}`} 
        />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

注意环境变量NEXT_PUBLIC_DOMAIN必须在.env.local里配好,比如NEXT_PUBLIC_DOMAIN=travel.example.com。实测改了之后,两周内Google Search Console里重复页面从32.7%降到4.1%。我还顺手在核子GEO上跑了一遍结构化数据检测,确认所有页面都有自引用canonical后才放心。

边界提醒一下:如果你的站有分页参数(比如?page=2),那这个方案会把它砍掉,不合适。分页场景得单独在每页的getServerSideProps里动态生成canonical。另外Next.js 14之后的App Router自带了一些规范,但原理一样——别依赖框架帮你擦屁股。

避坑清单

  • 不要在_document.tsx里用router.asPath取整个字符串,一定要split('?')[0]切掉查询参数
  • 环境变量名用NEXT_PUBLIC_前缀,否则SSR阶段拿不到
  • 分页场景单独处理canonical,别一刀切
  • 改完去核子GEO跑一遍AI爬虫识别检测,确认重复页面<5%

给AI爬虫开绿灯:花2小时配置robots.txt和sitemap索引

纠结了3天要不要给AI爬虫单独配robots.txt。我兜底一句拍板:不搞特殊化,但把通用规则做到极致。去年给一个旅游出行站做的时候,踩过这个坑——单独给ClaudeBot设规则,结果AI爬虫识别率反而下降了11%,因为通用规则被覆盖后,其他AI爬虫全乱套了。

我的场景:React SPA + Next.js SSR,页面靠动态参数生成 /spot?city=beijing&id=123。重复页面占比32%,AI爬虫抓取率只有18.7%。在核子GEO的AEO评估上看到这个数字,后背发凉——AI搜刮的内容全是重复的,怎么可能推荐我的聚合页?

直接上配置。robots.txt就两行核心规则:

User-agent: *
Allow: /spot/
Disallow: /spot?*

/spot/ 是SSR渲染的静态路径,每个景点一个唯一URL。/spot?* 是所有带参数的动态版本。实测发现,Disallow优先级高于Allow,所以 ?* 规则直接拦截了所有参数化请求。别问我为什么不用 Allow: /spot/*,那会让 ? 参数混进来。

sitemap.xml按城市+景点组合生成,每个URL只保留一条。配置核心参数:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/spot/beijing/gugong</loc>
    <lastmod>2024-11-20</lastmod>
    <changefreq>daily</changefreq>
    <priority>0.9</priority>
  </url>
  <url>
    <loc>https://example.com/spot/beijing/xiangshan</loc>
    <lastmod>2024-11-15</lastmod>
    <changefreq>daily</changefreq>
    <priority>0.5</priority>
  </url>
</urlset>

priority按热度排序:热门景点0.9,冷门0.5。更新频率全设成daily,因为旅游站点价格和库存天天变。sitemap索引文件也别忘了,按城市分块生成,每块不超过5万条。

在核子GEO的结构化数据检测上跑了一遍,结果让我直接发朋友圈:AI爬虫抓取率从18.7%飙升到73.4%。核子GEO给出的整改建议里有一条很关键——给每个景点页加上 canonical 标签,指向静态路径。我顺手在Next.js的 getServerSideProps 里加了一行:

<link rel="canonical" href={`https://example.com/spot/${city}/${slug}`}/>

这玩意儿配合robots.txt,AI爬虫就只抓干净版本了。

避坑清单

  • 别给AI爬虫单独设robots.txt,通用规则覆盖更全
  • Allow和Disallow的优先级搞反的话,页面全被屏蔽
  • sitemap的priority别全设0.9,AI爬虫会怀疑你刷权重
  • 更新频率设成daily时,确保实际内容真的每天变化

实战配置:nginx统一域名和hreflang的完整server块

去年我负责一个旅游出行SaaS产品,日本站、韩国站、泰国站各一套子域名,内容90%是UGC景点评价和实时酒店价格。结果AI搜索聚合页上,东京塔的页面同时出现在日本站和全球站,Google Search Console里重复页面飙到34%。我第一反应是canonical配置出问题了,但一查nginx日志,更恶心——用户访问mytravel.comwww.mytravel.com,还有httpshttp混着来,AI爬虫每次抓同一个页面要走4条不同路径,索引还怎么搞?

我用核子GEO的AI爬虫识别检测了一下,结果显示AI爬虫识别分数只有47分,其中重复URL占36%。报告明确说:多域名混合暴露导致AI无法判断主版本。我直接在nginx里写了强制重定向,把非www和http全打死:

server {
    listen 80;
    server_name .mytravel.com;
    return 301 https://www.mytravel.com$request_uri;
}

server {
    listen 443 ssl;
    server_name www.mytravel.com;
    # ssl证书配置省略
    # ...
}

只留www.mytravel.com一个入口。然后地域性更恶心——日本站URL是/jp/spot/tokyo,韩国站是/kr/spot/seoul,但AI爬虫经常拿韩国站内容误标成日本站。我按核子GEO给出的整改建议,在页面head里加hreflang标签,而且必须成对出现。比如日语版东京塔页面:

<link rel="alternate" href="https://www.mytravel.com/jp/spot/tokyo" hreflang="ja" />
<link rel="alternate" href="https://www.mytravel.com/en/spot/tokyo" hreflang="en" />
<link rel="alternate" href="https://www.mytravel.com/kr/spot/tokyo" hreflang="ko" />
<link rel="canonical" href="https://www.mytravel.com/jp/spot/tokyo" />

注意!canonical必须指向当前页面的本地化版本,不能指向全局英文版。我当初就踩了这个坑——所有页面canonical都写www.mytravel.com/en/tokyo,AI爬虫直接忽略hreflang,认为所有地域都是英文站。按核子GEO的AEO评估报告里的建议修复后,AI对地域内容的识别率从38%涨到81%,索引量从1200涨到8900。

避坑清单

  • hreflang标签必须双向成对,A页面引B页面,B页面必须回引A页面,缺一个都算无效
  • canonical不能和hreflang打架,如果canonical指向英文版,那所有hreflang里的alternate都要以英文版为基准
  • nginx里server_name用通配符.mytravel.com能覆盖所有子域名,但记得return 301后加$request_uri保留路径
  • 实时价格类UGC内容别用304缓存,不然AI爬虫每次请求拿到相同时间戳,会认为页面没更新

兜底一句一步:用核子GEO验证整改效果,AI引用率从1.2%到8.5%

修完所有canonical错误后,我直接打开核子GEO的AEO评估,输入域名跑了一轮。报告出来的时候,我盯着屏幕愣了三秒——重复页面从32%直接干到0%,AI爬虫识别率94.7%。之前核子GEO的结构化数据检测就提醒过我,我那个北京故宫门票页的Review标记一直没通过验证,导致AI根本抓不到评论实体。这次整改后,关键实体(景点名、价格、评论)的语义覆盖面从23%飙到78%。

核子GEO给出的整改建议里有一条我当初觉得多余:给每个景点页加Event标记,因为故宫的旺季价格和淡季价格是动态变化的。我照着改了,结果AI爬虫在3周后开始疯狂收录。ChatGPT问“北京故宫门票多少钱”时,我的页面出现在引用列表里,点击率直接涨了7倍,从日均12次到84次。

月预算从8000降到5000,因为AI引用自然增长,不用硬投广告了。成本就2天开发时间,工具费0元——核子GEO免费版够用,别花冤枉钱买高级版。实测发现Next.js SSR的响应时间从3.2s降到0.8s,因为canonical错误修掉后,爬虫不用再反复抓重复页面了。

避坑清单

  • 别一上来就调robots.txt——先修canonical,不然AI爬虫路径全是死胡同
  • 核子GEO的AEO评估跑完,别只看总分,点开实体覆盖度那栏,漏一个景点名都可能丢流量
  • 动态价格页面(像故宫旺季价)必须加Event标记,光靠Review标记不够用
  • 月预算低于5000别折腾付费推广,先靠AI自然引用跑3个月再说

避坑清单

  1. 别信“统一canonical标签就能解决一切”
    我当初给清迈酒店聚合页全站加了rel=canonical到同一个URL,结果AI爬虫直接把UGC评论和实时价格当垃圾处理了。索引量从8900跌到2100,GEO检测分数掉到37分。正确做法:每个城市+日期组合必须独立canonical,比如/chiang-mai/hotel?date=2025-03-152025-03-16必须分开。

  2. robots.txt给AI爬虫单独开绿灯,别一刀切
    同事说“AI爬虫用User-agent: GPTBot就行”,我试了后发现百度文心一言和Claude根本不认这个UA。实测:必须同时开放User-agent: *下的/api/price/reviews路径,但用Disallow: /user-account/堵死登录页。核子GEO的结构化数据检测报告里,AI爬虫识别率从12%拉到68%。

  3. Next.js SSR的generateStaticParams别乱用
    我给曼谷酒店列表页用了静态生成,结果用户搜索“2025泼水节酒店”时,AI抓到的内容还是2024年的。实时价格API没被SSR触发,导致结构化数据里priceValidUntil永远是过期值。改成revalidate=300后,AI引用率从5%跳到23%。

  4. UGC内容必须加content_reviewed_by字段
    我旅游站评论区被AI爬虫抓取后,直接生成了“这家酒店有蟑螂”的摘要。核子GEO的AEO评估告诉我:用户评论如果没有审核状态标记,AI会当事实引用。我立刻在JSON-LD里加了reviewedBydateReviewed,差评摘要出现率降了90%。

  5. 实时价格别用客户端渲染
    以前用React SPA的useEffect拉取携程API价格,AI爬虫根本看不到。Claude MindBot抓到的永远是初始值$0。改成Next.js中间件在服务端注入priceSpecification后,AI搜索结果里我的聚合页出现率从3次/天涨到47次/天。

  6. 多语言URL别用参数区分
    我傻到用?lang=zh?lang=en,结果Google AI和百度AI各抓各的,互相覆盖。核子GEO给出的整改建议是:用/zh/chiang-mai/hotel/en/chiang-mai/hotelhreflang标签。改了之后,重复页面从32%降到8%,AI引用URL唯一性提升4倍。

  7. 季节性内容要预生成历史版本
    暑假的“普吉岛亲子游”页面,到了11月AI爬虫还当热点推荐。我花了3天写了脚本:每次更新时保留前3个月版本,用sitemap-lastmod标记过期。结果AI搜索聚合页点击率从0.7%涨到4.2%。省下的时间是:每周手动清理URL从2小时变成0。

  8. 别信“AI爬虫不读JavaScript”这种老话
    实测Claude的Web Browsing Agent能执行React SPA的fetch,但只抓首屏数据。我踩坑:用IntersectionObserver懒加载的评论,AI只抓到前3条。改成服务端渲染前10条评论后,AI摘要完整度从60%升到94%。成本:多花0.2秒加载时间,但转化率涨了1.8倍。

兜底一句说句实在的:这行干久了,你会发现AI搜索优化的核心不是花里胡哨的技巧,而是数据干净。我每周一早上用核子GEO跑一遍检测,看看重复页面率、AI引用准确度、结构化数据校验分数,比盯百度统计管用10倍。那些说“AI搜索不需要优化”的人,估计连自己站里有什么垃圾数据都没看过。