了解搜索引擎是如何抓取、渲染和索引网页的,对于针对搜索引擎优化网站至关重要。多年来,随着谷歌等搜索引擎不断改变其流程,我们很难了解哪些有效,哪些无效--尤其是客户端 JavaScript。
我们注意到,一些陈旧的观念一直存在,让社区对应用 SEO 的最佳实践缺乏信心:
- "谷歌无法渲染客户端 JavaScript"。
- "谷歌对 JavaScript 页面的处理方式不同"。
- "渲染队列和时间对 SEO 有重大影响"。
- "JavaScript 量大的网站页面发现速度较慢"。
为了解决这些问题,我们与领先的搜索引擎优化和数据工程咨询公司 MERJ[1] 合作,对 Google 的抓取行为进行了新的实验。我们分析了不同网站上超过 100,000 次的 Googlelebot 抓取行为,以测试和验证 Google 的搜索引擎优化能力。
让我们来看看 Google 的渲染方式是如何演变的。然后,我们将探讨我们的发现及其对现代web应用的实际影响。
谷歌渲染能力的演变
多年来,谷歌抓取和索引网页内容的能力发生了显著变化。了解这一演变对于理解现代web应用的搜索引擎优化现状非常重要。
2009 年以前:对 JavaScript 的支持有限
在搜索的早期,谷歌主要索引静态 HTML 内容。搜索引擎基本上看不到 JavaScript 生成的内容,这导致静态 HTML 被广泛用于搜索引擎优化。
2009-2015年:AJAX 抓取方案
谷歌推出了 AJAX 抓取方案,允许网站提供动态生成内容的 HTML 快照。这是一种权宜之计,需要开发人员为网页创建单独的可抓取版本
2015-2018年:早期 JavaScript 渲染
谷歌开始使用无头 Chrome 浏览器渲染网页,标志着向前迈进了一大步。不过,这种旧版浏览器在处理现代 JavaScript 功能方面仍有局限。
2018 年至今:现代渲染能力
如今,谷歌使用最新版本的 Chrome 浏览器进行渲染,与最新的网络技术保持同步。当前系统的主要方面包括:
- 通用渲染:Google 现在会尝试渲染所有 HTML 页面,而不仅仅是一个子集。
- 最新的浏览器:Googlebot 使用最新稳定版本的 Chrome/Chromium,支持现代 JS 功能。
- 无状态渲染:每次页面渲染都是在一个全新的浏览器会话中进行的,不会保留之前渲染的 cookie 或状态。谷歌一般不会点击页面上的项目,如标签内容或 cookie 横幅。
- 隐藏:谷歌禁止向用户和搜索引擎显示不同的内容来操纵排名。避免根据 User-Agent 更改内容的代码。取而代之的是,为 Google 优化应用程序的无状态渲染,并通过有状态方法实现个性化。
- 资产缓存:Google 通过缓存资产加快网页渲染速度,这对于共享资源的页面和重复渲染同一页面非常有用。Google 的网页渲染服务不使用 HTTP Cache-Control 标头,而是采用自己的内部启发式方法来确定缓存资产何时仍然新鲜,何时需要再次下载。
图片
在更好地了解 Google 的能力之后,让我们来看看一些常见的误区以及它们对搜索引擎优化的影响。
方法
为了研究以下误区,我们使用 Vercel 的基础架构和 MERJ 的网络渲染监控器(WRM)技术进行了一项研究。我们的研究重点是 nextjs.org[2],以及 monogram.io[3] 和 basement.io[4] 的补充数据,时间跨度为 2024 年 4 月 1 日至 4 月 30 日。
数据收集
我们在这些网站上放置了一个定制的边缘中间件[5],用于拦截和分析来自搜索引擎机器人的请求。通过该中间件,我们可以:
- 识别并跟踪来自各种搜索引擎和AI爬虫的请求(查询中不包括用户数据)。
- 在 HTML 响应中为机器人注入一个轻量级 JavaScript 库[6]。
该 JavaScript 库在页面渲染完成时触发,向长期运行的服务器发送数据,其中包括:
- 页面 URL
- 唯一请求标识符(用于将页面渲染与常规服务器访问日志进行匹配)
- 渲染完成的时间戳(使用服务器上的 JavaScript 库请求接收时间计算得出)。
数据分析
通过比较服务器访问日志中的初始请求和我们的中间件向外部灯塔服务器发送的数据,我们可以:
- 确认哪些页面被搜索引擎成功渲染。
- 计算初始抓取和完成渲染之间的时间差。
- 分析不同类型内容和 URL 的处理模式。
数据范围
在本文中,我们主要关注来自 Googlebot 的数据,它提供了最大、最可靠的数据集。我们的分析包括超过 37,000 个与服务器-灯塔对匹配的渲染 HTML 页面,为我们提供了一个强大的样本来得出结论。
我们仍在收集其他搜索引擎的数据,包括 OpenAI 和 Anthropic 等人工智能提供商的数据,并希望在未来更多地讨论我们的发现。
在下面的章节中,我们将深入探讨每个误区,并在必要时提供更多相关方法。
误区1:谷歌无法渲染JavaScript内容
这一误区导致许多开发人员避开 JS 框架,或采用复杂的变通方法来实现SEO。
测试
为了测试 Google 渲染 JavaScript 内容的能力,我们重点关注了三个关键方面:
- JS 框架兼容性:我们使用 nextjs.org[7] 上的数据分析了 Googlebot 与 Next.js 的交互,Next.js.org[8] 混合使用了静态预渲染、服务器端渲染和客户端渲染。
- 动态内容索引:我们检查了 nextjs.org[9] 上通过 API 调用异步加载内容的页面。这使我们能够确定 Googlebot 是否能够处理和索引初始 HTML 响应中不存在的内容。
- 通过 React 服务器组件 (RSC) 流式加载内容:与上述情况类似,nextjs.org[10] 的大部分内容都是使用 Next.js App Router[11] 和 RSC[12] 构建的。我们可以看到 Googlebot 是如何处理并索引增量流向页面的内容的。
- 渲染成功率:我们将服务器日志中的 Googlebot 请求数与收到的成功渲染灯塔数进行了比较。这让我们深入了解了完全渲染的抓取页面所占的比例。
发现
- 在 nextjs.org[13] 上分析的 100,000 多次 Googlebot 抓取中,除去状态代码错误和不可索引的页面,100% 的 HTML 页面都实现了全页面渲染,包括具有复杂 JS 交互的页面。
- 所有通过 API 调用异步加载的内容都被成功索引,这证明了 Googlebot 处理动态加载内容的能力。
- 基于 React 框架的 Next.js 被 Googlebot 完全渲染,这证明了它与现代 JavaScript 框架的兼容性。
- 通过 RSC 流式传输的内容也被完全渲染,这证明流式传输不会对 SEO 产生不利影响[14]。
- Google 会尝试渲染它抓取的几乎所有 HTML 页面,而不仅仅是 JavaScript 重度页面的子集。
误区2:谷歌对 JavaScript 页面的处理方式不同
一个常见的误解是,谷歌对 JavaScript 较多的网页有单独的处理程序或标准。我们的研究以及 Google 的官方声明揭穿了这一误区。
测试
为了测试 Google 在哪些方面对 JS 较多的页面采取了不同的处理方式,我们采取了几种有针对性的方法:
- CSS @import测试:我们创建了一个不含 JavaScript 的测试页面,但其中的 CSS 文件会 @import 第二个 CSS 文件(只有在渲染第一个 CSS 文件时才会下载并显示在服务器日志中)。通过将这一行为与启用 JS 的页面进行比较,我们可以验证在启用和未启用 JS 的情况下,Google 渲染器处理 CSS 的方式是否有所不同。
- 状态码和元标签处理:我们开发了一个带有中间件的 Next.js 应用程序,用于测试 Google 的各种 HTTP 状态代码。我们的分析重点是谷歌如何处理不同状态代码(200、304、3xx、4xx、5xx)的网页以及带有 noindex 元标签的网页。这有助于我们了解在这些情况下,JavaScript 较多的页面是否会受到不同的处理。
- JavaScript 复杂性分析:我们比较了 nextjs.org[15] 上不同 JavaScript 复杂程度页面的 Google 渲染行为。这包括使用最少 JS 的页面、具有适度交互性的页面和具有大量客户端渲染的高动态页面。我们还计算并比较了初始抓取和完成渲染之间的时间,以了解更复杂的 JS 是否会导致更长的渲染队列或处理时间。
发现
- 我们的 CSS @import 测试证实,无论是否有 JS,Google 都能成功渲染页面。
- 无论是否有 JS 内容,Google 都能渲染所有 200 状态的 HTML 页面。使用原始 200 状态页面的内容渲染 304 状态页面。不渲染其他 3xx、4xx 和 5xx 错误的页面。
- 不渲染初始 HTML 响应中包含 noindex 元标记的页面,无论 JS 内容如何。客户端移除 noindex 标签对搜索引擎优化无效;如果一个页面在初始 HTML 响应中包含 noindex 标签,它将不会被渲染,而移除该标签的 JavaScript 也不会被执行。
- 我们发现,在渲染具有不同 JS 复杂程度的页面时,Google 的成功率没有显著差异。在 nextjs.org[16] 的规模上,我们也没有发现 JavaScript 复杂性与渲染延迟之间的相关性。不过,在规模更大的网站上,更复杂的 JavaScript 可能会影响抓取效率。
误区3:渲染队列和时间对 SEO 有重大影响
许多SEO从业人员认为,由于渲染队列的原因,JavaScript 较多的网页在索引过程中会面临严重的延迟。我们的研究对这一过程有了更清晰的认识。
测试
为了解决渲染队列和时间对搜索引擎优化的影响,我们进行了以下调查:
- 渲染延迟:我们使用 nextjs.org[17] 上超过 37,000 个匹配服务器-灯塔对的数据,检查了谷歌最初抓取页面与完成渲染之间的时间差。
- URL 类型:我们分析了带查询字符串和不带查询字符串的 URL 以及 nextjs.org[18] 不同部分(如 /docs、/learn、/showcase)的渲染时间。
- 频率模式:我们研究了 Google 重新渲染页面的频率,以及不同类型内容的渲染频率是否存在模式。
发现
渲染延迟分布如下:
- 第 50 个百分位数(中位数):10 秒
- 第 75 个百分位数:26 秒
- 第 90 个百分位数:~3 小时
- 第 95 个百分位数:~6 小时
- 第 99 个百分位数:~18 小时
图片
令人惊讶的是,第 25 百分位数的页面在初始抓取后 4 秒内就能渲染,这对 "长队列" 的概念提出了质疑。
虽然有些页面面临严重的延迟(第 99 百分位数的页面延迟时间长达约 18 小时),但这些都是例外,而不是常规。
我们还观察到一些有趣的模式,这些模式与 Google 如何快速渲染带有查询字符串 (?param=xyz)的 URL 有关:
图片
这些数据表明,如果 URL 包含不影响内容的查询字符串,Google 会以不同的方式处理 URL。例如,在 nextjs.org[19] 上,带有 ?ref= 参数的页面的渲染延迟时间更长,尤其是在百分位数较高的情况下。
此外,我们注意到,与较静态的部分相比,/docs 等经常更新的部分的中位渲染时间较短。例如,/showcase 页面尽管经常被链接,但渲染时间却更长,这表明 Google 可能会放慢对变化不大的页面的重新渲染速度。
误区4:大量使用 JavaScript 的网站页面发现速度较慢
SEO界始终认为,JavaScript 量大的网站,尤其是那些依赖于客户端渲染(CSR)的网站,如单页应用程序(SPA),谷歌发现页面的速度较慢。我们的研究在这方面提供了新的见解。
测试
为了研究 JavaScript 对页面发现的影响,我们:
- 分析了不同渲染场景下的链接发现:我们比较了 Google 在 nextjs.org[20] 上服务器渲染、静态生成和客户端渲染的页面中发现和抓取链接的速度。
- 测试非渲染的 JavaScript 有效载荷:我们在 nextjs.org[21] 的 /showcase 页面上添加了一个类似于 React 服务器组件 (RSC) 有效负载的 JSON 对象,其中包含指向以前未发现的新页面的链接。这样,我们就可以测试 Google 能否发现未渲染的 JavaScript 数据中的链接。
- 比较发现时间:我们监测了 Google 发现和抓取以不同方式链接的新网页的速度:标准 HTML 链接、客户端渲染内容中的链接以及未渲染的 JavaScript 有效载荷中的链接。
发现
- 无论采用何种渲染方法,Google 都能成功发现并抓取完全渲染页面中的链接。
- Google 可以发现页面上未渲染 JavaScript 有效载荷中的链接,例如 React Server Components 或类似结构中的链接。
- 在初始和渲染的 HTML 中,谷歌都会使用当前主机和端口作为相对 URL 的基础,通过识别类似 URL 的字符串来处理内容。(在我们类似 RSC 的有效负载中,谷歌没有发现编码 URL(即 https%3A%2F%2Fwebsite.com[22]),这表明谷歌的链接解析非常严格)。
- 链接的来源和格式(如在 <a> 标记中或嵌入在 JSON 有效负载中)并不影响 Google 抓取的优先级。无论 URL 是在初始抓取中发现还是在渲染后发现,抓取优先级都保持一致。
- 虽然 Google 能成功发现 CSR 页面中的链接,但这些页面确实需要先进行渲染。服务器渲染的页面或部分预渲染的页面在即时链接发现方面略占优势。
- 谷歌对链接发现和链接价值评估进行了区分。对网站架构和抓取优先级的链接价值评估是在全页面渲染之后进行的。
- 更新 sitemap.xml 即使不能消除不同渲染模式之间的链接发现时间差异,也能大大减少这种差异。
总体影响和建议
我们的研究揭穿了 Google 处理 JavaScript 重度网站的几个常见误区。以下是主要结论和可行建议:
影响
- JavaScript 兼容性:Google 可以有效地渲染 JavaScript 内容并编制索引,包括复杂的 SPA、动态加载的内容和流媒体内容。
- 渲染平等性:与静态 HTML 网页相比,谷歌处理 JavaScript 内容较多的网页的方式没有本质区别。所有页面都会被渲染。
- 渲染队列现实:虽然存在渲染队列,但其影响没有以前想象的那么大。大多数页面都是在几分钟内渲染,而不是几天或几周。
- 页面发现:JavaScript 较多的网站(包括 SPA)在谷歌页面发现方面并不处于劣势。
- 内容时机:某些元素(如 noindex 标签)何时添加到页面至关重要,因为 Google 可能不会处理客户端的更改。
- 链接价值评估:Google 区分链接发现和链接价值评估。后者发生在全页面渲染之后。
- 渲染优先级:Google 的渲染过程并不是严格的先入先出。与 JavaScript 的复杂性相比,内容的新鲜度和更新频率等因素对优先级的影响更大。
- 渲染性能和抓取预算:虽然 Google 可以有效渲染 JS 较多的页面,但与静态 HTML 相比,渲染过程对你和 Google 来说都是资源密集型的。对于大型网站(10,000 个以上唯一且经常变化的页面),这会影响网站的抓取预算。优化应用程序性能并尽量减少不必要的 JS 可以帮助加快渲染过程、提高抓取效率,并有可能让更多页面被抓取、渲染和索引。
推荐
- 拥抱 JavaScript:自由使用 JavaScript 框架,以增强用户和开发人员的体验,但要优先考虑性能,并遵守 Google 的懒加载最佳实践[23]。
- 错误处理:在 React 应用程序中实施错误边界[24],以防止因单个组件错误而导致整体渲染失败。
- 关键SEO元素:对关键的 SEO 标记和重要内容使用服务器端渲染或静态生成,以确保它们出现在初始 HTML 响应中。
- 资源管理:确保用于渲染的关键资源[25](API、JavaScript 文件、CSS 文件)不被 robots.txt 屏蔽。
- 内容更新:对于需要快速重新索引的内容,确保在服务器渲染的 HTML 中反映更改,而不仅仅是客户端 JavaScript。考虑采用增量静态再生[26]等策略,在内容新鲜度与搜索引擎优化和性能之间取得平衡。
- 内部链接和 URL 结构:创建清晰、合理的内部链接结构。将重要的导航链接作为真正的 HTML 锚标签 (<a href="...">),而不是基于 JavaScript 的导航。这种方法有助于提高用户导航和搜索引擎抓取效率,同时还能减少渲染延迟。
- 网站地图:使用并定期更新网站地图[27]。对于大型网站或经常更新的网站,在 XML 网站地图中使用 <lastmod> 标签来引导 Google 的抓取和索引过程。请记住,只有在发生重大内容更新时才更新 <lastmod>。
- 监控:使用 Google Search Console 的 URL 检查工具[28]或富媒体搜索结果工具[29]来验证 Googlebot 如何查看你的网页。监控抓取统计数据,确保你选择的渲染策略不会导致意外问题。
渲染策略
正如我们已经探讨过的,在谷歌的能力方面,不同的渲染策略[30]存在一些差异:
特性 | 静态网站生成(SSG) | 增量式静态再生(ISR) | 服务器端渲染(SSR) | 客户端渲染(CSR) |
抓取效率:谷歌访问、渲染和检索网页的速度和效率。 | 优秀 | 优秀 | 非常好 | 差 |
发现:寻找要抓取的新 URL 的过程*。 | 优秀 | 优秀 | 优秀 | 平均 |
渲染完整性(错误、失败等):谷歌加载和处理网页的准确性和完整性。 | 健全 | 健全 | 健全 | 可能失败** |
渲染时间:Google 完全渲染和处理网页所需的时间。 | 优秀 | 优秀 | 优秀 | 差 |
链接结构评估:谷歌如何评估链接以了解网站架构和页面的重要性。 | 渲染后 | 渲染后 | 渲染后 | 渲染后,如果渲染失败,链接可能会丢失 |
索引:谷歌存储和组织网站内容的过程。 | 健全 | 健全 | 健全 | 如果渲染失败,可能无法索引 |
- 更新 sitemap.xml,即使不能消除不同渲染模式之间的时间差,也能大大减少发现时间。
** 谷歌渲染通常不会失败,我们的研究已经证明了这一点;如果失败,通常是由于 robots.txt 中的资源被封或特定的边缘情况。
虽然存在这些细微差别,但无论采用哪种渲染策略,谷歌都会很快发现并索引你的网站。与其担心谷歌渲染过程的特殊适应性,不如专注于创建有益于用户的高性能网络应用程序。
毕竟,页面速度仍然是一个排名因素,因为谷歌的页面体验排名系统会根据谷歌的核心Web指标[31]来评估网站的性能。
此外,页面速度与良好的用户体验息息相关--每节省 100 毫秒的加载时间,网站转化率就会提高 8%。更少的用户跳出你的页面意味着谷歌将其视为更相关的页面。性能决定一切,毫秒至关重要。
本文译自:https://vercel.com/blog/how-google-handles-javascript-throughout-the-indexing-process
Reference
[1]MERJ: https://merj.com/
[2]nextjs.org: http://nextjs.org/
[3]monogram.io: http://monogram.io/
[4]basement.io: http://basement.io/
[5]边缘中间件: https://vercel.com/docs/functions/edge-middleware
[6]轻量级 JavaScript 库: https://github.com/merj/wrm-research-vercel
[7]nextjs.org: http://nextjs.org/
[8]Next.js.org: http://next.js.org/
[9]nextjs.org: http://nextjs.org/
[10]nextjs.org: http://nextjs.org/
[11]Next.js App Router: https://nextjs.org/docs/app
[12]RSC: https://vercel.com/blog/understanding-react-server-components?nxtPslug=understanding-react-server-components
[13]nextjs.org: http://nextjs.org/
[14]流式传输不会对 SEO 产生不利影响: https://vercel.com/guides/does-streaming-affect-seo
[15]nextjs.org: http://nextjs.org/
[16]nextjs.org: http://nextjs.org/
[17]nextjs.org: http://nextjs.org/
[18]nextjs.org: http://nextjs.org/
[19]nextjs.org: http://nextjs.org/
[20]nextjs.org: http://nextjs.org/
[21]nextjs.org: http://nextjs.org/
[22]2Fwebsite.com: http://2Fwebsite.com
[23]Google 的懒加载最佳实践: https://developers.google.com/search/docs/crawling-indexing/javascript/lazy-loading
[24]错误边界: https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary
[25]用于渲染的关键资源: https://merj.com/blog/managing-webpages-resources-for-efficient-crawling-and-rendering
[26]增量静态再生: https://vercel.com/docs/incremental-static-regeneration#differences-between-isr-and-cache-control-headers
[27]使用并定期更新网站地图: https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview
[28]URL 检查工具: https://support.google.com/webmasters/answer/9012289?hl=en
[29]富媒体搜索结果工具: https://search.google.com/test/rich-results
[30]渲染策略: https://vercel.com/blog/how-to-choose-the-best-rendering-strategy-for-your-app
[31]核心Web指标: https://developers.google.com/search/docs/appearance/core-web-vitals