原创  vue seo 实战 之 puppeteer 篇 原理 及 坑

分类:运维 2020-07-05T15:19:42    141人阅读   

起因:VUE 异步渲染页面 ,不利于SEO ,本站基本未被百度搜录,于是笔者捣鼓起了 vue SEO


过程:

    问度娘找到这篇文章:https://segmentfault.com/a/1190000019623624

   建议了四种种方案 

        1、VUE官方 SSR  方案  ,教程:https://ssr.vuejs.org/zh/

        本方案需要修改项目、项目必须是纯前后端分离的

        2、静态化 ,使用Nuxt.js创建项目 的打包

        3、预渲染prerender-spa-plugin 

                本方案需要修改项目不过改动较小,项目必须纯前后端分离

        4、使用Phantomjs针对爬虫做处理

                项目不需要修改,依赖node

本站点使用的是flask,通过服务器渲染index.html 页面, 然后在页面使用vue异步组件配合路由的方式 动态创建页面,所以并不是完全的前后端分离。加上一直沉迷爬虫 于是悻然选着了 方案4


方案4  的思路 是 通过nginx 识别请求是否为爬虫 发出的,如果是就将 请求 的url 发给phantomjs 渲染,然后获取 到渲染后的html 投喂给爬虫

文章中推荐了 项目 vue-seo-phantomjs 来处理渲染和投喂的处理 ,这个项目主要包含两个文件server.js 和 spider.js

server.js 主要是开起来一个node 服务端,将接到的请求url 发给phantomjs

spider.js 主要是调用phantomjs渲染页面并获取渲染后html 

 坑  

phantomjs 已经没人维护年久失修 部署在服务器上 竟然 返回的 页面 不包含 vue组件的动态内容


于是查找了爬完phantomjs 的api 几经修改还是不生效,发现有人推荐Puppeteer,眼前一亮 google 大厂研发,不需要像selenium 一样安装对应驱动,还要对应浏览器。简单方便。

想象应该有人已经这么做了,于是 "Puppeteer VUE SEO" 一搜找到了 这篇文章:

https://www.jianshu.com/p/5a1f9c49ad31  

原理和 vue-seo-phantomjs 一样,文章中也介绍了 两个文件 

chrome.js 文件主要是打开一个浏览器,保存浏览器devtools 的连接地址,减少每次请求都要打开一个新的浏览器

app.js 完成页面渲染和投喂爬虫

本站使用的代码示例:

chrome.js:

// chrome.js

"use strict";

const puppeteer = require('puppeteer');

var fs = require("fs") ;

puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']}).then(

  async browser => {

  fs.writeFile("chrome.txt",browser.wsEndpoint(),function (err) {

    if (err) throw err ;

    console.log("存入chrome.txt成功"); //文件被保存

  }) ;

  browser.disconnect()

});

app.js:

const express = require('express');

const app = express();

const fs = require("fs");

const puppeteer = require('puppeteer');
var moment = require('moment');


app.get('*', function (req, res) {
     var url = req.protocol + '://localhost:5000' + req.originalUrl;
    var ua = req.headers['user-agent'];
var now = moment(Date.now()).format('YYYY-MM-DD HH:mm:ss  ');
	fs.writeFile("app.log", now+url,function (err) {});
    (async() => {
const browser = await puppeteer.connect({browserWSEndpoint:browserUrl});

       		const page = await browser.newPage(); //创建一个页面.
        try {
			const browserUrl = fs.readFileSync("chrome.txt","utf8");
			

            await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 0 }); //到指定页面的网址.
			res.send(await page.content());       

        	await page.close();

        	await browser.disconnect();
        }

        catch (err) {

            await page.close();

            await browser.disconnect();
			  fs.appendFile("app.log", now+JSON.stringify(err),function (err) {});
            console.log('出现错误:'+err);
        }

       

    })();

});

var server = app.listen(3000,'127.0.0.1', function () {

    var host = server.address().address;

    var port = server.address().port;

    console.log('Example app listening at http://%s:%s', host, port);

});

nginx.conf:

server 节点前:

upstream spider_server {
	  server localhost:3000;
	}

location内:

if ($http_user_agent ~* "Baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link  		preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|bingbot|Sosospider|Sogou Pic Spider|Googlebot|360Spider") {
			proxy_pass  http://spider_server;
		}


 

坑 

1、由于vue hash 路由模式hash 只后台是接受不到的,所以笔者 想到 将hash 值 作为queryString 传到后台,然后在渲染前修改url 将queryString 拼接  hash ,再交给 puppeteer 渲染。于是在VUE路由跳转前修改URL 代码如下:

router.beforeEach((to, from, next) => {
            if (to.meta.title) {
                document.title = to.meta.title
            }  if (location.search != '') {
                location.search = to.path
            } next();

        });


but 单页面包含二级路由的时候 只能修改带一级路由

SO 必须使用 history 路由模式,histroy 路由模式请求后台会导致 404 , 可以在nginx、apache 等服务器拦截也可以修改后台代码。

服务器配置拦截 参考 vue 官方 文档https://router.vuejs.org/zh/guide/essentials/history-mode.html

后台代码修改才是最彻底的,思路是: 触发404 异常 的时候返回一个正常 结果 不让页面 报404 ,真正的页面渲染工作 交给 前端完成

本站代码示例(python):

@app.errorhandler(404)
    def page_not_found(e):
        return render_template('index.html')


最后关于两个nodejs 的开机启动和进程驻留

使用 pm2 ,pm2是一个进程管理工具,可以用它来管理你的node进程,并查看node进程的状态,当然也支持性能监控,进程守护,负载均衡等功能

相关命令:

安装 cnpm install -g pm2

添加并启动js进程 pm2  /chrome.js (js 文件绝对路径) --name="chromeBrower"

关闭js进程 pm2 stop chromeBrower

关闭所有 pm2 stop all

启动 pm2 start chromeBrower

删除 pm2 delete chromeBrower

查看 pm2 list

开机启动 pm2 startup

分享到: