701

我发现 AngularJS 应用程序有两个关于搜索引擎和 SEO 的问题:

1) 自定义标签会发生什么?搜索引擎会忽略这些标签中的全部内容吗?即假设我有

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

<h1>尽管在自定义标签内,但会被索引吗?


2) 有没有办法避免索引 {{}} 的搜索引擎按字面意思绑定?IE

<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)

  1. 通过 PushState,用户单击 PushState 链接,内容被 AJAX 处理。
  2. 通过直接点击 URL。

网站上的初始点击将涉及直接点击 URL。随着 PushState 更新 URL,随后的点击将简单地在内容中进行 AJAX。

爬虫从页面中获取链接,然后将它们添加到队列中以供以后处理。这意味着对于爬虫来说,服务器上的每次点击都是直接点击,它们不通过 Pushstate 导航。

Precomposition 将初始负载捆绑到来自服务器的第一个响应中,可能作为 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

谷歌已经能够解析 JavaScript 有一段时间了,这就是他们最初开发 Chrome 的原因,作为谷歌蜘蛛的全功能无头浏览器。如果链接具有有效的 href 属性,则可以将新 URL 编入索引。没有什么可做的了。

如果单击链接另外触发了 pushState 调用,则用户可以通过 PushState 导航站点。

PushState URL 的搜索引擎支持

Google 和 Bing 目前支持 PushState。

谷歌

这是 Matt Cutts 对 Paul Irish 关于 PushState for SEO 的问题的回应:

http://youtu.be/yiAF9VdvRPw

以下是 Google 宣布对蜘蛛的全面 JavaScript 支持:

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

结果是 Google 支持 PushState 并将索引 PushState URL。

另请参阅 Google 网站管理员工具的 fetch as Googlebot。你会看到你的 JavaScript(包括 Angular)被执行了。

必应

以下是 Bing 于 2013 年 3 月宣布支持漂亮的 PushState URL:

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="!">

Google 不会以这种形式将它们编入索引,而是会从 _escaped_fragments_ URL 中提取站点的静态版本并将其编入索引。

Pushstate URL 看起来像任何普通的 URL:

domain.com/path/to/resource

不同之处在于 Angular 通过拦截对在 JavaScript 中处理它的 document.location 的更改来为您处理它们。

如果您想使用 PushState URL(并且您可能会这样做),请删除所有旧的哈希样式 URL 和元标记,并在您的配置块中简单地启用 HTML5 模式。

测试您的网站

谷歌网站管理员工具现在包含一个工具,它允许您以谷歌的身份获取 URL,并在谷歌呈现它时呈现 JavaScript。

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

在 Angular 中生成 PushState URL

要在 Angular 中生成真实的 URL,而不是带 # 前缀的 URL,请在 $locationProvider 对象上设置 HTML5 模式。

$locationProvider.html5Mode(true);

服务器端

由于您使用的是真实 URL,因此您需要确保服务器为所有有效 URL 提供相同的模板(加上一些预先组合的内容)。您如何执行此操作将根据您的服务器架构而有所不同。

网站地图

您的应用可能会使用不寻常的导航形式,例如悬停或滚动。为确保 Google 能够驱动您的应用,我可能会建议创建一个站点地图,即您的应用响应的所有 url 的简单列表。您可以将其放置在默认位置(/sitemap 或 /sitemap.xml),或使用网站管理员工具告诉 Google。

无论如何,拥有一个站点地图是个好主意。

浏览器支持

Pushstate 在 IE10 中工作。在旧版浏览器中,Angular 会自动回退到哈希样式的 URL

演示页面

以下内容使用带有预合成的 pushstate URL 呈现:

http://html5.gingerhost.com/london

可以验证,在此链接中,内容已编入索引并出现在 Google 中。

服务 404 和 301 标头状态代码

因为搜索引擎总是会针对每个请求访问您的服务器,所以您可以从您的服务器提供标头状态代码并期望 Google 看到它们。

于 2014-04-23T13:10:39.423 回答
407

2014 年 5 月更新

Google 抓取工具现在执行 javascript - 您可以使用Google 网站管理员工具来更好地了解 Google 如何呈现您的网站。

原始答案
如果您想针对搜索引擎优化您的应用程序,不幸的是,没有办法向爬虫提供预渲染版本。您可以在此处阅读有关 Google 对 ajax 和 javascript-heavy 网站的建议的更多信息。

如果这是一个选项,我建议阅读这篇文章,了解如何使用服务器端渲染为 Angular 进行 SEO。

我不确定爬虫在遇到自定义标签时会做什么。

于 2012-11-23T00:17:30.597 回答
108

让我们确定一下 AngularJS 和 SEO

Google、Yahoo、Bing 和其他搜索引擎使用传统爬虫以传统方式爬取网络。他们运行机器人来抓取网页上的 HTML,并在此过程中收集信息。他们保留有趣的单词并寻找其他页面的其他链接(这些链接、它们的数量和它们的数量与 SEO 一起发挥作用)。

那么为什么搜索引擎不处理 javascript 网站呢?

答案与搜索引擎机器人通过无头浏览器工作这一事实有关,而且它们通常没有javascript 渲染引擎来渲染页面的 javascript。这适用于大多数页面,因为大多数静态页面不关心 JavaScript 呈现其页面,因为它们的内容已经可用。

可以做些什么呢?

幸运的是,大型网站的爬虫已经开始实现一种机制,使我们的 JavaScript 网站可被爬取,但这需要我们对我们的网站进行更改

如果我们将我们hashPrefix的 is#!而不是简单地更改为#,那么现代搜索引擎会将请求更改为使用_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_在搜索请求中看到查询字符串时,我们可以交付我们为页面拍摄的静态 HTML 快照,而不是仅通过 JS 的预渲染页面。这要求我们有一个后端来交付我们的页面,中间有条件逻辑。我们可以使用prerender.io 的后端之类的东西作为起点来自己运行它。当然,我们仍然需要处理代理和片段处理,但这是一个好的开始。

有偿服务

将内容输入搜索引擎的最简单和最快的方法是使用服务Bromboneseo.jsseo4ajaxprerender.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免费服务,该服务将为您生成 crwalable 页面并将其提供给搜索引擎。几乎所有服务器端 Web 平台都支持它。我最近开始使用它们,支持也很好。

我与他们没有任何从属关系,这是来自一个快乐的用户。

于 2013-11-26T16:25:12.873 回答
9

Angular 自己的网站为搜索引擎提供简化的内容:http ://docs.angularjs.org/?_escaped_fragment_=/tutorial/step_09

假设您的 Angular 应用正在使用 Node.js/Express 驱动的 JSON api,例如/api/path/to/resource. 也许您可以使用?_escaped_fragment_to重定向任何请求/api/path/to/resource.html,并使用内容协商来呈现内容的 HTML 模板,而不是返回 JSON 数据。

唯一的问题是,您的 Angular 路由需要与您的 REST API 1:1 匹配。

编辑:我意识到这有可能真正混淆你的 REST api,我不建议在非常简单的用例之外这样做,因为它可能很自然。

相反,您可以为机器人友好的内容使用一组完全不同的路由和控制器。但是随后您将在 Node/Express 中复制所有 AngularJS 路由和控制器。

我已经决定使用无头浏览器生成快照,尽管我觉得这有点不太理想。

于 2013-11-21T01:25:32.640 回答
8

可以在这里找到一个好的做法:

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

于 2014-03-16T13:56:49.897 回答
7

截至目前,谷歌已经改变了他们的 AJAX 抓取提议。

时代变了。今天,只要您不阻止 Googlebot 抓取您的 JavaScript 或 CSS 文件,我们通常能够像现代浏览器一样呈现和理解您的网页。

tl;dr:[Google] 不再推荐 2009 年提出的 AJAX 抓取提案 [Google]。

于 2015-10-15T10:00:51.457 回答
6

谷歌的 Crawlable Ajax Spec,正如其他答案中所引用的,基本上就是答案。

如果您对其他搜索引擎和社交机器人如何处理相同的问题感兴趣,我在这里写了最先进的技术:http: //blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification.html

我为https://ajaxsnapshots.com工作,该公司将 Crawlable Ajax 规范作为服务实施 - 该报告中的信息基于我们日志中的观察。

于 2014-01-21T22:53:28.160 回答
4

我找到了一个优雅的解决方案,可以涵盖您的大部分基础。我最初在这里写过它,并在此处回答了另一个类似的 StackOverflow 问题,它引用了它。

仅供参考,此解决方案还包括硬编码的后备标签,以防爬虫未获取 Javascript。我没有明确概述它,但值得一提的是,您应该激活 HTML5 模式以获得正确的 URL 支持。

另请注意:这些不是完整的文件,只是相关文件的重要部分。如果您需要帮助编写可以在其他地方找到的指令、服务等的样板。无论如何,这里...

应用程序.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' }
   })

元数据-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);
  }
};

索引.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 回答
2

使用 PreRender 之类的东西,它可以制作您网站的静态页面,以便搜索引擎对其进行索引。

在这里您可以找到可用的平台:https ://prerender.io/documentation/install-middleware#asp-net

于 2015-02-23T10:31:52.657 回答
2

使用 Angular Universal,您可以为应用程序生成看起来像完整应用程序的登录页面,然后在其后面加载您的 Angular 应用程序。
Angular Universal 在服务器端生成纯 HTML 意味着无 javascript 页面,并无延迟地将它们提供给用户。因此,您可以处理任何爬虫、机器人和用户(cpu 和网络速度已经很低)。然后您可以通过链接/按钮将它们重定向到已经加载的实际 angular 应用程序。官方网站推荐此解决方案。-有关 SEO 和 Angular Universal 的更多信息-

于 2017-05-16T22:30:26.133 回答
1

爬虫(或机器人)旨在爬取网页的 HTML 内容,但由于异步数据获取的 AJAX 操作,这成为一个问题,因为它需要一些时间来呈现页面并在其上显示动态内容。同样,AngularJS也使用异步模型,这会给 Google 爬虫带来问题。

一些开发人员使用真实数据创建基本的 html 页面,并在抓取时从服务器端提供这些页面。PhantomJS我们可以在服务端呈现相同的页面_escaped_fragment_(因为谷歌#!在我们的网站 url 中查找,然后获取之后的所有内容#!并将其添加到_escaped_fragment_查询参数中)。有关更多详细信息,请阅读此博客

于 2015-10-05T12:00:29.677 回答
0

爬虫不需要功能丰富、风格漂亮的 gui,它们只想查看内容,因此您不需要向它们提供为人类构建的页面的快照。

我的解决方案:为爬虫提供爬虫想要的东西

你必须想好爬虫想要什么,然后只给他那个。

提示不要弄乱背部。只需使用相同的 API 添加一点服务器端的前视图

于 2014-02-12T07:26:21.777 回答