使用谷歌headless(puppeteer)解决SEO问题
发布于 3 年前 作者 huaer 1657 次浏览 来自 问答
粉丝福利 : 关注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
回到顶部