SEO for Software Engineers

Ben Hoyt

給軟體工程師的 SEO

原文由 Ben Hoyt 發布,訂閱此部落格

刊載於 Compass 技術部落格的原文

幾個月前,我為我們的軟體開發人員做了一場主題為「給工程師的 SEO」的技術分享。我們(SEO 團隊)發現,許多工程師對搜尋引擎最佳化並不太熟悉,有時在設計面向消費者的頁面時,做法並不利於 SEO。

所以我們覺得有必要為更大的團隊複習一下做好 SEO 的基本技巧……現在也把這些資訊分享給大家。市面上已經有大量關於 SEO 的文章,但多半是由 SEO 代理商撰寫的——這篇文章則是由工程師撰寫,寫給工程師看的。

過去與現在

值得比較一下現在與幾年前的 Google 搜尋結果頁面:

2019 年與 2012 年的 Google 搜尋結果頁面對比

即使 2012 年的螢幕比較小,不用捲動就能看到 3 筆非廣告的搜尋結果。到了 2019 年,映入眼簾的是四則廣告、一堆 Google 知識圖譜資訊和「其他人也問了」的回答,接著才出現一筆真正的搜尋結果!

要在不用捲動就看得到的版位中出現,變得越來越困難,可以說這讓做好 SEO 顯得更加重要。

什麼是 SEO?

SEO 是「搜尋引擎最佳化(search engine optimization)」的縮寫。這是一個好聽的說法,指的是讓你的網頁在搜尋結果中排名更前面,從而從搜尋引擎獲得更多、更優質流量的各種做法。

由於 Google 是主要的搜尋引擎提供者,這實際上就意味著要在 Google 搜尋中取得更前面的排名——不過,為 Google 做的多數優化,對所有搜尋引擎都有幫助。

請注意,SEO 並不是 SEM(search engine marketing,搜尋引擎行銷),後者指的是付費購買關鍵字廣告。你可以把 SEO 的「O」想成 organic(自然/非付費)搜尋,把 SEM 的「M」想成 money(付費)搜尋。本文不會談 SEM,而是聚焦於 SEO,特別是如何被索引並取得好的排名。

對工程師來說,SEO 的有些面向相當直接(多半是技術層面的部分),但有些則困難得多(例如實際產出並發布優質內容)。本文主要會聚焦在那些比較直接、你應該要做的技術性優化。

讓搜尋引擎爬取與索引

你的網頁最基本的需求,就是能被 Googlebot 爬取並建立索引,而這件事出錯的機率其實高得令人意外。每個你希望參與排名的頁面或頁面類型,都應該做到以下幾點:

  • 允許 robots.txt 爬取
  • 擁有穩定、標準化的網址
  • 回傳 HTTP 200,而非 404 或 500
  • 使用伺服器端渲染的 HTML
  • 能從站內其他頁面連到
  • 被列在 XML Sitemap 中

下面我們逐一詳細說明。

Robots.txt

多數中大型網站都會在 /robots.txt 放置一個文字檔,用來告訴「善意的機器人」,例如 Google 網路爬蟲,哪些頁面該爬、哪些不該爬。檔案格式非常簡單,在 robotstxt.orgGoogle 官方文件中都有詳細說明。一個簡單的 robots.txt 可能長這樣:

Sitemap: https://www.example.com/sitemap.xml
User-Agent: *  
Disallow: /api/  
Disallow: /staff/

這告訴 Googlebot(以及其他爬蟲)兩件事:

  1. 這個網站的 XML Sitemap 在哪裡。
  2. 對於所有 user agent(也就是所有爬蟲),不要爬取任何以 /api/ 或 /staff/ 開頭的網址。

不過你得小心一點——例如,要是某位出於好意的工程師(不懂 SEO 或沒看過這篇文章)決定「把那些煩人的機器人全部擋掉」,在檔案裡加上「Disallow: /」會怎麼樣?

又或者,你的執行長請工程師「幫我做一個介紹我的頁面」,而工程師在不知道 robots.txt 規則的情況下,把頁面放在 /staff/billg?他可能完全沒意識到這個頁面根本不可能被索引。

這種事發生的頻率比你想像的還高。有些公司會使用 robots.txt 解析函式庫來加入自動化檢查,確保重要頁面始終可被爬取。至少,你應該把 robots.txt 納入版控,並對所有變更進行嚴格審查。

顯然,你希望被爬取的頁面就應該在 robots.txt 中被允許。但你也應該主動禁止不需要被爬取的網址。例如,JSON API 的回應就不該被爬取——Google 只會為你的網站分配一定的 爬取預算(crawl budget),你不會想讓它浪費在不需要的內容上。

請注意,在 robots.txt 中禁止爬取 並非一種安全措施。任何惡意的機器人或駭客仍然可以爬取這些頁面。所以舉例來說,即使 /api/ 已在 robots.txt 中被禁止,若背後涉及非公開資訊,仍然需要做好安全的身分驗證。

穩定、標準化的網址

如果你是在既有的網路應用程式上工作,網址結構可能早就定好了。但若你要設計新的網址,有幾點需要留意:

一頁一網址:永遠用單一、標準化的網址來提供單一頁面。這裡說的 canonical 並不是指 rel=canonical 連結,而是指單一、經過正規化的網址。例如,如果你在 /staff/billg 提供某個頁面,就不要同時在 /staff/gates/bill 提供相同內容。如果你確實需要允許多個網址,請將其他網址以 301 重新導向至標準網址。

處理結尾斜線:承上,不要讓 /staff/billg 和 /staff/billg/ 兩個網址都回傳 HTTP 200。請擇一作為標準網址,並將另一個版本以 301 重新導向過去。

半可讀的網址:有不少文獻主張在網址中加入具描述性的關鍵字,這已成為「現代網路」的最佳實務。例如,比起 /articles/1234,更推薦使用 /articles/1234/seo-for-engineers。

包含資源 ID:如上例所示,在網址中加入像 1234 這樣的資源 ID,會讓技術實作更單純。用 ID 來實際查詢資源,若「seo-for-engineers」這段 slug 與文章目前的 slug 不符,就以 301 重新導向至標準網址。許多網站都採用這種做法,包括 StackOverflow、TripAdvisor 等——它能省去維護歷史網址變更或重新導向資料庫的麻煩。

如果某個網路應用程式的網址結構糟到需要重新設計,也是可以安全地完成的——你需要使用 HTTP 301 Moved Permanently 將舊網址重新導向至新網址。不過,別太常這樣做!

有一個地方你絕對應該使用 301,那就是將你的 http:// 網站重新導向至 https://,以及將非 www 網域重新導向至 www 網域(或反之)。

乾淨的 HTTP 回應

你會希望你的頁面在 Googlebot 眼中看起來盡可能乾淨:回傳 HTTP 200 且沒有重新導向。這能避免 Google 浪費爬取預算在重試上,最糟的情況下,也能避免因失效連結或間歇性 500 錯誤而被 Google 降低排名。應該避免的情況包括:

  • HTTP 404:如果某個網址錯誤地回傳 404 Page Not Found,代表要不是連結壞了,就是頁面處理邏輯壞了——兩者都應該避免。當然,如果該位置本來就不該有頁面,回傳 404 就正確的。
  • HTTP 301:301 Moved Permanently 很有用且有其重要用途(見前一節),但如果你的站內頁面大量連結到會被重新導向的網址,就應該更新這些連結。
  • HTTP 500:Internal Server Error 代表 Google 看到的是完全壞掉的頁面。無論如何,希望你的工程師本來就有密切監控 500 錯誤,如果沒有,現在就是開始的時候!

更多資訊請閱讀 Moz 的 HTTP 狀態碼指南

伺服器端渲染

對於你在意能否被搜尋到的頁面,應該一律提供伺服器端渲染的 HTML。這不僅對使用者有好處(載入更快、執行 JavaScript 耗電更少),對 Googlebot 也有好處。

「可是,」有人會說,「Google 現在會執行 JavaScript 了。」這從至少 2014 年以來就是如此——Google 的確會嘗試透過執行你的 JavaScript 來更了解你的頁面。然而,執行 JavaScript 的難度恐怕比單純解析 HTML 高出一個數量級:想想看,啟動 V8 並執行 JavaScript 所需的 CPU 資源,比起直接從伺服器端渲染的 HTML 中解析文字要多上多少。

依賴 Google 來執行你的 JavaScript 有很多但書(見上方連結的 2014 年文章)。此外,Google 似乎會即時解析 HTML,而 JavaScript 的執行則是分成兩個階段的過程,可能會被顯著延遲。因此,為了達到最佳效果,請一律在伺服器端產生 HTML 來提供內容。

你仍然可以使用 React 這類客戶端技術來讓頁面更具互動性,只是需要多花一點功夫並啟用伺服器端渲染。Compass 在幾年前從客戶端 React 轉為伺服器端渲染後,就看到了顯著的排名提升。

ReactDOMServer.renderToString(element)

將 React 元素渲染為初始的 HTML。React 會回傳一個 HTML 字串。你可以使用這個方法在伺服器上產生 HTML,並在初始請求時將標記傳送下去,以加快頁面載入速度並讓搜尋引擎能夠爬取你的頁面以進行 SEO。

內部連結

「內部連結(Internal linking)」是 SEO 領域的流行術語,意思其實很簡單,就是同一個網站內從一個頁面連到另一個頁面的連結。這類連結不僅能幫助使用者在站內導覽,也能讓 Google 爬取你的網站,並在站內傳遞「排名權重」。更多內容請參考 Moz 關於內部連結的文章

內部連結通常不難實作,你應該盡可能(在合理範圍內)從重要頁面連向其他重要頁面。內部連結的例子包括:

  • 麵包屑導覽
  • 頁首或頁尾的導覽連結
  • 協助使用者導覽、同時也幫助 Googlebot 發現更多頁面的連結區塊,例如從 Compass 房源頁連到相似房源的連結:

Compass 房源頁面上的「相似房源」小工具

多數大型網站也會有 HTML Sitemap,裡面包含連向站上所有重要頁面的連結。這類 Sitemap 過去對使用者更有用,現在隨著搜尋功能無所不在,它更像是一種 SEO 工具。不過,擁有 HTML Sitemap 仍被視為良好的實務。

Compass 與其他房地產網站的 HTML Sitemap 具有州、郡、郵遞區號的層級結構——最底層的頁面會連結到所有目前上架中的 Compass 獨家房源。這是我們讓 Google 發現房源頁面的另一種方式。

XML Sitemap

對於像 Compass 這樣的大型網站來說,XML Sitemap 恐怕更為重要。這些是簡單的 XML 檔案,會上傳到 Google Search Console 或在 robots.txt 中引用,內容只是列出你網站上的所有網址。這讓 Googlebot 能夠有系統地找到你所有的產品頁面,而不必逐一追蹤成千上萬個連結。

Compass 有多個 XML Sitemap(可以有不只一個):

Sitemap: https://www.compass.com/sitemaps/exclusives/sales-sf/index.xml
Sitemap: https://www.compass.com/sitemaps/exclusives/sales-la/index.xml
Sitemap: https://www.compass.com/sitemaps/exclusives/sales-nyc/index.xml
Sitemap: https://www.compass.com/sitemaps/exclusives/sales-dc/index.xml
Sitemap: https://www.compass.com/sitemaps/exclusives/sales-other/index.xml
Sitemap: https://www.compass.com/sitemaps/exclusives/rentals/index.xml
...

每個 sitemap index.xml 都是連向實際 sitemap.xml 檔案的索引檔,實際的 sitemap.xml 長這樣:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
 <url>
  <loc>
   https://www.compass.com/listing/101-old-mamaroneck-road-unit-1b4-white-plains-ny-10605/409187998570262817/
  </loc>
  <lastmod>2020-02-22T01:25:55.877000+00:00</lastmod>
 </url>
 <url>
  <loc>
   https://www.compass.com/listing/4641-south-lincoln-street-englewood-co-80113/414572085652655249/
  </loc>
  <lastmod>2020-02-22T01:25:16.710000+00:00</lastmod>
 </url>
 ...

「lastmod」欄位是選填的,可讓 Google 知道該頁面的資訊最後是在何時修改的,以判斷是否需要再次爬取。

你可以在 Google 文件中閱讀更多關於 XML Sitemap 的說明

提升效能與排名

頁面基本要素

要讓個別頁面更容易被發現,有幾個基本事項必須做到:

  • 頁面應該對行動裝置友善。Google 採用行動優先索引(mobile-first indexing),因此你應該優化頁面,使其在行動裝置上有良好的體驗。另外,不要在行動裝置與桌機上提供不同的內容。這些做法不僅對 Googlebot 有幫助,對使用者也有幫助。
  • 每個頁面都應該有一個簡潔、具體的 <title> 標籤。這有助於 Google 理解頁面的主旨,而且通常會清楚地顯示在搜尋結果頁面上。
  • 每個頁面都應該在 meta description 中提供簡短但精準的摘要。請閱讀 Moz 關於 meta description 的說明文件。
  • 每個頁面都應該有良好的結構:有意義的 <h1> 與 <h2> 標題、有意義的連結文字、加上良好 alt 文字描述的圖片等。
  • 對於產品頁面等類型,請使用 結構化資料,例如 JSON-LD,來提供 Google 更多細節。這能幫助 Google 更深入理解內容,也能驅動搜尋結果頁面上的資訊卡,例如:

Google 搜尋結果頁面上的食譜「資訊卡」

頁面速度

Google 在 2018 年表示,已將頁面速度作為決定行動版頁面排名的因素之一,因此讓頁面變快是值得的。

當然,第一件事就是後端要能及時回傳 HTML。這很容易量測,但只是第一步——客戶端的效能同樣會被納入考量。Google 提供了大量關於如何量測與改善頁面速度的資訊,建議你去閱讀。

Chrome 本身也內建了很棒的工具,能讓你在本機以 Google 的視角量測頁面速度。在頁面上按右鍵,點選「檢查」,前往「Audits」分頁,然後對 Mobile 執行「Performance」檢測。你會得到一份精美的報告,其中包含一些(有時很有用的)建議:

Lighthouse 效能檢測的截圖

Google 關於速度的文章在他們自己的速度測試工具中拿到了 90/100 分——不錯(還是作弊了?:-)。

影響頁面速度的因素有很多:

  • Time to first byte:伺服器回傳第一個位元組所需的網路時間。接著是 HTML 下載時間,取決於使用者的頻寬與 HTML 的大小。盡量把檔案大小壓低!
  • First contentful paint:首次渲染出 DOM 真實內容所需的時間。這能讓使用者知道頁面正在載入,Google 也將其作為頁面速度的信號之一。
  • Time to interactive:使用者實際能與頁面互動所需的時間。通常需要執行一些 JavaScript 才能讓頁面可互動,因此要留意 JavaScript 的打包大小、啟動時間等。
  • 靜態資源:你的 CSS 與 JavaScript 應該以較長的到期時間進行快取,最好放在 CDN 之後。它們也應該在合理範圍內盡可能小——要小心像 Moment.js 這類大型的 JavaScript 套件!
  • 圖片載入時間:你應該提供大小合理的圖片,並設定正確的快取標頭,最好透過具快取功能的 CDN 提供。如果頁面引用了大量大圖,請考慮對其中部分圖片採用延遲載入(lazy-loading)。

要小心!如果你跟多數公司一樣,不斷在迭代與開發頁面,頁面很可能會越來越慢。你需要持續對頁面速度保持警覺:每當新增功能、增加對後端服務的呼叫時,都要進行量測。

連結與網域權重

Google 誕生於 PageRank 演算法(有趣的是,它是以 Larry Page 的名字命名,而非 Web Page)。

PageRank 的運作方式是透過計算指向某個頁面的連結數量與品質,來粗略估算該網站的重要性。

換句話說,如果有很多其他頁面連到你的頁面,你的排名就會更好。若這些連結來自 PageRank 高的頁面,效果會更好。因此,你應該盡可能讓具權威性的網站連結到你的頁面。

例外是 rel=nofollow 連結:「nofollow」是網站加在 <a> 連結標籤上的屬性,用來告訴 Google 不要追蹤或在排名計算中採用這個連結。這通常用於使用者產生的內容,例如部落格或 YouTube 留言,這些內容可能品質低落且充斥垃圾訊息。

如果這類網站沒有使用 rel=nofollow,垃圾訊息發送者就會提交數百個連向自己頁面的連結來人為拉高排名。而這正是「nofollow」出現之前實際發生的情況。

還有一個 SEO 概念叫 網域權重(domain authority),這是 Moz 的一項指標,用來表示特定網域整體的權威程度(例如:nytimes.com 是 95/100,stackoverflow.com 是 93,我的個人小網站則是 37)。這並不是 Google 的指標,但似乎可以作為 Google 如何看待特定網域重要性的合理參考。

延伸閱讀

本文主要討論的是技術性的 SEO 改善——這些往往是工程師能直接掌控的部分。但這只是故事的一半。

如果你做了所有這些技術性的 SEO,卻沒有好的內容,Google 不會給你排名,也不會有人使用你的網站。SEO 做得再好,內容很糟,還是糟糕的 SEO。反過來說,如果你有好的內容,遵循這些技巧會讓它有更大的機會獲得好的排名。

Google 的 SEO 入門指南是來自官方、關於這些主題的絕佳讀物,Moz 的 SEO 初學者指南也是如此。

如果想與我們聯繫,請查看我們 robots.txt 頂端的橫幅!

本文章由 muse-spark-1.2-contributor 進行翻譯

留言