返回技术文章
JavaScript 渲染SSRAI 爬虫可抓取性技术 SEOGEO

AI 爬虫不执行 JavaScript:静态 HTML 可读性的技术验收清单

Vercel 与 MERJ 的日志研究显示 GPTBot、ClaudeBot、PerplexityBot 都不渲染 JavaScript,而我们的检测数据里 16% 的网站关掉脚本后没有正文。本文给出四种渲染模式的验收矩阵、一套差分自检命令和修复优先级。

妙蛙 GEO 研究团队15 分钟

一句话结论:Google 会排队渲染你的 JavaScript,主流 AI 爬虫不会。Vercel 与 MERJ 对数亿次抓取的日志分析确认,OpenAI、Anthropic、Perplexity 的爬虫都只读原始 HTML;我们免费检测工具的聚合数据里,16% 的网站关掉脚本后读不到正文。一个页面可以在 Google 排第一,同时对 ChatGPT 是一个空壳。验收方法不是"打开浏览器看一眼",而是拿不执行脚本的抓取结果和浏览器渲染结果做差分。

四种渲染模式下,不执行 JavaScript 的抓取器各自能读到什么:SSR 与 SSG 完整,流式 SSR 取决于服务端是否完成,CSR 只有空壳
四种渲染模式下,不执行 JavaScript 的抓取器各自能读到什么:SSR 与 SSG 完整,流式 SSR 取决于服务端是否完成,CSR 只有空壳

一、三类读者,三种能力

讨论"AI 能不能读到我的页面"之前,先把读者分成三类,因为它们的能力完全不同。

第一类是搜索引擎的渲染器。 Google Search Central 的 JavaScript SEO 基础文档(2026 年 3 月更新)把处理分成抓取、渲染、索引三个阶段:Googlebot 先处理 HTTP 响应里的 HTML,再把返回 200 的页面放进渲染队列,"页面可能在队列里停留几秒,但也可能更久",资源允许时由常青版 Chromium 执行脚本。也就是说 Google 能看到 JS 渲染后的内容,只是有延迟、有队列、有预算。

第二类是 AI 厂商的抓取器。 Vercel 与 MERJ 在 2024 年 12 月发布的日志研究覆盖了 Vercel 网络上一个月的抓取:GPTBot 5.69 亿次、Claude 3.70 亿次、AppleBot 3.14 亿次、PerplexityBot 2,440 万次。结论是"目前没有任何主流 AI 爬虫渲染 JavaScript",覆盖 OpenAI、Anthropic、Meta、ByteDance 与 Perplexity;只有 Google 的 Gemini 与 AppleBot 借助浏览器基础设施执行脚本。一个容易误读的细节:ChatGPT 的抓取中 11.50% 是 JS 文件、Claude 是 23.84%,它们会下载脚本,但当作文本读,不执行。OpenAI 自己的爬虫文档区分了 GPTBot、OAI-SearchBot 与 ChatGPT-User 三个身份,没有一处宣称会执行脚本。

第三类是 agent 浏览器。 ChatGPT agent、Atlas 这类产品在真实浏览器里操作页面,能看到渲染后的结果;但它们服务的是"替用户完成任务",不是"决定引用谁"。引用决策发生在第二类读者的检索阶段,这一点《AI 的引用决策发生在检索阶段:RAG 六环节完整拆解》已经讲过。

这三类读者对应三种验收标准。SEO 团队习惯用 Google 的标准,而 GEO 要按第二类的标准来:初始 HTML 里没有的内容,对 AI 检索就是不存在的。

Google 自己在 2025 年 12 月更新的"AI 功能与你的网站"文档里也把这条写成了要求——"确保重要内容以文本形式可用",并明确不需要任何额外的机器可读文件或标记。见《Google 2026 生成式 AI 搜索指南:没有特殊 Schema,真正该修的是哪六层》

二、我们的数据:16% 的站关掉脚本后没有正文

妙蛙 GEO 的免费检测工具有一项"静态可读性"检查:不执行 JavaScript 抓取页面,整块剥掉 script、style、noscript 与注释,再去标签、解实体、压空白,数剩下多少字符。阈值是 500 字符以上通过、200 到 499 告警、200 以下不合格。剥离顺序很重要——先去标签再剥脚本,脚本里的一个大 JSON 就能让空壳站看起来内容充足。

《86 个网站来测了 AI 可见度:近一半在配置 AI 不看的东西,三分之二栽在 AI 真正读的地方》公开的聚合数据里,这一项的结果是:

检查项分母不合格比例
关闭 JavaScript 后无正文68 站1116%
对 AI 爬虫 UA 与浏览器返回不同内容48 站612.5%
位于 WAF / CDN 之后57 站2340%

16% 是全部检查项里后果最重的一项:读不到,后面所有优化都不存在。12.5% 的 UA 差分说明另一件事——有些站不是"没有静态内容",而是对 AI 爬虫返回了拦截页或空响应,这属于访问层问题,处理方法见《AI 爬虫治理实战:Cloudflare 9 月 15 日新默认规则生效前,出海企业必须做的 7 件事》

样本来自主动使用检测工具的网站,偏向已经关心 AI 可见度的一群人;真实互联网的比例大概率更高,不会更低。

三、CSR 站点在 ChatGPT 免费档吃两次亏

《免费版 ChatGPT 根本没打开你的网页:1,200 个回答的检索栈解剖,和它推翻的四条 GEO 常识》引用的 RESONEO 研究显示,在捕获的即时模式回答中,93% 一个页面都没有打开,模型看到的只是搜索索引里的标题和 H1 之后约 200 个字符的摘要。

把这条和"不渲染 JS"放在一起,客户端渲染的站点会连吃两次亏:

  1. 索引层:给 ChatGPT 检索供数的索引如果没有渲染你的页面,标题之外的摘要就是空的,或者是"请启用 JavaScript"。
  2. 打开层:即使模型决定打开页面,OAI-SearchBot 与 ChatGPT-User 读到的仍是初始 HTML——正文如果在脚本里,打开也是白开。

所以标题、H1 和紧随其后的第一段,是必须出现在初始 HTML 里的最小集合。这不是性能优化建议,是资格问题。

四、四种渲染模式的验收矩阵

不要按框架名判断,按"初始 HTML 响应里有没有内容"判断。同一个 Next.js 或 Nuxt 项目里,四种模式可能同时存在。

模式初始 HTML 里有什么不执行脚本的抓取器读到常见陷阱
SSR(服务端渲染)完整正文完整服务端出错时回落到客户端渲染,抓取器拿到空壳
SSG / ISR(构建期生成)完整正文完整重新验证失败后长期提供旧版本
流式 SSR(Streaming)分块到达的正文服务端完成时完整抓取器读到的是"响应结束时"的 HTML,服务端超时的 Suspense 区块会缺失
CSR(客户端渲染)空容器与脚本只有 title 与壳一切内容都在 API 响应里

四种之外还有"混合污染",它们让本来 SSR 的页面在关键位置退化成 CSR:

  • 挂载后再取数:正文骨架是服务端的,但价格、库存、参数表在 useEffect 或 onMounted 里请求。
  • 懒挂载的 Tab 与手风琴:只有默认展开的面板进了 HTML,其余面板的内容在切换时才渲染。
  • "展开全文"与无限滚动:第一屏之外的内容不在 HTML 里,也没有分页 URL。
  • 同意墙与地区跳转:脚本在拿到同意或判定地区之前不渲染正文,抓取器永远停在弹窗那一步。
  • JS 制造的软 404:页面不存在时服务端仍返回 200,由脚本显示"未找到"。Google 文档明确要求"使用有意义的状态码,比如找不到页面时返回 404";不执行脚本的抓取器只看得到那个 200 和空壳。
  • 脚本注入的 canonical、noindex、JSON-LD:这些标签如果由客户端脚本插入,第二类读者一个都看不到。

AI 抓取器在坏链接与跳转上的容错也远比 Googlebot 差。同一份 Vercel 研究里,ChatGPT 34.82% 的抓取落在 404 页面、14.36% 跟随了重定向,Googlebot 分别只有 8.22% 与 1.49%。一个靠 JS 跳转或靠 JS 显示"未找到"的站,会把这两个比例进一步推高。

静态可读性差分自检的三步:用爬虫 UA 抓取初始 HTML,剥离脚本后计数,与浏览器渲染文本比对
静态可读性差分自检的三步:用爬虫 UA 抓取初始 HTML,剥离脚本后计数,与浏览器渲染文本比对

五、差分自检:三份文本,一次比对

验收不是"我在浏览器里看到了"。下面这套流程用两个不执行脚本的抓取和一个浏览器结果做比对,二十分钟能跑完一批关键页面。

第一步,用爬虫身份抓初始 HTML。 分别用普通浏览器、OAI-SearchBot 与 GPTBot 的 User-Agent 各抓一次,保留状态码、体积和响应体:

UA_BROWSER="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
UA_OAI="Mozilla/5.0 (compatible; OAI-SearchBot/1.0; +https://openai.com/searchbot)"
UA_GPTBOT="Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.2; +https://openai.com/gptbot"
URL="https://example.com/products/x"

curl -sS --compressed -A "$UA_BROWSER" -o /tmp/browser.html -w "browser %{http_code} %{size_download}\n" "$URL"
curl -sS --compressed -A "$UA_OAI"     -o /tmp/oai.html     -w "oai-searchbot %{http_code} %{size_download}\n" "$URL"
curl -sS --compressed -A "$UA_GPTBOT"  -o /tmp/gptbot.html  -w "gptbot %{http_code} %{size_download}\n" "$URL"

三次的状态码与体积应当接近。体积差一个数量级,或者爬虫 UA 拿到 403、503、验证页,就是访问层问题,先修那一层。

第二步,剥离脚本后计数。 用与检测工具相同的顺序处理:先整块剥脚本与样式,再去标签。

node -e '
const html = require("fs").readFileSync(process.argv[1], "utf8");
const text = html
  .replace(/<script[\s\S]*?<\/script>/gi, " ")
  .replace(/<style[\s\S]*?<\/style>/gi, " ")
  .replace(/<noscript[\s\S]*?<\/noscript>/gi, " ")
  .replace(/<!--[\s\S]*?-->/g, " ")
  .replace(/<[^>]+>/g, " ")
  .replace(/&[a-z#0-9]+;/gi, " ")
  .replace(/\s+/g, " ")
  .trim();
console.log(text.length);
' /tmp/oai.html

低于 500 字符,按我们的口径就是不合格。更严格的做法是在这份文本里直接搜索三样东西:页面标题里的核心词、H1 之后的第一句、最重要的一个数字(价格、参数、认证编号)。搜不到,就说明它们在脚本里。

第三步,与浏览器文本比对。 在浏览器控制台取 document.body.innerText.length,与第二步的数字放在一起。差距在两倍以内通常是导航、页脚等结构差异;差距达到五倍以上,几乎必然有整块内容在脚本里。把差异定位到具体区块,比总量更有用——通常就是参数表、价格、FAQ 这些恰好最值得被引用的部分。

顺手核对四个标签。 在第一步的原始 HTML 里搜索 <title><h1rel="canonical"application/ld+json。它们必须出现在初始响应里,出现在渲染后的 DOM 里不算数。

六、修法的优先级

按"资格优先"排序,而不是按工作量。

  1. 内容路由改为服务端输出。 文章、产品、分类、FAQ 页面全部 SSR 或 SSG。交互组件(筛选器、计算器、聊天)保留客户端渲染,但它们不承载事实。
  2. 把最小集合钉死在初始 HTML。 标题、H1、首段、核心参数表、JSON-LD、canonical。做一条渲染合约测试,构建后用不执行脚本的 fetch 断言这些元素存在——我们自己站点的做法见《TechArticle 结构化数据工程:图片、日期、作者与面包屑怎样保持同源》
  3. 消灭挂载后取数。 价格与库存如果必须实时,把服务端渲染的最近值放进 HTML,客户端再刷新;抓取器至少拿到一个带时间标记的值,而不是空白。
  4. 给懒挂载内容一个 HTML 落点。 Tab 面板全部渲染进 HTML 再用脚本控制显示;无限滚动配分页 URL。
  5. 同意墙不得遮蔽正文。 弹窗覆盖在内容之上,而不是替代内容渲染。
  6. 服务端状态码。 不存在的路径返回真实 404;重定向由服务端发 301 或 308,不用 JS 或 meta refresh。
  7. 老 SPA 用预渲染过渡。 无法短期改架构的站点,先为产品页、服务页、高流量文章做预渲染,让抓取器拿到静态快照;这只是过渡,快照与真实页面漂移是新的维护负担。
静态可读性验收清单:初始 HTML 含最小集合、无脚本文本超过 500 字符、UA 差分一致、服务端状态码、懒内容有落点、构建后自动断言
静态可读性验收清单:初始 HTML 含最小集合、无脚本文本超过 500 字符、UA 差分一致、服务端状态码、懒内容有落点、构建后自动断言

七、发布前的验收清单

  • 关键页面用爬虫 UA 抓取,状态码 200,体积与浏览器 UA 一致;
  • 剥离脚本后的可见文本不少于 500 字符,且能搜到标题核心词、首段与最重要的数字;
  • <title><h1>、canonical、JSON-LD 出现在初始 HTML;
  • 不存在的路径返回真实 404,重定向为服务端 301 或 308;
  • Tab、手风琴、折叠区的内容在 HTML 里,无限滚动有分页 URL;
  • 同意弹窗不阻断正文渲染;
  • 构建流程里有一条不执行脚本的渲染断言,改坏时能挡下发布;
  • 服务器日志里能看到 OAI-SearchBot、ClaudeBot、PerplexityBot 拿到 200,核验方法见《服务器日志取证:用 AI 爬虫 UA 证明你的页面被抓取和检索(2026 完整版)》

边界声明

  • Vercel 与 MERJ 的数据采集于 2024 年末的 Vercel 网络与 nextjs.org,反映当时的爬虫行为;本文写作时没有任何 AI 厂商公开宣布其抓取器开始执行 JavaScript,但这类行为可能在不通知的情况下改变,验收应当定期重跑。
  • 静态可读性是资格条件,不是引用保证。通过验收只说明"AI 能读到",不说明"AI 会引用"。
  • 我们的 86 站样本来自主动使用检测工具的网站,不代表全网分布。
  • Google 能渲染 JavaScript,因此一个 CSR 站点在 Google 自然排名上可能完全正常;本文讨论的是 AI 检索侧的可读性,两者不能互相推断。
  • 命令示例用于自检,正则处理 HTML 有边界情况,结论以人工核对为准。

本文事实资料来自 Google Search Central(JavaScript SEO 基础、AI 功能与你的网站)、Vercel 与 MERJ 的 AI 爬虫日志研究、OpenAI 爬虫文档、RESONEO 的 ChatGPT 检索栈研究,以及妙蛙 GEO 免费检测工具的聚合数据。

本文由妙蛙 GEO 研究团队撰写,使用 AI 辅助进行资料整理与语言校对,文中事实、来源和结论均经人工复核。

继续阅读

相关技术文章

可访问性树可访问性树是 AI agent 读网页的真实视图:语义化 HTML 的工程验收

我们检测过的网站里 64% 的可访问性树不合格,而 OpenAI 明确说 Atlas 用 ARIA 角色与标签理解页面,Google 也发布了 agent 友好网站指南。本文说明可访问性树是什么、什么会把它弄坏、怎样用 DevTools 与 Playwright 验收,以及它和 AI 引用的边界。

AI 爬虫AI 爬虫治理实战:Cloudflare 9 月 15 日新默认规则生效前,出海企业必须做的 7 件事

Cloudflare 自 2026 年 9 月 15 日起把 AI 爬虫拆成 Search / Agent / Training 三类并启用新默认策略,混用爬虫按最严规则处理。含 7 步自查清单、可直接复制的 robots.txt 模板与验证命令。

GEO 方法论如何让 ChatGPT 在回答中主动提到你的品牌

ChatGPT 的品牌提及率仅 0.59%,是所有主流 AI 中最难攻的平台。本文说明它的信源结构、为什么品牌词策略在这里行不通,以及中小企业唯一现实的切入路径。