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

一、三类读者,三种能力
讨论"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 站 | 11 | 16% |
| 对 AI 爬虫 UA 与浏览器返回不同内容 | 48 站 | 6 | 12.5% |
| 位于 WAF / CDN 之后 | 57 站 | 23 | 40% |
16% 是全部检查项里后果最重的一项:读不到,后面所有优化都不存在。12.5% 的 UA 差分说明另一件事——有些站不是"没有静态内容",而是对 AI 爬虫返回了拦截页或空响应,这属于访问层问题,处理方法见《AI 爬虫治理实战:Cloudflare 9 月 15 日新默认规则生效前,出海企业必须做的 7 件事》。
样本来自主动使用检测工具的网站,偏向已经关心 AI 可见度的一群人;真实互联网的比例大概率更高,不会更低。
三、CSR 站点在 ChatGPT 免费档吃两次亏
《免费版 ChatGPT 根本没打开你的网页:1,200 个回答的检索栈解剖,和它推翻的四条 GEO 常识》引用的 RESONEO 研究显示,在捕获的即时模式回答中,93% 一个页面都没有打开,模型看到的只是搜索索引里的标题和 H1 之后约 200 个字符的摘要。
把这条和"不渲染 JS"放在一起,客户端渲染的站点会连吃两次亏:
- 索引层:给 ChatGPT 检索供数的索引如果没有渲染你的页面,标题之外的摘要就是空的,或者是"请启用 JavaScript"。
- 打开层:即使模型决定打开页面,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 显示"未找到"的站,会把这两个比例进一步推高。

五、差分自检:三份文本,一次比对
验收不是"我在浏览器里看到了"。下面这套流程用两个不执行脚本的抓取和一个浏览器结果做比对,二十分钟能跑完一批关键页面。
第一步,用爬虫身份抓初始 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>、<h1、rel="canonical"、application/ld+json。它们必须出现在初始响应里,出现在渲染后的 DOM 里不算数。
六、修法的优先级
按"资格优先"排序,而不是按工作量。
- 内容路由改为服务端输出。 文章、产品、分类、FAQ 页面全部 SSR 或 SSG。交互组件(筛选器、计算器、聊天)保留客户端渲染,但它们不承载事实。
- 把最小集合钉死在初始 HTML。 标题、H1、首段、核心参数表、JSON-LD、canonical。做一条渲染合约测试,构建后用不执行脚本的 fetch 断言这些元素存在——我们自己站点的做法见《TechArticle 结构化数据工程:图片、日期、作者与面包屑怎样保持同源》。
- 消灭挂载后取数。 价格与库存如果必须实时,把服务端渲染的最近值放进 HTML,客户端再刷新;抓取器至少拿到一个带时间标记的值,而不是空白。
- 给懒挂载内容一个 HTML 落点。 Tab 面板全部渲染进 HTML 再用脚本控制显示;无限滚动配分页 URL。
- 同意墙不得遮蔽正文。 弹窗覆盖在内容之上,而不是替代内容渲染。
- 服务端状态码。 不存在的路径返回真实 404;重定向由服务端发 301 或 308,不用 JS 或 meta refresh。
- 老 SPA 用预渲染过渡。 无法短期改架构的站点,先为产品页、服务页、高流量文章做预渲染,让抓取器拿到静态快照;这只是过渡,快照与真实页面漂移是新的维护负担。

七、发布前的验收清单
- 关键页面用爬虫 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 辅助进行资料整理与语言校对,文中事实、来源和结论均经人工复核。
