参考文章: https://blog.csdn.net/wuyuanshun/article/details/127737603
1、创建文件夹mysite
mkdir /app/puppeteer/project/mysite
cd /app/puppeteer/project/mysite
2、puppeteer-pool.js 性能优化,去除不必要的功能,提高性能。
const puppeteer = require('/app/puppeteer/core/node_modules/puppeteer');//由于目录不一致,所以使用的是绝对路径
const MAX_WSE = 2; //启动几个浏览器
let WSE_LIST = []; //存储browserWSEndpoint列表
//负载均衡
(async () => {
for (var i = 0; i < MAX_WSE; i++) {
const browser = await puppeteer.launch({
//无头模式
headless: true,
//参数
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-setuid-sandbox',
'--no-first-run',
'--no-sandbox',
'--no-zygote',
'--single-process'
]
});
browserWSEndpoint = await browser.wsEndpoint();
WSE_LIST.push(browserWSEndpoint);
}
})();
module.exports = WSE_LIST
3、spider.js渲染请求的页面
const puppeteer = require('/app/puppeteer/core/node_modules/puppeteer');//由于目录不一致,所以使用的是绝对路径
const WSE_LIST = require('./puppeteer-pool.js') //这里注意文件的路径和文件名
const spider = async (url) => {
let tmp = Math.floor(Math.random() * WSE_LIST.length);
//随机获取浏览器
let browserWSEndpoint = WSE_LIST[tmp];
//连接
const browser = await puppeteer.connect({
browserWSEndpoint
});
//打开一个标签页
var page = await browser.newPage();
//打开网页
await page.goto(url, {
timeout: 0, //连接超时时间,单位ms
waitUntil: 'networkidle0' //网络空闲说明已加载完毕
})
//获取渲染好的页面源码。不建议使用await page.content();获取页面,因为在我测试中发现,页面还没有完全加载。就获取到了。页面源码不完整。也就是动态路由没有加载。vue路由也配置了history模式
var html = await page.evaluate(() => {
return document.getElementsByTagName('html')[0].outerHTML;
});
await page.close();
return html;
}
module.exports = spider;
4、server.js,通过express 开启一个服务器。接受转发的请求
首先需要安装express。这里我是回到了/app/puppeteer/core这个目录。
这里由于下载速度问题,我还是用的cnpm
cd /app/puppeteer/core
cnpm install express --save
cnpm install html-minifier --save
然后是server.js的代码
const express = require('/app/puppeteer/core/node_modules/express');//由于目录不一致,所以使用的是绝对路径
var app = express();
var spider = require("./spider.js")
var minify = require('/app/puppeteer/core/node_modules/html-minifier').minify;//由于目录不一致,所以使用的是绝对路径
app.get('*', async (req, res, next) => {
// 部署到服务器的完整URL
var url = req.protocol + '://'+ req.hostname + req.originalUrl;
console.log('请求的完整URL:' + url);
var content = await spider(url).catch((error) => {
console.log(error);
res.send('获取html内容失败');
return;
});
//由于是直接获取的源码,下面通过minify库压缩代码,也不知道是不是多余的。
content=minify(content,{removeComments: true,collapseWhitespace: true,minifyJS:true, minifyCSS:true});
res.send(content);
});
//监听4000端口
app.listen(4000, () => {
console.log('预渲染服务已启动!');
});
尝试启动
node server.js
这样表示服务启动成功了。
这里用的端口号是4000(可以根据自己的服务器情况更换端口号)。后续nginx的时候要用到
5、接下来开始配置nginx
整体的部署说明一下
(1)用的域名,端口是80。
(2)因为是vue的应用,所以location /中配置了alias来访问前端
(3)而我们的这个也是要监听所有的应用,也就是也要放在location /中
整体的访问结构图
简单说明:
一个请求过来,首先是判断是否是爬虫,如果是爬虫的话,就将其抓到puppeteer上,然后puppeteer会根据url抓取到最终的完整页面返给爬虫,从而达到我们SEO的目的。如果不是爬虫,则直接访问前端即可,这样的场景就是普通的请求,直接放行即可(不需要再经过puppeteer了,因为这样其实是慢的)。
附上我的nginx的配置。
location / {
#爬虫的转发配置 start
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 ~* "Sogou Pic Spider|Baiduspider|Baiduspider-render|YisouSpider|Sogou web spider|Bytespider|360Spider|Googlebot|YodaoBot") {
proxy_pass http://localhost:4000;
}
#爬虫的转发配置 end
#vue前端的文件夹 start
alias /app/mysite-front/dist/;
gzip_static on; #查找静态文件
#vue前端的文件夹 end
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
6、做了个启动脚本文件
文件名:startup.sh
内容:
nohup node /app/puppeteer/project/mysite/server.js &
7、启动
/app/puppeteer/project/mysite/startup.sh
8、测试
我用postman测试的
header中的user-agent设置成:Baiduspider
然后看返回值即可,如果是比较完成的页面,则表示没问题了