单页应用 AI 爬虫抓取失败:客户端渲染、链接与正文暴露验收指南

单页应用 AI 爬虫抓取对照:原始 HTML 空壳与渲染后正文的字数差异示意

网站从多页架构重构成单页应用(SPA)后,单页应用 AI 爬虫抓取失败是最常见也最隐蔽的翻车点:页面在浏览器里显示正常,GPTBot、豆包、Kimi 这类 AI 爬虫却只拿到一个几乎空白的 HTML 空壳。正文、链接、结构化数据全由 JavaScript 在客户端二次生成,而主流 AI 爬虫不执行 JavaScript——它们看到的和用户看到的,是两个网站。

本文给出可落地的验收流程:先讲清哪些爬虫渲染、哪些不渲染,再用一套三层暴露对照法比对原始源码、渲染后 DOM 与各爬虫实际所见,接着给出链接发现与正文暴露的通过阈值、常见框架的修复对照,以及上线回归监测清单。如果你正在或即将做前端重构,建议配合从 robots.txt、WAF 到渲染与日志逐层排查的 AI 爬虫抓取诊断指南一起跑一遍。

单页应用 AI 爬虫抓取对照:原始 HTML 空壳与渲染后正文的字数差异示意

为什么单页应用改版后 AI 爬虫抓不到正文?

根因是客户端渲染(CSR):SPA 首个请求只返回一个空的 HTML 骨架,正文要等浏览器下载并执行 JavaScript 后才注入 DOM。 用户浏览器会执行这段 JS,所以看得到;但多数 AI 爬虫拿到首个 HTML 响应就直接解析、抽取、离开,不等渲染。

结果是一种“薛定谔的正文”:在 Chrome 的 Elements 面板能看到完整文章,用“查看网页源代码”(view-source)却几乎是空的。AI 爬虫看到的是后者。 这就是改版上线后,品牌在 AI 答案里的提及和引用突然掉线的原因——内容没删,只是从爬虫视角“隐身”了。

哪些 AI 爬虫会执行 JavaScript,哪些不会?

结论先行:除 Googlebot 外,主流 AI 爬虫目前基本都不渲染 JavaScript。Vercel 对其网络上 AI 爬虫抓取行为的分析,一个月内 GPTBot 抓取约 5.69 亿次、ClaudeBot 约 3.70 亿次、PerplexityBot 约 2440 万次,没有一个执行 JavaScript。它们会下载 JS 文件(GPTBot 约 11.5%、ClaudeBot 约 23.84% 的请求),但只当文本抓取,不运行。

爬虫 / 平台 归属 执行 JavaScript 客户端渲染正文可见性
GPTBot OpenAI(训练) 不可见
OAI-SearchBot / ChatGPT-User OpenAI(搜索/实时) 不可见
ClaudeBot Anthropic 不可见
PerplexityBot Perplexity 不可见
Googlebot Google 是(常青版 Chromium) 可见(渲染后)
Bingbot Microsoft 部分渲染 部分可见
DeepSeek / 豆包 / Kimi / 通义千问 各自爬虫 + 搜索后端 基本不执行 多不可见,依赖底层索引

有一个例外要说清:Googlebot 自 2019 年起用常青版 Chromium 渲染 JavaScript,纯 CSR 内容仍可能进入 Google 索引,进而出现在 Google AI Overviews。但这是唯一的大厂例外;Anthropic 的 web fetch 工具文档也说明,它读取的是页面返回的原始内容、不执行客户端渲染。押注“Google 看得到”,并不能让 ChatGPT、Claude、Perplexity 及国产平台看到。

国产 AI 平台(DeepSeek、豆包、Kimi、通义千问)怎么取内容?

国产平台普遍走 RAG + 联网搜索:先用爬虫或搜索后端取回原始 HTML,再喂给模型生成答案。 公开的来源结构分析显示,各平台引用来源差异很大——豆包偏抖音、今日头条、搜狐、网易、知乎;DeepSeek 近期偏淘宝、百度百科、网易;Kimi 以搜狐等为主。

这对 SPA 是双重风险:这些平台自己的抓取拿不到 CSR 正文;它们依赖的搜索索引若也没收录你的渲染内容,你就彻底出局。

客户端渲染、服务端渲染、预渲染有什么区别?

核心区别在于“正文在哪一刻、哪一层生成”:只要正文出现在服务器返回的首个 HTML 响应里,AI 爬虫就能读到;只要它依赖浏览器执行 JS 才出现,就读不到。

渲染方案 正文所在位置 AI 爬虫可见 适用场景
客户端渲染 CSR JS 执行后的 DOM 后台/交互面板,不宜承载可引用内容
服务端渲染 SSR 首个 HTML 响应内 需要被 AI 引用的内容型页面
静态生成 SSG / 预渲染 构建时生成的 HTML 变动较少的文章、文档、落地页
动态渲染 Dynamic Rendering 按 UA 给爬虫单独预渲染 是(已不推荐) 仅作迁移过渡

Google Search Central 的 JavaScript SEO 基础文档已把动态渲染明确标注为“权宜之计(workaround)”,不再作为长期方案推荐,改荐 SSR、静态渲染或 hydration。新项目别再拿动态渲染当解法,直接上 SSR/SSG。 Vercel 的数据也补了一个利好:只要正文在首个 HTML 里(包括 SSR 注入的 JSON 或服务端组件输出),即便不是纯静态 HTML,AI 也能解析。

常见 SPA 框架怎么改到 AI 可见?

同一条原则落到不同框架,动作不一样:目标始终是让正文进入首个 HTML 响应。 下表按主流框架给出从“默认 CSR”到“AI 可见”的最短路径。

框架 默认渲染 让正文进首个 HTML 的做法
React(CRA / Vite SPA) 纯 CSR 迁移到 Next.js(SSR/SSG)或 Remix;轻量站可用 Vike / 预渲染
Vue(Vite SPA) 纯 CSR 迁移到 Nuxt,用 SSR 或 SSG 输出
Angular 纯 CSR 启用 Angular SSR(原 Angular Universal)+ hydration
Next.js 可 SSR 用服务端组件 / getServerSideProps / SSG;别用 dynamic(..., { ssr: false }) 包裹正文
Nuxt 默认 SSR 保持 ssr: true,勿设 ssr: false 退回 SPA
SvelteKit 默认 SSR 保持默认,勿对内容页全局关掉 ssr
Astro 默认静态 默认输出静态 HTML,正文天然可见;别把正文塞进 client:only 组件

关键提醒:用了 SSR 框架不等于自动安全。 Next.js 里一个 ssr: false 的动态导入、Nuxt 里一处 ssr: false、或把正文塞进仅客户端组件,都会让这块内容悄悄退回 CSR。框架只是给了你 SSR 的能力,是否真的输出到首个 HTML,仍要靠下面的三层对照法验收。

抓取暴露三层对照法:原始源码 vs 渲染后 DOM vs 爬虫所见

三层暴露对照法,是把同一个 URL 的三种“可见版本”并排比对,用差异定位正文到底丢在哪一层。 这是本文的核心验收框架,任何一次改版上线都应跑一遍。

  1. 第一层·原始源码curl -sL https://你的页面 取回首个 HTML,统计正文字数;或浏览器“查看网页源代码”。这就是 AI 爬虫默认拿到的内容。
  2. 第二层·渲染后 DOM:用无头浏览器(Playwright / Puppeteer)加载页面,读取 document.body.innerText这是用户和 Googlebot 看到的内容。
  3. 第三层·爬虫所见:带爬虫 UA 请求,如 curl -A "GPTBot/1.1 (+https://openai.com/gptbot)" https://你的页面,再核对服务器日志里这些 UA 实际取到的状态码与响应体,排除被 WAF 或 robots 拦截。

判读规则:第一层与第二层的正文字数差距越大,客户端渲染泄漏越严重。 理想状态是三层内容几乎一致——原始源码里就能搜到你的关键句、标题和结构化数据。

三层暴露对照法示意图:原始源码、渲染后 DOM、AI 爬虫所见的正文差异

单页应用的链接发现怎么验收?

光有正文还不够——SPA 常用 JavaScript 路由代替真实链接,AI 爬虫发现不了内页,整棵路由子树对 AI 隐身。 内容暴露和链接暴露是两件事,必须分开验收。

典型问题是把导航写成 <div onClick={() => router.push('/x')}> 而非 <a href="/x">。爬虫不执行 JS,就看不到这次跳转,也抓不到目标页。链接发现验收要点:

  • 关键路由必须是真实 <a href="/path">,不能只靠 onClick 或按钮触发。
  • 避免 hash 路由(#/path:URL 片段不被当作独立页面。
  • 无限滚动、“加载更多”之后的内容,要额外提供分页 <a href> 或写进 sitemap。
  • 提交 XML sitemap 列全可索引 URL,lastmod 与实际更新一致。

顺带提醒:把正文藏在登录墙、表单或点击展开之后,等于对 AI 爬虫二次隐身。 获客与可引用性之间怎么取舍,见内容放在登录墙和表单后 AI 还能不能读到

正文与内容暴露验收清单(含通过阈值)

下面这份清单可直接作为上线门禁:每项设“通过 / 不通过”,任一不通过即阻断发布。 阈值是我们在多次 SPA 迁移诊断中沉淀的经验值,供团队对齐验收口径。

  1. 正文一致性:原始源码正文字数 ÷ 渲染后正文字数 ≥ 95%
  2. 首屏关键信息(标题、定义、价格/参数、FAQ 答案)出现在 curl 原始 HTML 中。
  3. <title><h1>、meta description、JSON-LD 均在原始 HTML 内且唯一。
  4. 关键路由 ≥ 95% 为真实 <a href>,无 hash-only 路由。
  5. 爬虫 UA(GPTBot / ClaudeBot / PerplexityBot / Bingbot)请求返回 200 且含正文,未被 WAF、robots 或速率限制拦截。
  6. XML sitemap 覆盖全部可引用页面,lastmod 准确。
  7. 结构化数据字段与可见正文一致,不标页面上没有的信息。

改版前后对照:一个典型 SPA 迁移的诊断样例

用三层对照法拆解一个从 Vue 客户端渲染迁到服务端渲染的内容站,能直观看到差距。 下表数值取自我们在多次 SPA 迁移诊断中反复看到的量级,供你对照自查,非单一客户实测披露。

指标 改版后(纯 CSR) 修复(SSR)后
原始 HTML 正文字数 ≈ 120 字(空壳) ≈ 2,600 字
原始 HTML 内 <a href> 数量 4 180+
GPTBot UA 取到正文
可被发现的内页路由 1 240
结构化数据出现在原始 HTML

样例的启示很清楚:改版“看起来正常”和“AI 抓得到”是两码事。 纯 CSR 版本里,爬虫拿到的正文不足渲染后的 5%,可发现路由只剩首页一个;换 SSR 后,正文一致率和路由覆盖同时回到可用区间。决定 AI 可见度的,不是页面在浏览器里美不美,而是首个 HTML 响应里到底装了多少东西。

如果改版还要主动下线或合并部分旧页面,别直接删——先算清它们贡献了多少 AI 引用再决定跳转,参考删除或合并页面会不会丢 AI 引用

修好之后怎么做回归监测,防止下次上线又掉?

修好只是起点:懒加载组件、A/B 实验、CDN 规则或一次前端重构,都可能在下次发布时又把正文推回客户端。 回归监测要同时盯三层信号,形成闭环。

  • 上线门禁:把三层对照法写进 CI,正文一致率 < 95% 或关键路由缺失就直接 fail,不让合并。
  • 日志监控:持续观察 GPTBot、ClaudeBot、Bingbot 及国产爬虫 UA 的抓取量与状态码,异常 4xx/5xx 及时告警。
  • 平台侧结果监测:跟踪品牌在 DeepSeek、豆包、Kimi、通义千问的 AI 提及率、AI 搜索排名与 AI 引用来源是否随改版波动——这是最终验收,也是 MaxAEO 这类 AI 可见度监测平台的用武之地。当技术层都通过、AI 提及率却下滑,往往说明还有未覆盖的路由,或被索引延迟卡住。

把技术验收和结果监测接起来,才能把“改版掉引用”从事后救火变成上线前拦截。迁移期的完整动作清单,见网站改版怎么避免 AI 引用掉线的迁移清单

SPA 从客户端渲染迁移到服务端渲染前后,爬虫可见正文与可索引路由对比

常见问题

单页应用一定对 AI 爬虫不友好吗?
不是。问题出在客户端渲染,而不在 SPA 架构本身。用 SSR 或 SSG 把正文放进首个 HTML 响应,SPA 同样能被 AI 爬虫完整抓取。

只做了 Google 收录,为什么 ChatGPT、Kimi 还是引用不到?
因为 Googlebot 会渲染 JavaScript,而 GPTBot、ClaudeBot、PerplexityBot 等基本不渲染。Google 能看到你的 CSR 内容,不代表其他 AI 平台也能看到,两条抓取链路要分别验收。

用了 Next.js、Nuxt 这类框架就一定安全吗?
不一定。这些框架给了你 SSR 能力,但只要用 ssr: false、把正文放进仅客户端组件或 { ssr: false } 的动态导入,这块内容照样退回客户端渲染。是否真进了首个 HTML,仍要用三层对照法逐页验收。

动态渲染(给爬虫单独预渲染)现在还能用吗?
可作迁移期的过渡方案,但 Google 已将其标注为权宜之计并停止推荐,长期应迁到 SSR 或 SSG,避免维护两套渲染逻辑带来的一致性风险。

怎么快速自测正文是否暴露给了 AI 爬虫?
curl 取原始 HTML 统计正文字数,或在浏览器“查看网页源代码”里搜一句正文关键句。如果搜不到、字数远小于页面实际内容,就是客户端渲染泄漏。

修复后多久 AI 平台会重新收录?
取决于各平台的抓取与索引周期,通常数天到数周不等。建议持续监测 AI 提及率与引用来源,用结果确认恢复,而不是只看技术层是否通过。