使用谷歌headless(puppeteer)解决SEO问题
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利
使用headless解决SEO问题,原理是在服务器使用浏览器渲染好页面后返回给有益的蜘蛛爬虫,代码也没有服务端客户端的区别。渲染过程可能会比较消耗服务器资源,建议单独使用一台服务器搭建,我没有做压力测试,如果有人做了也希望分享我一下。
1、安装依赖
# 安装 puppeteer
cnpm install puppeteer
# puppeteer依赖,如果已安装谷歌浏览器可略过
yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64
yum install xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc
yum update nss -y
2、server.js
const http = require('http');
const puppeteer = require('puppeteer');
let conf = {
// 是否使用https访问API
useHttps: false,
// 是否检测IP,防止伪造UA
checkIp: false,
// 可以访问的蜘蛛IP地址
allowIpList: [],
launchOption: {
args: ['--no-sandbox', '--disable-setuid-sandbox']
}
};
/**
* 获取IP地址
*
* @param req
* @returns {*|string}
*/
function getIp (req) {
return req.headers['x-real-ip'] ||
req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress || '';
}
/**
* 检测ip是否合法
*
* @param ip
* @returns {boolean}
*/
function checkIP(ip) {
//也可以使用别的规则校验
return conf.checkIp ? conf.allowIpList.includes(ip) : true;
}
// 载入浏览器
puppeteer.launch(conf.launchOption).then(async browser => {
const server = http.createServer();
server.on('request', function(request, response){
let url = (conf.useHttps ? 'https://' : 'http://') + request.headers.host + request.url;
let ip = getIp(request);
// 检测ip地址
if (checkIP(ip)) {
browser.newPage().then(async page => {
// 访问url
await page.goto(url);
let content= await page.content();
// 关闭页面,返回数据
await page.close();
response.end(content);
})
} else {
response.statusCode = 404;
response.end("404 NOT Found");
}
})
server.on('close', function(){
browser.close();
})
server.listen(3000, '127.0.0.1', function () {
console.log('puppeteer server listening on port 3000!');
});
});
这里我选择先打开浏览器再启动服务;还有一种方式时先启动服务,接受到请求再打开浏览器处理请求,但我觉得这样每个请求都要打开关闭一次浏览器,有点浪费资源。不知道我这个想法是否正确,欢迎指正。
3、nginx配置
location / {
# 蜘蛛爬虫处理
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
if ($http_user_agent ~* "spider|bot") {
proxy_pass http://127.0.0.1:3000;
}
try_files $uri $uri/ @router;
}
location @router {
rewrite ^(.*)$ /index.html last;
}
4、hosts配置
配置host,从内网访问API
127.0.0.1 api.domain.com