首页 文章

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

提问于
浏览
690

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

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

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

尽管在自定义标签内,_ 2011年才会被编入索引吗?

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

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

我知道我可以做点什么

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

但是,如果我想让爬虫“看到” Headers 呢?服务器端渲染是唯一的解决方案吗?

15 回答

  • 1

    The crawlers do not need a rich featured pretty styled gui, they only want to see the content ,因此您无需为他们提供为人类构建的页面的快照 .

    我的解决方案:到 give the crawler what the crawler wants

    你必须考虑爬虫想要的东西,并只给他一点 .

    提示不要乱用背面 . 只需使用相同的API添加一个服务器端的前端视图

  • 4

    使用PushState和Precomposition

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

    PushState更改顶部浏览器栏中的URL而不重新加载页面 . 假设您有一个包含标签的页面 . 选项卡隐藏和显示内容,动态插入内容,使用AJAX或只需设置display:none和display:block隐藏并显示正确的选项卡内容 .

    单击选项卡后,使用pushState更新地址栏中的URL . 呈现页面时,使用地址栏中的值确定要显示的选项卡 . 角度路由将自动为您执行此操作 .

    预复合

    有两种方法可以使用PushState单页应用程序(SPA)

    • 通过PushState,用户单击PushState链接,内容为AJAX .

    • 直接点击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

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

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

    搜索引擎支持PushState URL

    PushState目前由Google和Bing支持 .

    谷歌

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

    http://youtu.be/yiAF9VdvRPw

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

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

    结果是谷歌支持PushState并将索引PushState URL .

    另请参阅Google网站管理员工具的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网址是一个丑陋的权宜之计,要求开发人员在特殊位置提供网站的预渲染版本 . 它们仍然有效,但您不需要使用它们 .

    Hashbang网址如下所示:

    domain.com/#!path/to/resource

    这将与这样的元标记配对:

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

    谷歌不会以这种形式对它们进行索引,而是从_escaped_fragments_ URL中提取网站的静态版本并将其编入索引 .

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

    domain.com/path/to/resource

    区别在于Angular通过拦截在JavaScript中处理它的document.location的更改来为您处理它们 .

    如果您想使用PushState URL(您可能会这样做),请取出所有旧的哈希样式URL和元标记,并在配置块中启用HTML5模式 .

    测试您的网站

    Google网站站长工具现在包含一个工具,可以让您以谷歌的形式获取网址,并在Google呈现时呈现JavaScript .

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

    在Angular中生成PushState URL

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

    $locationProvider.html5Mode(true);
    

    服务器端

    由于您使用的是真实URL,因此您需要确保服务器为所有有效URL提供相同的模板(以及一些预先组合的内容) . 如何执行此操作将取决于您的服务器体系结构 .

    站点 Map

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

    无论如何都有一个站点 Map 是个好主意 .

    浏览器支持

    Pushstate适用于IE10 . 在旧版浏览器中,Angular会自动回退到哈希样式网址

    一个演示页面

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

    http://html5.gingerhost.com/london

    可以在this link验证,内容已编入索引,并且正在Google中显示 .

    提供404和301 Headers 状态代码

    由于搜索引擎始终会针对每个请求点击您的服务器,因此您可以从服务器提供 Headers 状态代码,并希望Google能够看到它们 .

  • 400

    我找到了一个优雅的解决方案,涵盖了你的大部分基地 . 我最初写了here并回答了另一个引用它的类似StackOverflow问题here .

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

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

    app.js

    您可以在此处为每条路线提供自定义元数据( Headers ,说明等)

    $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支持上不受欢迎)的完全动态渲染,您仍然必须使用其他一些答案中提到的预渲染服务之一 .

    希望这可以帮助!

  • 106

    让我们对AngularJS和SEO有所了解

    Google,Yahoo,Bing和其他搜索引擎使用传统抓取工具以传统方式抓取网络 . 他们运行机器人,在网页上抓取HTML,沿途收集信息 . 他们保留有趣的单词,并寻找其他页面的其他链接(这些链接,它们的数量和它们的数量与SEO发挥作用) .

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

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

    可以做些什么呢?

    幸运的是,大型网站的抓取工具已经开始实施一种机制,允许我们使我们的JavaScript网站可以抓取,但它是 requires us to implement a change to our site .

    如果我们将 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标签来实现:

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

    提醒一下,我们可以使用 $location 服务设置 html5Mode()

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

    处理搜索引擎

    我们有很多机会确定我们如何处理实际向搜索引擎提供内容的静态HTML . 我们可以自己托管后端,我们可以使用服务为我们托管后端,我们可以使用代理来提供内容等 . 让我们看几个选项:

    自托管

    我们可以编写一个服务来处理使用无头浏览器(如phantomjs或zombiejs)爬行我们自己的站点,使用呈现的数据拍摄页面的快照并将其存储为HTML . 每当我们在搜索请求中看到查询字符串 ?_escaped_fragment_ 时,我们就可以通过JS传递我们对页面而不是预呈现页面的静态HTML快照 . 这要求我们有一个后端,在中间提供带有条件逻辑的页面 . 我们可以使用prerender.io's后端之类的东西作为自己运行的起点 . 当然,我们仍然需要处理代理和代码段处理,但这是一个好的开始 .

    使用付费服务

    将内容引入搜索引擎的最简单,最快捷的方法是使用服务Bromboneseo.jsseo4ajaxprerender.io就是这些将为您托管上述内容呈现的好例子 . 对于我们通常非常快速的时代来说,这是一个不错的选择 .

    有关Angular和SEO的更多信息,我们在http://www.ng-newsletter.com/posts/serious-angular-seo.html and 上写了一篇关于它的大量教程,我们在 ng-book: The Complete Book on AngularJS 中更详细地介绍了它 . 看看这个在ng-book.com .

  • 56

    谷歌的Crawlable Ajax Spec,在这里的其他答案中引用,基本上就是答案 .

    如果你对其他搜索引擎和社交机器人如何处理同样的问题感兴趣,我在这里写下了现状:http://blog.ajaxsnapshots.com/2013/11/googles-crawlable-ajax-specification.html

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

  • 9

    使用类似PreRender的东西,它会生成您网站的静态页面,以便搜索引擎可以为其编制索引 .

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

  • 7

    使用Angular Universal,您可以为应用程序生成看起来像完整应用程序的登录页面,然后在其后面加载Angular应用程序 .
    Angular Universal生成纯HTML意味着服务器端的无javascript页面,并在不延迟的情况下为用户提供服务 . 因此,您可以处理任何爬虫,机器人和用户(已经具有较低的CPU和网络速度) . 然后,您可以通过链接/按钮将它们重定向到已经加载到其后面的实际角度应用程序 . 该解决方案由官方网站推荐 . -More info about SEO and Angular Universal-

  • 0

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

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

    tl;博士:[Google]不再推荐2009年制作的AJAX抓取提案[Google] .

  • 2
  • 6

    这已经发生了巨大的变化 .

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

    如果您使用:$ locationProvider.html5Mode(true);你被设定了 .

    没有更多的渲染页面 .

  • 2

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

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

  • 41

    您应该在moo博客年度查看有关构建SEO友好的AngularJS网站的教程 . 他将引导您完成Angular文档中列出的所有步骤 . http://www.yearofmoo.com/2012/11/angularjs-and-seo.html

    使用此技术,搜索引擎会看到扩展的HTML而不是自定义标记 .

  • 8

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

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

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

    EDIT :我建议在非常简单的用例之外进行,这可能是天生的选择 .

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

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

  • 17

    自从提出这个问题以来,情况发生了很大的变化 . 现在有选项让Google为您的AngularJS网站编制索引 . 我找到的最简单的选择是使用 http://prerender.io 免费服务,它将为您生成crwalable页面并将其提供给搜索引擎 . 它几乎在所有服务器端Web平台上都受支持 . 我最近开始使用它们,支持也非常好 .

    I do not have any affiliation with them, this is coming from a happy user.

  • 470

    Update May 2014

    Google抓取工具now executes javascript - 您可以使用Google Webmaster Tools更好地了解Google如何呈现您的网站 .

    Original answer
    如果您想针对搜索引擎优化您的应用,很遗憾无法为抓取工具提供预渲染版本 . 您可以阅读有关Google针对ajax和javascript-heavy sites here的建议的更多信息 .

    如果这是一个选项,我建议阅读this article关于如何使用服务器端渲染为Angular做SEO .

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

相关问题