2009-10-12

「讓 AJAX 網頁可以被網路爬蟲讀取」的建議書

原文網址: http://googlewebmastercentral.blogspot.com/2009/10/proposal-for-making-ajax-crawlable.html

今天,我們很興奮地提出「讓以 AJAX 為基礎的網站可以被網路爬蟲讀取」的規格建議書。這將有益於網站管理者和使用者在製作豐富、互動的 AJAX 網站時,可以讓所有的搜尋引擎讀取到想要被搜尋到的部份。我們相信,這類的內容如果可以被網路爬蟲讀取以及被索引,將會讓網路有長足的進步。

當 AJAX 網站受到使用者歡迎的同時,搜尋引擎並無法讀取這些網站的內容。我們的最新調查顯示:有 70% 的網站在 form 或是其他地方使用了 JavaScript。當然,大部分的 JavaScript 並不是 AJAX,但是如果搜尋引擎可以處理、索引 AJAX 的內容,開發者就可以在他們的網站上做出更多豐富的內容,而搜尋引擎依然找得到。

下面是這份建議書希望達到的目標:

  • 當網站成長時,所需要的變動是最小的
  • 使用者跟搜尋引擎看到的是相同的內容(無須 cloaking)
  • 搜尋引擎可以直接讓使用者導向到 AJAX 的 URL(而不一個靜態複製網頁)
  • 網站擁有者有方法可以驗證他們的 AJAX 網站顯示正常,也因此網路爬蟲可以讀取所有的內容。

下面是我們初步建議書當中,搜尋引擎處理、索引 AJAX 內容的方式:

  • 把 stateful 的 AJAX 頁面的 URL fragment 稍作修改:
    無論何時,直接讀取 stateful 的 AJAX 頁面都會顯示一樣內容。這些頁面可以變成搜尋結果。我們想把像這樣的 URL「http://example.com/page?query#state」 加上一個 token 成這樣「http://example.com/page?query#[FRAGMENTTOKEN]state」以作識別。在檢視網路上的 URL 之後,我們建議使用驚嘆號「!」。在搜尋結果當中顯示的 URL 會像這樣「http://example.com/page?query#!state」。
  • 使用 headless 瀏覽器,讓你的 web server 有一個 HTML 的 snapshot。
    headless 瀏覽器用來讀取 AJAX 頁面,然後最終瀏覽器的結果產生 HTML。只有特別標記的 URL 才傳給 headless 瀏覽器處理。在 server 端作這件事情時,網站擁有者可以控制 HTML  的產生,也就可以輕鬆地驗證所有的 JavaScript 是否正常執行。HtmlUnit —open source、沒有 GUI 的 Java 程式—就是一個 headless 瀏覽器的例子。
  • 允許搜尋引擎的爬蟲去讀取有對 state 作 escape 的 URL
    URL fragment 並不會隨著 request 送到 server 去,所以需要稍微變動 URL 以讀取該頁面。同時,這也會讓 server 啟用 headless 瀏覽器去產生 HTML 而不是傳回有 JavaScript 的頁面。此外,既有的 URL—使用者看到的那些—則會用平常的方式處理,不會啟用 headless 瀏覽器。我們建議 escape state 資訊,然後把它加到 query parameter 當中,變成一個 token。用上頭的例子,URL 可能會長這樣:「http://example.com/page?query&[QUERYTOKEN]=state」。依照我們對現在網路上 URL 的分析結果,我們建議用「_escaped_fragment_」來作為 token。建議的 URL 會變成:「http://example.com/page?query&_escaped_fragment_=state」
  • 在搜尋結果當中,顯示原來的 URL
    為了改善使用者經驗,這會讓使用者直接連回 AJAX 頁面。搜尋結果當中顯示原始的 URL(如前面的例子:http://example.com/page?query#!state)就可以做到。搜尋引擎可以檢查被 Googlebot 索引的文字,是否跟使用者看到的一樣(或是子集)。



總結來說,如果一個 stateful 的 URL,例如:「http://example.com/dictionary.html#AJAX」,同時給使用者或網路爬蟲使用的 URL 會變成「http://example.com/dictionary.html#!AJAX」,而可以被爬蟲爬的 URL 會變成「http://example.com/dictionary.html?_escaped_fragment_=AJAX」,但使用者存取還是用「http://example.com/dictionary.html#!AJAX」