七仔的博客

七仔的博客GithubPages分博

0%

基于谷歌/火狐无头浏览器模式解决Vue的SEO问题

基于谷歌/火狐无头浏览器模式解决Vue的SEO问题

基于谷歌/火狐无头浏览器模式解决Vue的SEO问题

启发来自冷子欲的文章: 基于Vue SEO的四种方案,感谢作者的分享。

在他的文章里【使用Phantomjs针对爬虫做处理】对于已经开发完成的单页面Vue项目是很好的选择,但是我用Phantomjs安装完后不能正常工作,另外“PhantomJS宣布终止开发”,所以选择弃用Phantomjs转用其他的方案代替。

Phantomjs的本质是一个无头浏览器,我了解到谷歌和火狐都有无头浏览器模式,所以想到使用python调用浏览器来实现返回渲染好的html页面。

下面是我设计的流程图

flow 流程图

下面是具体的流程,在流程开始之前要安装Nginx、火狐/谷歌、Nodejs、python环境,安装及使用这里就不赘述了:

1.Nginx做转发

在Nginx的配置文件里的http区块加转发地址:

1
2
3
upstream spider_server {
server localhost:3000;
}

在http区块->server区块->location区块里加判断:

1
2
3
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;
}

这样便实现了对百度或其余的爬虫转发到3000端口,3000端口是node.js程序监听的地址,可以自己设置。

2.使用node.js调用python爬虫

创建server.js文件并运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// ExpressJS调用方式
var express = require('express');
var app = express();

// 引入NodeJS的子进程模块
var child_process = require('child_process');
var iconv = require('iconv-lite');

app.get('*', function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
//url
var url = req.protocol + '://'+ req.hostname + req.originalUrl;

// 预渲染后的页面字符串容器
var content = '';

// 开启一个python子进程
var firefox = child_process.spawn('python', ['firefox.py', url]);

// 设置stdout字符编码
//firefox.stdout.setEncoding('utf8');

// 监听python的stdout,并拼接起来
firefox.stdout.on('data', function(data){
//content += data.toString();
content += iconv.decode(new Buffer(data, 'binary'), 'gb2312');
});


// 捕获标准错误输出并将其打印到控制台
firefox.stderr.on('data', function (data) {
console.log('standard error output:\n' + data);
});

// 监听子进程退出事件
firefox.on('exit', function(code){
switch (code){
case 1:
console.log('load error');
res.write('加载失败');
break;
case 2:
console.log('timeout: '+ url);
res.write('time out');
break;
default:
//console.log(content);
res.write(content);
break;
}
res.end();
});

});

app.listen(3000, function () {
console.log('Spider app listening on port 3000!');
});

这里的3000便是Nginx转发的端口。

3.使用python调用谷歌/火狐浏览器获得渲染数据

这里使用python调用火狐浏览器获取渲染数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from selenium.webdriver.firefox.options import Options
from selenium import webdriver
import sys

# print(sys.argv[1])

# url = 'https://www.baby7blog.com'
js_delStyle = "var elems = document.getElementsByTagName('style');" \
"for(var i = 0; i < elems.length; i++){elems[i].parentNode.removeChild(elems[i]);}"
#
options = Options()
options.add_argument('--headless') # 无界面
options.set_preference('permissions.default.image', 2) # 不加载图片
browser = webdriver.Firefox(options=options) # 打开浏览器
browser.get(url=sys.argv[1]) # 请求
browser.execute_script(js_delStyle)
print(browser.page_source.encode('GBK','ignore').decode('GBk')) # 输出
browser.close() # 关闭浏览器
browser.quit() # # 杀死chrome浏览器的连接桥(chromedriver)的进程

可以看到使用了无头、无界面、不加载图片的浏览器模式,并且请求后对html做了处理,删除了不必要的