html5 tutorial中文 - 搜索引擎如何處理AngularJS應用程序?




4書 angular入門 (13)

一個好的做法可以在這裡找到:

http://scotch.io/tutorials/javascript/angularjs-seo-with-prerender-io?_escaped_fragment_=tag

我看到有關搜索引擎和搜索引擎優化的AngularJS應用程序的兩個問題:

1)自定義標籤會發生什麼? 搜索引擎會忽略這些標籤中的全部內容嗎? 即假設我有

<custom>
  <h1>Hey, this title is important</h1>
</custom>

儘管在自定義標籤內,會不會索引<h1>


2)有沒有辦法避免索引{{}}的搜索引擎直接綁定? 即

<h2>{{title}}</h2>

我知道我可以做類似的事情

<h2 ng-bind="title"></h2>

但是如果我想讓爬蟲“看見”標題呢? 服務器端是唯一的解決方案嗎?


使用PushState和預分解

目前(2015年)的方式是使用JavaScript pushState方法。

PushState更改頂部瀏覽器欄中的URL,而無需重新加載頁面。 假設您有一個包含選項卡的頁面。 這些標籤隱藏並顯示內容,並且動態插入內容,可以使用AJAX或通過簡單設置display:none和display:block來隱藏和顯示正確的標籤內容。

點擊標籤後,使用pushState更新地址欄中的網址。 當頁面呈現時,使用地址欄中的值來確定顯示哪個標籤。 角度路由將自動為您完成。

Precomposition

有兩種方法可以觸發PushState單頁應用程序(SPA)

  1. 通過PushState,用戶點擊一個PushState鏈接並且內容被AJAX引入。
  2. 直接點擊URL。

網站上的最初命中將涉及直接點擊URL。 隨著PushState更新URL,隨後的點擊只會在內容中顯示AJAX。

爬行程序從頁面收集鏈接,然後將它們添加到隊列中以供日後處理。 這意味著對於爬蟲來說,服務器上的每次命中都是直接命中,它們不會通過Pushstate進行導航。

預整合將初始有效負載捆綁到來自服務器的第一個響應中,可能是JSON對象。 這允許搜索引擎在不執行AJAX調用的情況下呈現頁面。

有一些證據表明Google可能不會執行AJAX請求。 更多關於這裡:

https://web.archive.org/web/20160318211223/http://www.analog-ni.co/precomposing-a-spa-may-become-the-holy-grail-to-seo

搜索引擎可以讀取和執行JavaScript

Google已經能夠解析JavaScript一段時間了,這就是為什麼他們最初開發Chrome的原因,是為了充當Google spider的全功能無頭瀏覽器。 如果鏈接具有有效的href屬性,則可以對新URL進行索引。 沒有什麼可做的了。

如果另外點擊鏈接觸發pushState調用,則用戶可以通過PushState導航站點。

搜索引擎支持PushState網址

PushState目前由Google和Bing支持。

谷歌

馬特卡茨回應Paul Irish關於PushState搜索引擎優化的問題:

http://youtu.be/yiAF9VdvRPw

Google宣布對蜘蛛完全支持JavaScript:

http://googlewebmastercentral.blogspot.de/2014/05/understanding-web-pages-better.html

結果是Google支持PushState並將索引PushState URL。

另請參閱Google網站站長工具的Googlebot抓取工具。 你會看到你的JavaScript(包括Angular)被執行。

這是Bing公司於2013年3月發布的支持美國PushState網址的公告:

http://blogs.bing.com/webmaster/2013/03/21/search-engine-optimization-best-practices-for-ajax-urls/

不要使用HashBangs#!

Hashbang網站是一個醜陋的主題,要求開發人員在特定位置提供預渲染版本的網站。 他們仍然工作,但你不需要使用它們。

Hashbang網址如下所示:

domain.com/#!path/to/resource

這將與這樣的元標籤配對:

<meta name="fragment" content="!">

Google不會以這種形式為它們編制索引,而是會從_escaped_fragments_網址中提取該網站的靜態版本並將其編入索引。

推送狀態URL看起來像任何普通的URL:

domain.com/path/to/resource

不同之處在於Angular通過攔截在JavaScript中處理document.location的變化來處理它們。

如果你想使用PushState URLs(你可能會這樣做)去掉所有舊的哈希樣式URL和元標記,並簡單地在你的配置塊中啟用HTML5模式。

測試你的網站

谷歌網站管理員工具現在包含一個工具,它可以讓你獲取一個網址為谷歌,並呈現為谷歌呈現它的JavaScript。

https://www.google.com/webmasters/tools/googlebot-fetch

在Angular中生成PushState URL

要在Angular中生成真實的URL,而不是#前綴,請在$ locationProvider對像上設置HTML5模式。

$locationProvider.html5Mode(true);

服務器端

由於您使用的是真實網址,因此您需要確保服務器為所有有效的網址提供相同的模板(以及一些預先製作的內容)。 你如何做到這一點將取決於你的服務器體系結構。

網站地圖

您的應用可能會使用不尋常的導航形式,例如懸停或滾動。 為確保Google能夠驅動您的應用,我可能會建議您創建一個網站地圖,這是您應用響應的所有網址的簡單列表。 您可以將其放置在默認位置(/ sitemap或/sitemap.xml),或者使用網站管理員工具告知Google。

無論如何,有一個網站地圖是一個好主意。

瀏覽器支持

Pushstate在IE10中工作。 在舊版瀏覽器中,Angular會自動回退到哈希風格的URL

演示頁面

以下內容使用具有預合成功能的pushstate網址呈現:

http://html5.gingerhost.com/london

可以驗證的是,在此鏈接中 ,內容已編入索引並顯示在Google中。

提供404和301標題狀態代碼

由於搜索引擎總是會針對您的服務器提出每項請求,因此您可以從服務器提供標題狀態代碼,並希望Google能夠看到它們。



2014年5月更新

Google抓取工具現在可以執行JavaScript - 您可以使用Google網站站長工具來更好地了解您的網站是如何由Google呈現的。

原始答案
如果你想優化你的搜索引擎的應用程序,不幸的是沒有辦法為爬蟲提供預渲染的版本。 您可以在這裡閱讀更多關於Google針對ajax和javascript-heavy網站的建議。

如果這是一個選項,我建議閱讀這篇文章,了解如何使用服務器端渲染為Angular做SEO。

我不確定抓取工具在遇到自定義代碼時會做些什麼。


Google的Crawlable Ajax Spec,在這裡的其他答案中提到,基本上就是答案。

如果您對其他搜索引擎和社交機器人如何處理相同問題感興趣,請在此處撰寫藝術狀態: http://blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification.html : http://blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification.html

我為https://ajaxsnapshots.com工作,這是一家實施Crawlable Ajax Spec作為服務的公司 - 該報告中的信息基於我們日誌中的觀察結果。



讓我們了解一下AngularJS和SEO

Google,Yahoo,Bing和其他搜索引擎使用傳統的抓取工具以傳統方式抓取網頁。 他們運行機器人抓取網頁上的HTML,沿途收集信息。 他們保持有趣的話,並尋找其他網頁的其他鏈接(這些鏈接,它們的數量和它們的數量與SEO發揮作用)。

那麼,為什麼不搜索引擎處理JavaScript網站?

答案與搜索引擎機器人通過無頭瀏覽器工作的事實有關,並且他們通常沒有 JavaScript呈現引擎來呈現頁面的JavaScript。 這適用於大多數頁面,因為大多數靜態頁面不關心JavaScript呈現頁面,因為它們的內容已經可用。

可以做些什麼呢?

幸運的是,大型網站的抓取工具已經開始實施一種機制,使我們能夠抓取我們的JavaScript網站,但這需要我們對我們的網站實施更改

如果我們將hashPrefix更改為#! 而不是簡單的# ,那麼現代搜索引擎將改變請求使用_escaped_fragment_而不是#! 。 (使用HTML5模式,即我們有沒有哈希前綴的鏈接,我們可以通過查看我們後端的User Agent頭來實現相同的功能)。

也就是說,而不是來自正常瀏覽器的請求,如下所示:

http://www.ng-newsletter.com/#!/signup/page

搜索引擎將通過以下方式搜索頁面:

http://www.ng-newsletter.com/?_escaped_fragment_=/signup/page

我們可以使用ngRoute的內置方法來設置Angular應用程序的哈希前綴:

angular.module('myApp', [])
.config(['$location', function($location) {
  $location.hashPrefix('!');
}]);

而且,如果我們使用html5Mode ,我們需要使用元標記來實現它:

<meta name="fragment" content="!">

提醒一下,我們可以用$location服務設置html5Mode()

angular.module('myApp', [])
.config(['$location', 
function($location) {
  $location.html5Mode(true);
}]);

處理搜索引擎

我們有很多機會來確定如何處理將內容實際提供給搜索引擎的靜態HTML。 我們可以自己託管一個後端,我們可以使用服務為我們託管後端,我們可以使用代理來交付內容等。讓我們看看幾個選項:

自託管

我們可以編寫一個服務來處理如何使用無頭瀏覽器(例如​​phantomjs或zombiejs)來抓取我們自己的網站,並使用呈現的數據對網頁進行快照並將其存儲為HTML。 無論何時我們在搜索請求中看到查詢字符串?_escaped_fragment_ ,我們都可以通過僅提供靜態HTML快照來獲取頁面,而不是僅通過JS提供的預渲染頁面。 這就要求我們有一個後端,它在中間提供了帶有條件邏輯的頁面。 我們可以使用像prerender.io's後端作為起點來運行它自己。 當然,我們仍然需要處理代理和代碼段處理,但這是一個好的開始。

使用付費服務

獲取內容到搜索引擎的最簡單和最快速的方法是使用服務Bromboneseo.jsseo4ajaxprerender.io's是這些將為您提供上述內容呈現的好例子。 對於我們不想處理運行服務器/代理的時代來說,這是一個很好的選擇。 另外,它通常超級快。

有關Angular和SEO的更多信息,我們在http://www.ng-newsletter.com/posts/serious-angular-seo.html上寫了一篇關於它的廣泛教程我們在書中詳細介紹了它:關於AngularJS的完整書籍 。 在ng-book.com查看。


我找到了一個可以覆蓋大部分基地的優雅解決方案。 我最初here寫了它here並回答了另一個類似的引用它的問題。

僅供參考此解決方案還包括硬編碼後備標籤,以防抓取工具未找到Javascript。 我沒有明確地概述它,但值得一提的是,您應該激活HTML5模式以獲得適當的URL支持。

還要注意:這些不是完整的文件,只是那些相關的重要部分。 如果您需要幫助編寫可在別處找到的指令,服務等的樣板文件。 無論如何,這裡...

app.js

這是您為每條路線提供自定義元數據的地方(標題,說明等)

$routeProvider
   .when('/', {
       templateUrl: 'views/homepage.html',
       controller: 'HomepageCtrl',
       metadata: {
           title: 'The Base Page Title',
           description: 'The Base Page Description' }
   })
   .when('/about', {
       templateUrl: 'views/about.html',
       controller: 'AboutCtrl',
       metadata: {
           title: 'The About Page Title',
           description: 'The About Page Description' }
   })

metadata-service.js (服務)

設置自定義元數據選項或使用默認值作為後備。

var self = this;

// Set custom options or use provided fallback (default) options
self.loadMetadata = function(metadata) {
  self.title = document.title = metadata.title || 'Fallback Title';
  self.description = metadata.description || 'Fallback Description';
  self.url = metadata.url || $location.absUrl();
  self.image = metadata.image || 'fallbackimage.jpg';
  self.ogpType = metadata.ogpType || 'website';
  self.twitterCard = metadata.twitterCard || 'summary_large_image';
  self.twitterSite = metadata.twitterSite || '@fallback_handle';
};

// Route change handler, sets the route's defined metadata
$rootScope.$on('$routeChangeSuccess', function (event, newRoute) {
  self.loadMetadata(newRoute.metadata);
});

metaproperty.js (指令)

為視圖打包元數據服務結果。

return {
  restrict: 'A',
  scope: {
    metaproperty: '@'
  },
  link: function postLink(scope, element, attrs) {
    scope.default = element.attr('content');
    scope.metadata = metadataService;

    // Watch for metadata changes and set content
    scope.$watch('metadata', function (newVal, oldVal) {
      setContent(newVal);
    }, true);

    // Set the content attribute with new metadataService value or back to the default
    function setContent(metadata) {
      var content = metadata[scope.metaproperty] || scope.default;
      element.attr('content', content);
    }

    setContent(scope.metadata);
  }
};

的index.html

完成前面提到的硬編碼後備標籤,對於無法獲取任何Javascript的抓取工具。

<head>
  <title>Fallback Title</title>
  <meta name="description" metaproperty="description" content="Fallback Description">

  <!-- Open Graph Protocol Tags -->
  <meta property="og:url" content="fallbackurl.com" metaproperty="url">
  <meta property="og:title" content="Fallback Title" metaproperty="title">
  <meta property="og:description" content="Fallback Description" metaproperty="description">
  <meta property="og:type" content="website" metaproperty="ogpType">
  <meta property="og:image" content="fallbackimage.jpg" metaproperty="image">

  <!-- Twitter Card Tags -->
  <meta name="twitter:card" content="summary_large_image" metaproperty="twitterCard">
  <meta name="twitter:title" content="Fallback Title" metaproperty="title">
  <meta name="twitter:description" content="Fallback Description" metaproperty="description">
  <meta name="twitter:site" content="@fallback_handle" metaproperty="twitterSite">
  <meta name="twitter:image:src" content="fallbackimage.jpg" metaproperty="image">
</head>

這對大多數搜索引擎用例應該有很大的幫助。 如果您想為社交網絡抓取工具提供完全動態呈現(這對Javascript支持很有幫助),您仍然必須使用某些其他答案中提到的預呈現服務之一。

希望這可以幫助!


自這個問題提出後,事情發生了很大變化。 現在可以選擇讓Google將您的AngularJS網站編入索引。 我發現的最簡單的選擇是使用http://prerender.io免費服務,它將為您生成可追踪的頁面並將其提供給搜索引擎。 幾乎所有的服務器端網絡平台都支持它。 我最近開始使用它們,支持也非常好。

我與他們沒有任何關係,這是來自一位快樂的用戶。


抓取工具不需要富有特色的漂亮風格的gui,他們只想看到內容 ,所以你不需要給他們提供一個為人類構建的頁面的快照。

我的解決方案:為抓取工具提供抓取工具所需的內容

您必須考慮抓取工具需要什麼,並只給他。

提示不要背後。 只需使用相同的API添加一點服務器端Frontview即可


爬蟲(或漫遊器)被設計為抓取網頁的HTML內容,但由於AJAX操作異步數據抓取,這成為一個問題,因為它需要一段時間來呈現頁面並顯示動態內容。 同樣, AngularJS也使用異步模型,這為Google抓取工具帶來了問題。

一些開發人員使用真實數據創建基本的html頁面,並在爬網時從服務器端提供這些頁面。 我們可以在服務端渲染與PhantomJS相同的頁面,其中有_escaped_fragment_ (因為Google在我們的站點URL中查找#!然後將#!中的所有內容並將其添加到_escaped_fragment_查詢參數中)。 欲了解更多詳情,請閱讀此blog



用圖片解釋:

數據綁定需要映射

範圍中的引用不完全是模板中的引用。 當你數據綁定兩個對象時,你需要第三個接受第一個對象並修改其他對象。

在這裡,當你修改<input> ,你可以觸摸data-ref3 。 經典的數據綁定機制將改變data-ref4 。 那麼其他{{data}}表達式將如何移動?

事件導致$ digest()

Angular維護每個綁定的oldValuenewValue 。 在每個Angular事件之後 ,著名的$digest()循環將檢查WatchList以查看是否有更改。 這些Angular事件ng-clickng-change$http completed ...只要任何oldValuenewValue不同, $digest()就會循環。

在前面的圖片中,它會注意到data-ref1和data-ref2已經改變。

結論

這有點像雞蛋和雞肉。 你永遠不知道誰是首發的,但希望大部分時間都能按預期工作。

另一點是你可以很容易地理解內存和CPU的簡單綁定的影響。 希望台式機足夠處理這個問題。 手機並不那麼強大。





html5 angularjs seo search-engine google-search