web-dev-qa-db-ja.com

検索エンジンはAngularJSアプリケーションをどのように扱いますか?

検索エンジンとSEOに関してAngularJSアプリケーションには2つの問題があります。

1)カスタムタグはどうなりますか?検索エンジンはこれらのタグ内のコンテンツ全体を無視しますか?すなわち私が持っているとします

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

カスタムタグの中にあっても<h1>はインデックス付けされますか?


2)インデックス化の検索エンジンが文字通りバインドするのを避ける方法はありますか?すなわち.

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

私は私が好きなことができることを知っています

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

しかし、クローラーに実際にタイトルを「見せる」ようにしたい場合はどうすればよいですか。サーバーサイドレンダリングは唯一の解決策ですか?

692
luisfarzati

2014年5月に更新

Googleクローラ 現在はjavascriptを実行します - あなたのサイトがGoogleによってどのようにレンダリングされるかを理解するために Googleウェブマスターツール を使うことができます。

元の答え
検索エンジン用にアプリを最適化したい場合は、残念ながらクローラに事前にレンダリングされたバージョンを提供する方法はありません。あなたはajaxとjavascriptが多いサイトに対するGoogleの勧告についてもっと読むことができます here

これが選択肢であるならば、私は この記事 を読んでサーバーサイドレンダリングでAngularのSEOを行う方法についてお勧めします。

クローラがカスタムタグに遭遇したときの動作がわからない。

402
joakimbl

PushStateと事前合成を使う

これを行うための現在(2015年)の方法は、JavaScriptのpushStateメソッドを使用することです。

PushStateは、ページを再ロードせずにトップブラウザバーのURLを変更します。タブを含むページがあるとしましょう。タブはコンテンツの表示と非表示を切り替えます。コンテンツはAJAXを使用するか、単にdisplay:noneとdisplay:blockを設定することで動的に挿入され、正しいタブコンテンツが表示および非表示になります。

タブがクリックされたら、pushStateを使用してアドレスバーのURLを更新します。ページがレンダリングされたら、アドレスバーの値を使用して表示するタブを決定します。 Angularルーティングは自動的にこれを行います。

前処理

PushState Single Page App(SPA)を使用する方法は2つあります。

  1. ユーザーがPushStateリンクをクリックするとコンテンツがAJAXされるPushStateを介して。
  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を解析することができました。Googleスパイダーのためのフル機能のヘッドレスブラウザとして機能するために、彼らが最初にChromeを開発したのはそのためです。リンクに有効なhref属性がある場合は、新しいURLにインデックスを付けることができます。他にやることは何もありません。

さらにリンクをクリックするとpushState呼び出しがトリガーされると、ユーザーはPushStateを介してサイトをナビゲートできます。

PushState URLの検索エンジンサポート

PushStateは現在GoogleとBingでサポートされています。

グーグル

SEOのためのPushStateについてのPaul Irishの質問に答えているMatt Cuttsです。

http://youtu.be/yiAF9VdvRPw

Googleがクモの完全なJavaScriptサポートを発表しました。

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

その結果、GoogleはPushStateをサポートし、PushStateのURLにインデックスを付けます。

グーグルウェブマスターツールがグーグルボットとして入手することも参照のこと。あなたはあなたのJavaScript(Angularを含む)が実行されるのを見るでしょう。

ビング

2013年3月付けのかわいいPushState URLに対するBingのサポートの発表は、次のとおりです。

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

HashBangs#を使わないでください。

HashbangのURLは、開発者が事前にレンダリングされたバージョンのサイトを特別な場所に提供することを要求する醜い一時停止でした。まだ機能しますが、使用する必要はありません。

HashbangのURLは次のようになります。

domain.com/#!path/to/resource

これは、このようなメタタグとペアになります。

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

グーグルはそれらをこの形式で索引付けするのではなく、代わりに_escaped_fragments_ URLから静的バージョンのサイトを引き出してそれを索引付けします。

プッシュステートURLは、通常のURLのように見えます。

domain.com/path/to/resource

違いは、AngularがJavaScriptでdocument.locationへの変更をインターセプトすることによってそれらを処理することです。

もしあなたがPushState URLを使いたいなら(そしておそらくあなたはそうするでしょう)、古いハッシュスタイルのURLとメタタグをすべて取り除き、あなたの設定ブロックでHTML5モードを有効にしてください。

サイトをテストする

Googleウェブマスターツールには、URLをGoogleとして取得したり、GoogleがレンダリングしたときにJavaScriptをレンダリングしたりできるツールが含まれるようになりました。

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

AngularでPushState URLを生成する

接頭辞を付けずにAngularで実際のURLを生成するには、$ locationProviderオブジェクトにHTML5モードを設定します。

$locationProvider.html5Mode(true);

サーバ側

実際のURLを使用しているので、すべての有効なURLに対して同じテンプレート(およびいくつかの事前作成されたコンテンツ)がサーバーから出荷されていることを確認する必要があります。これを行う方法は、サーバーのアーキテクチャによって異なります。

サイトマップ

あなたのアプリは、ホバーやスクロールなどの変わった形のナビゲーションを使うかもしれません。 Googleがあなたのアプリを動かすことができることを確実にするために、私はおそらくあなたのアプリが応答するすべてのURLの単純なリストであるサイトマップを作成することを勧めます。これをデフォルトの場所(/ sitemapまたは/sitemap.xml)に配置するか、ウェブマスターツールを使用してGoogleに通知することができます。

とにかくサイトマップを用意するのは良い考えです。

ブラウザサポート

プッシュステートはIE10で動作します。古いブラウザでは、Angularは自動的にハッシュスタイルのURLに戻ります。

デモページ

次のコンテンツは、前処理付きのプッシュステートURLを使用してレンダリングされます。

http://html5.gingerhost.com/london

確認できるように、 このリンク で、コンテンツにインデックスが付けられ、Googleに表示されます。

404および301ヘッダーステータスコードの配信

検索エンジンはリクエストごとに常にサーバーにアクセスするため、サーバーからヘッダーステータスコードを送信してGoogleに表示させることができます。

470
superluminary

AngularJSとSEOについて明確にしましょう

Google、Yahoo、Bing、およびその他の検索エンジンは、従来のクローラーを使用して従来の方法でWebをクロールします。彼らはロボットを実行し、Webページ上のHTMLをクロールし、途中で情報を収集します。彼らは面白い言葉を保持し、他のページへの他のリンクを探します(これらのリンク、それらの量、およびそれらの数はSEOに関係します)。

では、なぜ検索エンジンはjavascriptサイトを扱わないのですか?

答えは、検索エンジンロボットがヘッドレスブラウザーを介して動作し、ほとんどの場合、ページのjavascriptをレンダリングするJavaScriptレンダリングエンジンをnot持っているという事実に関係しています。ほとんどの静的ページはコンテンツが既に利用可能であるため、ほとんどのページでJavaScriptがページをレンダリングすることを考慮していないため、これはほとんどのページで機能します。

それについて何ができますか?

幸いなことに、大規模なサイトのクローラーは、JavaScriptサイトをクロール可能にするメカニズムを実装し始めましたが、サイトに変更を実装する必要があります

hashPrefixを単に#!ではなく#に変更すると、最新の検索エンジンは_escaped_fragment_ではなく#!を使用するようにリクエストを変更します。 (HTML5モード、つまりハッシュプレフィックスのないリンクがある場合、バックエンドのUser Agentヘッダーを調べることでこの同じ機能を実装できます)。

つまり、次のような通常のブラウザからのリクエストの代わりに:

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

検索エンジンは、次を使用してページを検索します。

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

Angularアプリのハッシュプレフィックスは、ngRouteの組み込みメソッドを使用して設定できます。

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

そして、html5Modeを使用している場合、メタタグを使用してこれを実装する必要があります。

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

html5Mode()$locationサービスで設定できます:

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

検索エンジンの取り扱い

静的HTMLとして検索エンジンにコンテンツを実際に配信する方法を決定する多くの機会があります。バックエンドを自分でホストしたり、サービスを使用してバックエンドをホストしたり、プロキシを使用してコンテンツを配信したりすることができます。いくつかのオプションを見てみましょう。

自己ホスト

Phantomjsやzombiejsなどのヘッドレスブラウザーを使用してサイトのクロールを処理するサービスを記述し、レンダリングされたデータを含むページのスナップショットを取得してHTMLとして保存できます。検索リクエストにクエリ文字列?_escaped_fragment_が表示されるたびに、事前レンダリングされたページの代わりに、JSのみを使用してページの静的なHTMLスナップショットを配信できます。これには、途中で条件付きロジックを使用してページを配信するバックエンドが必要です。 prerender.io's バックエンドのようなものを、これを自分で実行するための出発点として使用できます。もちろん、プロキシ処理とスニペット処理を引き続き行う必要がありますが、良いスタートです。

有料サービス付き

コンテンツを検索エンジンに取り込む最も簡単で最速の方法は、サービスを使用することです Bromboneseo.jsseo4ajax 、および prerender.io は、上記のコンテンツレンダリングをホストするこれらの良い例です。これは、サーバー/プロキシの実行に対処したくない場合に適したオプションです。また、通常は非常に高速です。

AngularおよびSEOの詳細については、 http://www.ng-newsletter.com/posts/serious-angular-seo.html で詳細なチュートリアルを作成しました。 and本でさらに詳しく説明しましたng-book:AngularJSの完全な本ng-book.com で確認してください。

106
auser

あなたは本当にmooブログの年にSEOにやさしいAngularJSサイトを構築することに関するチュートリアルをチェックするべきです。彼はAngularのドキュメントで概説されているすべてのステップをあなたに案内します。 http://www.yearofmoo.com/2012/11/angularjs-and-seo.html

この技術を使用して、検索エンジンはカスタムタグの代わりに拡張されたHTMLを見ます。

56
Brad Green

これは劇的に変わりました。

http://searchengineland.com/bing-offers-recommendations-for-seo-friendly-ajax-suggest-html5-pushstate-152946

使用する場合:$ locationProvider.html5Mode(true);あなたは設定されています。

これ以上レンダリングページはありません。

41
user3330270

この質問をしてから、状況はかなり変わりました。 GoogleがAngularJSサイトをインデックスに登録するためのオプションがあります。私が見つけた最も簡単なオプションはhttp://prerender.iofreeサービスを使うことでした。ほとんどすべてのサーバーサイドWebプラットフォームでサポートされています。私は最近それらを使い始めました、そしてサポートも優れています。

私は彼らと提携していません、これは幸せなユーザーから来ています。

17
Ketan

Angular自身のWebサイトは、検索エンジンに簡略化されたコンテンツを提供します。 http://docs.angularjs.org/?_escaped_fragment_=/tutorial/step_09

Angularアプリが、/api/path/to/resourceのようにNode.js/Express駆動のJSON APIを使用しているとします。 JSONデータを返すのではなく、コンテンツのHTMLテンプレートをレンダリングするために、?_escaped_fragment_のリクエストを/api/path/to/resource.htmlにリダイレクトし、 コンテンツネゴシエーション を使用することができます。

唯一のことは、あなたのAngularルートがあなたのREST AP​​Iと1:1でマッチする必要があるということです。

_ edit _ :これはあなたのREST apiを本当に曖昧にする可能性があることに気づいています。自然にフィットします。

代わりに、あなたのロボットにやさしいコンテンツのために全く異なるルートとコントローラーのセットを使うことができます。しかし、その後、Node/Express内のAngularJSのルートとコントローラをすべて複製しています。

ヘッドレスブラウザを使ってスナップショットを生成することにしました。

9
Kevin C.
8
pixparker

現在、GoogleはAJAXクロールの提案を変更しました。

時が変わった。今日、GooglebotがあなたのJavaScriptやCSSファイルをクロールするのを妨げていない限り、私たちはあなたのウェブページを現代のブラウザのようにレンダリングし理解することができます。

tl; dr:[Google]は2009年に作成されたAJAXクロールの提案[Google]を推奨しなくなりました。

7
Thor

ここで他の答えで参照されるようにグーグルのクロール可能なAjax仕様は基本的に答えです。

他のサーチエンジンやソーシャルボットが同じ問題にどのように対処しているかに興味があるなら、私がここで最先端を書いた: http://blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification .html

私は https://ajaxsnapshots.com 、Crawlable Ajax Specをサービスとして実装している会社で働いています - そのレポートの情報は私たちのログからの観察に基づいています。

6
Robert AJS

私はあなたの拠点のほとんどをカバーするような優雅な解決策を見つけました。私は最初にそれについて書きました ここ そしてそれを参照しているもう一つの同様のStackOverflow質問 ここ に答えました。

参考までに、このソリューションには、Javascriptがクローラーによって検出されない場合のためのハードコードされたフォールバックタグも含まれています。私は明示的には概説していませんが、適切なURLサポートのためにはHTML 5モードを有効にするべきであることを言及する価値があります。

また、注意してください:これらは完全なファイルではなく、関連するそれらの重要な部分だけです。他の場所にあるディレクティブ、サービスなどの定型文を書くのに手助けが必要な場合。とにかく、ここに行きます...

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をサポートしている場合)に完全に動的なレンダリングが必要な場合は、他の回答で説明しているプレレンダリングサービスのいずれかを使用する必要があります。

お役に立てれば!

4
Andrew

Angular Universalを使用すると、完全なアプリのように見えるアプリのランディングページを生成し、その背後に自分のAngularアプリを読み込むことができます。
Angular Universalは、サーバーサイドに純粋なHTMLの手段なしのJavaScriptページを生成し、それらを遅延することなくユーザーに提供します。だからあなたは(すでに低いCPUとネットワーク速度を持っている)任意のクローラ、ボットとユーザーに対処することができます。あなたはそれの後ろにすでにロードされているあなたの実際の角度のアプリにリンク/ボタンでそれらをリダイレクトできます。この解決策は公式サイトによって推奨されています。 - SEOとAngular Universalに関する詳細情報 /

2
erginduran

PreRenderのようなものを使用してください、それはあなたのサイトの静的なページを作るので検索エンジンがそれを索引付けすることができます。

ここであなたはそれが利用可能なプラットフォームについて調べることができます: https://prerender.io/documentation/install-middleware#asp-net

2
NicoJuicy

クローラ(またはボット)はWebページのHTMLコンテンツをクロールするように設計されていますが、非同期データフェッチのためのAJAX操作のため、ページをレンダリングして動的コンテンツを表示するのに時間がかかるため、問題になりました。同様に、AngularJSも非同期モデルを使用します。これはGoogleクローラーに問題を引き起こします。

実際のデータで基本的なHTMLページを作成し、クロール時にサーバー側からこれらのページを提供する開発者もいます。 _escaped_fragment_を持つサーバー側でPhantomJSを使用して同じページをレンダリングすることができます(Googleでは、サイトのURLで#!を検索し、#!の後にあるすべてのものを_escaped_fragment_クエリパラメータに追加しています)。詳しくは blog を読んでください。

1
Rubi saini

クローラは豊富な機能を備えたかわいいスタイルのGUIを必要としません。コンテンツを表示するだけです したがって、人間向けに作成されたページのスナップショットを提供する必要はありません。

私の解決策:/ クローラが欲しいものをクローラに渡す

クローラーが何を望んでいるのかを考えて、それだけを彼に伝えなければなりません。

ちょっと後ろを台無しにしないでください。同じAPIを使用して、小さなサーバーサイドの正面図を追加するだけです。

0
pykiss