701

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

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

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

カスタムタグ内にあるに<h1>もかかわらず、インデックスに登録されますか?


2) 検索エンジンによる {{}} バインドの文字通りのインデックス作成を回避する方法はありますか? すなわち

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

私は次のようなことができることを知っています

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

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

4

15 に答える 15

471

PushState と Precomposition を使用する

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

PushState は、ページをリロードせずに上部のブラウザー バーの URL を変更します。タブを含むページがあるとします。タブはコンテンツを非表示および表示し、AJAX を使用するか、display:none および display:block を設定して正しいタブ コンテンツを非表示および表示することにより、コンテンツが動的に挿入されます。

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

前構成

PushState シングル ページ アプリ (SPA) をヒットするには 2 つの方法があります。

  1. ユーザーが 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 を解析できるようになってからしばらく経ちました。Google スパイダー用のフル機能のヘッドレス ブラウザとして機能する Chrome を最初に開発したのはそのためです。リンクに有効な href 属性がある場合、新しい URL をインデックス化できます。もう何もする必要はありません。

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

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

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

グーグル

以下は、SEO のための PushState に関する Paul Irish の質問に対する Matt Cutts の回答です。

http://youtu.be/yiAF9VdvRPw

スパイダーの完全な JavaScript サポートを発表した Google は次のとおりです。

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

つまり、Google は PushState をサポートしており、PushState URL をインデックスに登録します。

Google ウェブマスター ツールの fetch as Googlebot も参照してください。JavaScript (Angular を含む) が実行されていることがわかります。

ビング

以下は、2013 年 3 月付けの Bing によるプリティ PushState URL のサポートの発表です。

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

HashBangs を使用しないでください #!

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

ハッシュバン URL は次のようになります。

domain.com/#!path/to/resource

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

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

Google はこの形式でそれらをインデックスに登録しませんが、代わりに _escaped_fragments_ URL からサイトの静的バージョンを取得してインデックスに登録します。

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

domain.com/path/to/resource

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

PushState URL を使用したい場合 (おそらく使用している場合)、古いハッシュ スタイルの URL とメタタグをすべて削除し、構成ブロックで HTML5 モードを有効にするだけです。

サイトのテスト

Google ウェブマスター ツールには、Google として URL をフェッチし、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 に伝えることができます。

とにかくサイトマップを持っていることをお勧めします。

ブラウザのサポート

Pushstate は IE10 で動作します。古いブラウザーでは、Angular は自動的にハッシュ スタイルの URL にフォールバックします。

デモページ

次のコンテンツは、構成済みのプッシュステート URL を使用してレンダリングされます。

http://html5.gingerhost.com/london

確認できるように、このリンクでは、コンテンツがインデックスに登録され、Google に表示されています。

404 および 301 ヘッダー ステータス コードの提供

検索エンジンはすべてのリクエストに対して常にサーバーにアクセスするため、サーバーからヘッダー ステータス コードを提供し、Google がそれらを確認することを期待できます。

于 2014-04-23T13:10:39.423 に答える
108

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

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

では、なぜ検索エンジンは JavaScript サイトを扱わないのでしょうか?

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

それについて何ができるでしょうか?

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

ourhashPrefix#!単に の代わりに に変更すると#、最新の検索エンジンはリクエストを_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 として検索エンジンに実際に配信する方法を決定する機会はたくさんあります。自分でバックエンドをホストすることも、サービスを使用してバックエンドをホストすることも、プロキシを使用してコンテンツを配信することもできます。いくつかのオプションを見てみましょう。

自己ホスト型

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

有料サービスで

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

Angular と SEO の詳細については、http: //www.ng-newsletter.com/posts/serious-angular-seo.html で広範なチュートリアルを作成し、本 ng-bookでさらに詳しく説明していますAngularJS の完全な本ng-book.comでチェックしてください。

于 2013-12-24T20:05:37.603 に答える
58

Moo ブログの年の SEO に適した AngularJS サイトの構築に関するチュートリアルを実際に確認する必要があります。彼は、Angular のドキュメントで概説されているすべての手順を順を追って説明します。http://www.yearofmoo.com/2012/11/angularjs-and-seo.html

この手法を使用すると、検索エンジンはカスタム タグではなく、展開された HTML を認識します。

于 2012-11-27T21:55:03.177 に答える
42

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

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

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

ページのレンダリングはもうありません。

于 2014-02-19T22:35:32.907 に答える
17

この質問が出されてから、状況はかなり変わりました。Google が AngularJS サイトをインデックスに登録できるようにするオプションが追加されました。私が見つけた最も簡単なオプションは、http://prerender.io の無料サービスを使用することでしたこれは、クロール可能なページを生成して検索エンジンに提供します。これは、ほぼすべてのサーバー側 Web プラットフォームでサポートされています。私は最近それらを使い始めましたが、サポートも優れています。

私は彼らとは何の関係もありません。これは幸せなユーザーからのものです。

于 2013-11-26T16:25:12.873 に答える
9

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

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

唯一のことは、Angular ルートが REST API と 1:1 で一致する必要があるということです。

編集: これは REST API を本当に混乱させる可能性があることを認識しており、自然に適合する可能性のある非常に単純なユースケース以外で行うことはお勧めしません。

代わりに、ロボットに適したコンテンツにまったく異なるルートとコントローラーのセットを使用できます。しかし、AngularJS のすべてのルートとコントローラーを Node/Express に複製しています。

私はヘッドレス ブラウザでスナップショットを生成することにしましたが、それは理想的とは言えません。

于 2013-11-21T01:25:32.640 に答える
4

あなたのベースのほとんどをカバーするエレガントなソリューションを見つけました。私は最初にそれについてここに書き、それを参照する別の同様の StackOverflow の質問に答えました。

参考までに、このソリューションには、Javascript がクローラーによって検出されない場合に備えて、ハードコーディングされたフォールバック タグも含まれています。明示的には説明していませんが、適切な URL サポートのために HTML5 モードを有効にする必要があることに注意してください。

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

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

お役に立てれば!

于 2015-12-15T16:56:51.227 に答える
0

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

私の解決策:クローラーが望むものをクローラーに与えるには

クローラーが何を望んでいるのかを考え、それだけを与える必要があります。

ヒント 背面を台無しにしないでください。同じ API を使用して、サーバー側のフロントビューを少し追加するだけです

于 2014-02-12T07:26:21.777 に答える