Prerender + vuejs1.xSEO 最佳实践 百度爬虫 + 谷歌收录 亲测成功

2,504 阅读5分钟

前言

单页应用的痛点以及什么原因导致的我不多说了 网上资料很多 能搜索到这篇文章 我想你也经历了诸多痛苦和无奈
注: 由于前端后分离 不同公司采用不同的语言组合 请根据本文配置 自行推倒相应配置
本司采用 SpringMVC + Vuejs1.x(可以忽略 SEO基本于该架构无关)
服务器环境: Oneinstack 本文仅作演示 只安装了其中的Tengine(Nginx)作为WEB容器
本文仅以Ubuntu14.04 LTS系统作为演示 (阿里云已经成功了 自用+商用都成功了 但是没有多余的资源 贡献了我许久未用的学生优惠服务器[doge] 大三狗强行秀即将逝去的优势)
请其他服务器在安装相应依赖或者软件的时候注意替换相应命令

用到的服务

服务器配置

(若已经安装过 均可跳过)

// 刚装完系统 先升级下旧包 觉得每次都要输sudo麻烦的 先执行 sudo su 保证以下操作不会出现因为权限到导致的一些莫名奇妙的问题
sudo apt-get update
安装git
sudo apt-get install git
安装nodejs nodejs各大平台官方安装指南 下列是Ubuntu安装 nodejs 6.x版本步骤
sudo apt-get install curl // 请先确认服务器是否安装了curl 如果已经安装跳过即可
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt-get install -y build-essential
// 如果不受 墙 影响可以忽略这步 并将下方cnpm换成npm即可
sudo npm install -g cnpm --registry=https://registry.npm.taobao.org

Clone prerender rep

git clone https://github.com/prerender/prerender

Why cnpm?

prerender需要用到phantomjs当你在墙内下载的时候 你会感受到来自 墙 的满满的恶意 而每当这时候淘宝镜像源仿佛救世主一般降临

执行npm install

cd prerender
cnpm install

after-cnpm-install

执行node server.js

node server.js

如果遇到以下错误(后面两行提示的)

ubuntu@VM-0-110-ubuntu:~/prerender$ node server.js
2016-12-31T19:57:42.231Z starting worker thread #0
2016-12-31T19:57:42.452Z starting phantom...
2016-12-31T19:57:42.460Z Server running on port 3000
/home/ubuntu/prerender/node_modules/.2.1.14@phantomjs-prebuilt/lib/phantom/bin/phantomjs: error while loading shared libraries: libfontconfig.so.1: cannot open shared object file: No such file or directory
(node:10992) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: /home/ubuntu/prerender/node_modules/.2.1.14@phantomjs-prebuilt/lib/phantom/bin/phantomjs: error while loading shared libraries: libfontconfig.so.1: cannot open shared object file: No such file or directory

修复方案

// ubuntu
sudo apt-get install libfontconfig
// centos
yum install libXext libXrender fontconfig libfontconfig.so.1

直到看到了类似下面的提示(不同配置会开启不同数量的的进程 所以可能看到多行starting phantom…) 才算开启成功

ubuntu@VM-0-110-ubuntu:~/prerender$ node server.js
2016-12-31T20:00:55.655Z starting worker thread #0
2016-12-31T20:00:55.865Z starting phantom...
2016-12-31T20:00:55.873Z Server running on port 3000
2016-12-31T20:00:56.491Z started phantom

测试服务是否安装成功

  • 打开你的服务器外网IP:3000/http://www.deboy.cn 查看shell控制台是否有进入日志 如有有说明成功了(不用管网页样式表加没加载 待会儿会讲)

服务器环境安装 (以下环境安装尽量做到与实际项目部署一致, 但是由于只是项目演示 会缩减掉部分旁枝末节)

这部分建议可以不随本文这样做 因为每个公司的架构都不一样 环境也是不一定一样 我这里只演示nginx中间件的使用 其他的中间件 点这里:prerender-install-middleware

  • 按照Oneinstack官方安装文档安装好你需要的任意组合的环境(作为演示 我不安装其他环境 单独安装nginx 因为全套安装下来时间比较长)
    注意 安装过程中 当问到是否安装pureftpd服务的时候选择y等下会用到这个创建FTP帐号
  • 参考官方的 如何删除虚拟主机?如何管理FTP账号? 分别新建一个域名对应的主机 和 一个默认的FTP帐号
  • 通过FTP帐号使用xftp或者任意FTP工具链接并上传一个简单的页面 确保域名解析正常后 开始改造你的项目代码

改造项目代码(不想手动创建直接到这一步最后一条Clone我的github demo)

我将使用一个简单的 vue-cli生成的模版 集成了Vue + vue-router + vue-resource)的项目来演示动态改变标题和内容

  • 通过vue-cli新建一个项目 不详细讲 请自行查看vue-cli文档 我们这里初始化的模版是1.0的 2.0的已经默认是vue2.0了

    vue init webpack#1.0 vue-prerender-demo
  • 修改(config/inex.js)buildassetsPublicPath配置 修改为以下格式 (此步是为了让页面在抓取的时候 不因为css资源路径的问题导致页面排版错乱 也为了最高程度还原网页内容)
    原本: /
    改成: youdomain.com/

  • 修改vue-router beforeEach 和 afterEach 原因

    router.beforeEach(function () {
    window.prerenderReady = false
    })
    router.afterEach(function (transition) {
    window.document.title = transition.to.title || 'Default page title'
    window.prerenderReady = true
    })
  • 给index.html 加meta标签 告诉爬虫我这是ajax页面 你丫无论如何也得等我js请求完再抓内容(国内然并卵)

    <meta name="fragment" content="!">
  • Github: vue-prerender-demo

修改站点对应Nginx(Tengine)配置文件(使用nginx中间件)

server {
listen 80;
server_name youdomain.com;
access_log /data/wwwlogs/youdomain.com_nginx.log combined;
index index.html index.htm index.php;
include /usr/local/tengine/conf/rewrite/typecho.conf;
root /data/wwwroot/youdomain.com;
#error_page 404 = /404.html;
#error_page 502 = /502.html;
location / {
try_files $uri @prerender;
}
location @prerender {
#proxy_set_header X-Prerender-Token YOUR_TOKEN;
set $prerender 0;
if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
set $prerender 1;
}
if ($args ~ "_escaped_fragment_") {
set $prerender 1;
}
if ($http_user_agent ~ "Prerender") {
set $prerender 0;
}
if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") {
set $prerender 0;
}
#resolve using Google's DNS server to force DNS resolution and prevent caching of IPs
#resolver 8.8.8.8;
if ($prerender = 1) {
#setting prerender as a variable forces DNS resolution since nginx caches IPs and doesnt play well with load balancing
set $prerender "127.0.0.1:3000";
rewrite .* /$scheme://$host$request_uri? break;
proxy_pass http://$prerender;
}
if ($prerender = 0) {
rewrite .* /index.html break;
}
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
expires 30d;
access_log off;
}
location ~ .*\.(js|css)?$ {
expires 7d;
access_log off;
}
location ~ /\.ht {
deny all;
}
// 接口转发 这里只是模拟 假设用的是java 那么端口就是转发到8080 只转发 有项目包名的哪一个 把/projectName改掉即可
#location /projectName {
# proxy_pass http://127.0.0.1:8080;
# include proxy.conf;
#}
}
  • 修改完成 重启Nginx
    service nginx restart

让node脚本不随终端断开而断开

sudo cnpm install forever -g
forever start server.js

检验成果 官方

原地址: vue-prerender.deboy.cn/#!/titleFro…

可抓取地址: vue-prerender.deboy.cn/?_escapedfragment=/titleFromRouterDefine

百度的缓存更新得太慢了 抓的IP是腾讯云的 我已经换阿里云了 可还是不行 只能换一个平台来抓取了 下面的Hello World!渲染出来 说明已经是成功了 访问上面那个页面 得到的应该是没有异步请求结果

下图是我wget得到的结果 为什么要把地址中#! 换成 ?_escaped_fragment_=你们看nginx配置就清楚了 同样百度爬虫来了 和这个是一样的效果

原理

  • 判断是否爬虫以及一些自定义调试条件
  • 服务端prerender预渲染(使用phantomjs在服务器上跑了一遍)并缓存文件 发送给爬虫
  • 页面抓取完成