2016-03-03
当前位置: ㊣苏云田博客 > SEO > 文章正文

AngularJS 使用 Prerender.io 处理 SEO 的问题

0

AngularJS是一个用来构建网站和app的很棒的框架。内建的路由,数据绑定以及指令(directive)以及其他功能使得AngularJS可以很好的处理应用的各种前端功能。
使用AngularJS唯一的一个不爽的地方(到目前为之)是搜索引擎优化(SEO)。在这个教程中,我们将会介绍如何使你的AngularJS网站或app可以被Google抓取。
问题
搜索引擎爬虫(又叫机器人)最初是被设计用来抓取网页的HTML内容的。随着web以及网站技术的进化,JavaScript变成了web的主要语言。AJAX允许我们在web上做异步的操作。AngularJS充分使用了异步模型,这也给Google的爬虫带来了问题。

22153748_ODh8

如果你是一个AngularJS的重度使用者,很可能你的程序只有一个真正的HTML页面,然后异步的向该页面中填充其他的视图。所有的路由和程序逻辑都在客户端完成,因此,不论你是修改页面,提交评论,或者是执行增删改查操作,你都在一个页面中完成这些工作。
解决方案
放心,Google确实有一种方法来为AJAX的程序创建索引,你的AngularJS 程序可以被抓取,索引,以及像其他网站那样出现在搜索结果中。有一些你需要注意的事项及其他的步骤,但是Google全面支持这种方法。想要了解更多关于Google抓取AJAX内容的指南请参看 Google’s Webmaster AJAX Crawling Guidelines.
我们要构建什么
我们的程序应该能够被Google的爬虫以及其他爬虫(Bing的爬虫)渲染出结果。如果用这种方式,我们不会遇到上面那张图所显示的问题。我们会得到用户期望从我们这里得到的得到比较好的搜索结果。
AngularJS 使用 Prerender.io 处理 SEO 的问题
它是如何工作的
当一个搜索引擎的爬虫访问你的应用程序并且看到时,它会在你的URL中添加一个?_escaped_fragment_=tag。
你的服务器将会拦截这个请求,并把它发送给一个用来处理这个特殊的爬虫请求的中间件。在这篇文章中,我们选用Prerender.io,因此,下一步是针对Prerender.io的。
Prerender.io 将会检查请求的页面是否有一个现存的快照(或者缓存的页面),如果有,它会将这个页面响应给爬虫,如果没有的话,他会调用PhantomJS来渲染这个完整页面,并将它响应给爬虫。
未缓存的页面需要每次调用PhantomJS,这会花较长的时间来渲染页面,导致更长的响应时间,因此最好经常缓存页面。
还有其他的方法来实现!
替代方案:
使用Prerender.io的源码来配置你自己的Prerender服务。
使用一个不同的服务,如 BromBone, Seo.jsSEO4AJAX
创建你自己针对搜索引擎的渲染和快照的服务
关于 Prerender.io
Prerender.io 是一个兼容多种不同平台(包括Node,PHP和Ruby)的一个服务。该服务是完全开源的,但是如果你不想搭建一个你自己的SEO服务器的话,你可以使用他们提供的解决方案。Prerender的人们认为,SEO是一件正确的事,并不是一个特权,他们已经做了一些了不起的工作来扩展他们的解决方案,添加了很多自定义的功能和插件。
配置Node 的 package.json
我们将会构建一个简单的Node/AngularJS程序,改程序有多个页面以及动态的内容。我们将使用Node.js结合Express模块作为我们的后端服务器。使用下面的package.json文件来指定该篇教程中所用到的依赖。完成这些之后,你可以注册一个免费的prerender.io的账号并得到一个token。

1
2
3
4
5
6
7
8
9
10
11
12
// package.json

{
"name": "Angular-SEO-Prerender",
"description": "...",
"version": "0.0.1",
"private": "true",
"dependencies": {
"express": "latest",
"prerender-node": "latest"
}
}

现在,我们的package.json文件已经准备好了,接下来让我们使用npm install 来安装Node的依赖。
设置Node的server.js
这里的设置是非常标准。在我们的server.js文件中,我们将需要预渲染服务,并使用预渲染令牌连接它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// server.js
var express = require('express');

var app = module.exports = express();

app.configure(function(){
// Here we require the prerender middleware that will handle requests from Search Engine crawlers
// We set the token only if we're using the Prerender.io service
app.use(require('prerender-node').set('prerenderToken', 'YOUR-TOKEN-HERE'));
app.use(express.static("public"));
app.use(app.router);
});

// This will ensure that all routing is handed over to AngularJS
app.get('*', function(req, res){
res.sendfile('./public/index.html');
});

app.listen(8081);
console.log("Go Prerender Go!");

主页index.html
主页也是非常标准的。写你的代码像平时那样。大的变化是简单的在页面的中添加。这个meta标签将告诉搜索引擎的爬虫,这个网站有动态的JavaScript内容需要爬取。 另外,如果你的网页没有正确的缓存或者遗漏了内容,你可以添加如下的脚本片段window.prerenderReady = false;,它将告诉预渲染服务在获取快照之前等待直到你的整个页面被渲染。一旦你确认你的内容完全加载了,你需要设置window.prerenderReady = true。有很大的可能性你不需要包含这个代码片段,但是这是一个选项在你需要它的时候

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!-- index.html -->
 
<!doctype html>
<!-- We will create a mainController and bind it to HTML which will give us access to the entire DOM -->
<html ng-app="prerender-tutorial" ng-controller="mainController">
<head>
         
    <meta name="fragment" content="!">
    <!-- We define the SEO variables we want to dynamically update -->
    <title>Scotch Tutorial | {{ seo.pageTitle }}</title>
    <meta name="description" content="{{ seo.metaDescription }}">
 
    <!-- CSS-->
    <link rel="stylesheet" type="text/css" href="/assets/bootstrap.min.css">
    <style>
        body { margin-top:60px; }
    </style>
 
    <!-- JS -->
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
    <script src="http://code.angularjs.org/1.2.10/angular-route.min.js"></script>
    <script src="/app.js"></script>
</head>
<body>
<div class="container">
 
    <!-- NAVIGATION BAR -->
    <div class="bs-example bs-navbar-top-example">
        <nav class="navbar navbar-default navbar-fixed-top">
            <div class="navbar-header">
                <a class="navbar-brand" href="/">Angular SEO Prerender Tutorial</a>
            </div>
 
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
                <li><a href="/about">About</a></li>
                <li><a href="/features">Features</a></li>
            </ul>
        </nav>
    </div>
 
    <h1 class="text-center">Welcome to the Angular SEO Prerender Tutorial</h1>
    <!-- where we will inject our template data -->
    <div ng-view></div>
 
</div>
</body>
</html>

Angular 配置 app.js
在定义了AngularJS代码的app.js中,我们需要这句代码添加到我们的路由配置中:$locationProvider.hashPrefix(‘!’); 这个方法会重写你的URL。
如果你使用的是html5模式(html5Mode),你不会看到任何区别,除了你的url地址看起来将会是类似http://localhost:3000/#!/home 的形式相对于标准的地址http://localhost:3000/#/home。
URL里面的#!非常重要,因为它会告诉爬虫你的程序有AJAX内容,需要它做一下AJAX抓取转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// app.js
var app = angular.module('prerender-tutorial', ['ngRoute'])
.config(function($routeProvider, $locationProvider){
$routeProvider.when('/', {
templateUrl : 'views/homeView.html',
controller: 'homeController'
})

$routeProvider.when('/about', {
templateUrl : '/views/aboutView.html',
controller: 'aboutController'
})

$routeProvider.when('/features', {
templateUrl : '/views/featuresView.html',
controller : 'featuresController'
})

$routeProvider.otherwise({
redirectTo : '/'
});

$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
});

function mainController($scope) {
// We will create an seo variable on the scope and decide which fields we want to populate
$scope.seo = {
pageTitle : '',
pageDescription : ''
};
}

function homeController($scope) {
// For this tutorial, we will simply access the $scope.seo variable from the main controller and fill it with content.
// Additionally you can create a service to update the SEO variables - but that's for another tutorial.
$scope.$parent.seo = {
pageTitle : 'AngularJS SEO Tutorial',
pageDescripton: 'Welcome to our tutorial on getting your AngularJS websites and apps indexed by Google.'
};
}

function aboutController($scope) {
$scope.$parent.seo = {
pageTitle : 'About',
pageDescripton: 'We are a content heavy website so we need to be indexed.'
};
}

function featuresController($scope) {
$scope.$parent.seo = {
pageTitle : 'Features',
pageDescripton: 'Check out some of our awesome features!'
};
}

在上面的代码中,你可以看到我们是如何处理Angular的路由的以及如何处理不同的页面的pageTitle和pageDescription的。这些东西将会以SEO页面的形式渲染给爬虫!
到底怎么回事呢?
当爬虫通过地址 http://localhost:3000/#!/home访问你的页面时,url地址将会被转换成 http://localhost:3000/?_escaped_fragment_=/home地址,一旦,Prerender 中间件看到这 类URL,Prerender 服务将会被调用。另外,当爬虫通过http://localhost:3000/home访问你的主页时,你使用了HTML5模式,URL将会被转换 成http://localhost:3000/home/?_escaped_fragment_=地址。
Prerender服务将检测是否有对应这个URL的快照或者缓存的页面,如果存在就发给爬虫,如 果不存在,则在fly上生成快照,然后发送正确的页面给爬虫。
确保它可以正常工作
Prerender 为你提供了一个控制台用来哪些页面已经被渲染并且被爬虫抓取。这是一个很棒的工具用来查看你的SEO页面是怎么工作的。
22153750_1R82
22153751_B3z6
注意事项
最近,我有机会和Prerender.io的创始人进行了交谈,并问了他一些关于如何对单页面的app进行索引的问题。以下是他说的一些内容:
相应给爬虫渲染后的HTML,而不是JavaScript
不要发送404
如果你使用#来连接你的URL,一定要设置hashPrefix(‘!’),以便URL被重写为’#!’。
如果你有很多页面和内容,一定要有一个sitemap.xml和robots.txt。
Google每天只抓取一些页面,这由你的PageRank决定。包含一个sitemap.xml文件允许你来决定哪一个页面需要被索引。
当你想在Google的站长工具中测试一下你的AngularJS页面是如何渲染的,一定要在右边的地方添加上#!或?_escaped_fragment_=,因为这个工具不会像爬虫那样对地址进行转换。
结语
希望通过使用这个工具,你可以对你的Angular程序进行SEO。有很多像Prerender这样的服务以及方法去抓取AJAX的内容。去看一看 Google Webmaster AJAX Crawling Guidelines ,并构建一个可以进行良好SEO的Angular程序!
查看相关代码 https://github.com/scotch-io/angular-seo-prerender

原文地址:http://www.oschina.net/translate/angularjs-seo-with-prerender-io
英文原文:http://scotch.io/tutorials/javascript/angularjs-seo-with-prerender-io

Post a Comment

您的昵称 *

您的邮箱 *

您的网站