search引擎如何处理AngularJS应用程序?

我看到有关search引擎和search引擎优化的AngularJS应用程序的两个问题:

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

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

尽pipe在自定义标签内,会不会索引<h1>

2)有没有办法避免索引{{}}的search引擎从字面上绑定? 即

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

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

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

但是如果我想让爬虫“看见”标题呢? 服务器端是唯一的解决scheme吗?

2014年5月更新

Google抓取工具现在可以执行JavaScript了 – 您可以使用Google网站站长工具来更好地了解您的网站是如何由Google呈现的。

原始答案
如果你想优化你的search引擎的应用程序,不幸的是没有办法提供给履带式的预渲染版本。 您可以在这里阅读更多关于Google对ajax和javascript-heavy网站的build议。

如果这是一个选项,我build议阅读这篇文章关于如何做服务器端渲染Angular的SEO。

我不确定抓取工具在遇到自定义标记时会做什么。

使用PushState和预分解

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

PushState更改顶部浏览器栏中的URL,而无需重新加载页面。 假设您有一个包含选项卡的页面。 选项卡隐藏和显示内容,并且dynamic地插入内容,可以使用AJAX或通过简单地设置display:none和display:block来隐藏和显示正确的选项卡内容。

点击标签后,使用pushState更新地址栏中的url。 当页面呈现时,使用地址栏中的值来确定显示哪个标签。 angular度路由将自动为您完成。

Precomposition

有两种方法来打PushState单页应用程序(SPA)

  1. 通过PushState,用户点击一个PushState链接,并且内容被AJAX引入。
  2. 直接点击URL。

网站上的最初命中将涉及直接击中URL。 随着PushState更新URL,随后的内容将仅仅是内容中的AJAX。

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

预整合将初始负载捆绑到来自服务器的第一个响应中,可能是一个JSON对象。 这允许search引擎在不执行AJAX调用的情况下呈现页面。

有一些证据表明Google可能不会执行AJAX请求。 更多关于这里:

http://www.analog-ni.co/precomposing-a-spa-may-become-the-holy-grail-to-seo

search引擎可以读取和执行JavaScript

Google已经能够parsingJavaScript一段时间了,这就是为什么他们最初开发Chrome的原因,是为了充当Google spider的全function无头浏览器。 如果链接具有有效的href属性,则可以对新的URL进行索引。 没有什么可做的了

如果另外点击一个链接触发一个pushState调用,那么站点可以由用户通过PushState导航。

search引擎支持PushStateurl

PushState目前由Google和Bing支持。

谷歌

这是马特卡茨回应保罗爱尔兰的PushState的问题:

http://youtu.be/yiAF9VdvRPw

下面是Google宣布对蜘蛛的完整JavaScript支持:

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

结果是Google支持PushState,并且将对PushState URL进行索引。

另请参阅Google网站pipe理员工具的Googlebot抓取方式。 你会看到你的JavaScript(包括Angular)被执行。

这是Bing宣布支持2013年3月发布的PushStateurl:

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

不要使用HashBangs#!

哈希邦网站是一个丑陋的权宜之计,要求开发者在特定的位置提供预先渲染的网站版本。 他们还在工作,但你不需要使用它们。

Hashbangurl如下所示:

domain.com/#!path/to/resource

这将与这样一个元标签配对:

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

Google不会以这种forms将它们编入索引,而是会从_escaped_fragments_url中提取该网站的静态版本并将其编入索引。

推送状态的URL看起来像任何普通的URL:

domain.com/path/to/resource

不同之处在于Angular通过拦截对JavaScript进行处理的document.location的改变来处理它们。

如果你想使用PushState的URL(你可能会这样做)拿出所有旧的哈希样式的URL和元标记,只需在你的configuration块启用HTML5模式。

testing你的网站

谷歌网站pipe理员工具现在包含一个工具,它可以让你获取一个url为谷歌,并呈现JavaScript的谷歌呈现它。

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

在Angular中生成PushState URL

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

 $locationProvider.html5Mode(true); 

服务器端

由于您使用的是真实url,因此您需要确保服务器为所有有效的url提供相同的模板(以及一些预先制作的内容)。 你如何做这将取决于你的服务器体系结构。

网站地图

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

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

浏览器支持

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

演示页面

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

http://html5.gingerhost.com/london

可以validation,在这个链接 ,内容被索引,并出现在谷歌。

服务404和301标题状态代码

由于search引擎总是会针对您的服务器提出请求,因此您可以从服务器提供标题状态代码,并希望Google能够看到它们。

让我们来看看AngularJS和SEO

Google,Yahoo,Bing和其他search引擎使用传统的抓取工具以传统方式抓取网页。 他们运行机器人抓取网页上的HTML,沿途收集信息。 他们保持有趣的话,并寻find其他网页的其他链接(这些链接,他们的数量和他们的数量发挥与search引擎优化)。

那么为什么不search引擎处理JavaScript网站?

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

可以做些什么呢?

幸运的是,大型网站的抓取工具已经开始实施一种机制,使我们能够抓取我们的JavaScript网站,但这需要我们对我们的网站进行更改

如果我们改变我们的hashPrefix#! 那么现代search引擎会改变请求来使用_escaped_fragment_而不是#! 。 (使用HTML5模式,即我们有没有哈希前缀的链接,我们可以通过查看我们后端的User Agent头来实现这个相同的function)。

也就是说,而不是来自正常浏览器的请求,如下所示:

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

search引擎将search页面:

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); }]); 

处理search引擎

我们有很多机会来决定如何处理实际上将内容作为静态HTML提供给search引擎。 我们可以自己托pipe一个后端,我们可以使用一个服务为我们托pipe一个后端,我们可以使用一个代理来传递内容,等等。让我们来看几个选项:

自托pipe

我们可以编写一个服务来处理如何使用无头浏览器(例如phantomjs或zombiejs)来抓取我们自己的网站,并使用呈现的数据对网页进行快照并将其存储为HTML。 每当我们在search请求中看到查询string?_escaped_fragment_时,我们就可以通过JS提供页面的静态HTML快照,而不是预渲染的页面。 这要求我们有一个后端,在中间提供我们的页面与条件逻辑。 我们可以使用像prerender.io的后端作为起点来运行它自己。 当然,我们仍然需要处理代理和代码段处理,但这是一个好的开始。

有了付费服务

获取内容到search引擎的最简单和最快捷的方法是使用服务Brombone , seo.js , seo4ajax和prerender.io是这些将为您提供上述内容渲染的好例子。 当我们不想处理运行服务器/代理的时候,这是一个很好的select。 另外,它通常超级快。

有关Angular和SEO的更多信息,我们在http://www.ng-newsletter.com/posts/serious-angular-seo.html上写了一篇广泛的教程;我们在书中详细介绍了它:关于AngularJS的全书 。 在ng-book.com上查看。

你应该真的看看在moo博客年build立一个search引擎友好的AngularJS网站的教程。 他向您介绍了Angular文档中列出的所有步骤。 http://www.yearofmoo.com/2012/11/angularjs-and-seo.html

使用这种技术,search引擎会看到扩展的HTML而不是自定义标签。

这已经彻底改变了。

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

如果使用:$ locationProvider.html5Mode(true); 你被设置。

没有更多的渲染页面。

自从问到这个问题以后,事情发生了很大变化。 现在有一些选项可以让Google将您的AngularJS网站编入索引。 我发现的最简单的select是使用http://prerender.io免费服务,将为您生成可压缩的页面,并将其提供给search引擎。 几乎所有的服务器端networking平台都支持它。 我最近开始使用它们,支持也非常好。

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

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

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

唯一的事情是,你的Angular路线需要与你的REST API匹配1:1。

编辑 :我意识到这有可能真的浑浑你的REST api,我不build议在非常简单的使用情况之外进行它可能是天作之合。

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

我已经决定用无头浏览器生成快照,尽pipe我觉得这样做不太理想。

截至目前,Google已经改变了他们的AJAX抓取scheme。

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

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

Google的可爬行Ajax规范,在这里的其他答案中引用,基本上是答案。

如果您有兴趣了解其他search引擎和社交机器人如何处理相同的问题,我写下了这里的艺术状态: http : //blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification.html

我为https://ajaxsnapshots.com工作,这是一家实施Crawlable Ajax Spec作为服务的公司 – 该报告中的信息基于我们日志中的观察结果。

我find了一个优雅的解决scheme,将涵盖大部分基地。 我最初在这里写了关于它,并在这里回答了另一个类似的StackOverflow问题,它引用它。

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

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

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> 

这应该对大多数search引擎用例有很大的帮助。 如果您想为社交networking抓取工具(如果支持Javascript)完全dynamic呈现,则您仍然必须使用某些其他答案中提到的预呈现服务之一。

希望这可以帮助!

使用PreRender之类的东西,它会使站点的静态页面,以便search引擎可以索引它。

在这里你可以find它可用的平台: https : //prerender.io/documentation/install-middleware#asp-net

爬虫(或机器人)被devise为抓取网页的HTML内容,但由于AJAX操作asynchronous数据抓取,这成为一个问题,因为它需要一段时间来呈现页面,并显示dynamic内容。 同样, AngularJS也使用asynchronous模式,这为Google抓取工具带来了问题。

一些开发人员使用真实数据创build基本的html页面,并在爬网时从服务器端提供这些页面。 我们可以使用PhantomJS在服务端渲染相同的页面,其中有_escaped_fragment_ (因为Google在我们的站点URL中查找#!然后将#!中的所有内容都加上,并将其添加到_escaped_fragment_查询参数中)。 欲了解更多详情,请阅读这个博客 。

使用Angular Universal,您可以为应用程序生成着陆页,看起来像完整的应用程序,然后加载您的Angular应用程序。
Angular Universal生成的纯HTML意味着在服务器端没有JavaScript页面,并在不延迟的情况下为用户提供服务。 所以你可以处理任何爬虫,机器人和用户(谁已经有很低的CPU和networking速度)。然后你可以通过链接/buttonredirect到你的实际angular度的应用程序已经加载在它后面。 这个解决scheme是由官方网站推荐的。 – 更多关于SEO和Angular Universal-

抓取工具不需要丰富的特色风格的gui,他们只想看到内容 ,所以你不需要给他们一个为人类构build的页面的快照。

我的解决scheme:为抓取工具提供抓取工具所需的信息

您必须考虑抓取工具需要什么,只给他。

提示不要背后。 只需使用相同的API添加一点服务器端的Frontview