谷歌如何索引動態渲染的網站,你知道嗎?
了解搜索引擎是如何抓取、渲染和索引網頁的,對于針對搜索引擎優化網站至關重要。多年來,隨著谷歌等搜索引擎不斷改變其流程,我們很難了解哪些有效,哪些無效--尤其是客戶端 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