个人博客地址云墨白的博客前言博客上线也有一段时间了?

作为一个单页面应用,都是通过js来渲染页面,这就导致了蜘蛛在爬取网站的时候只能获取到一个空壳。seo优化问题,本来想使用官方的做法服务器渲染,但这样会导致很多问题,由于我的功能已经开发好了,如果使用服务器渲染,那我的整个项目都要进行重构,费时费力。.js性能优化,去除不必要的功能,提高性能。这三种方法我都在我的网站服务器测试过,并通过百度官方的抓取诊断测试过,也使用过工具本地批量抓取测试。

个人博客地址 云墨白的博客

前言

博客上线有一段时间了,我也提交了资料供各大搜索引擎收录,但是没用。当我空闲和无聊时,我开始了 seo。 Vue作为单页应用,通过js渲染页面,导致蜘蛛在抓取网站时只能得到一个空壳。如果没有信息,则不会包括在内。于是我开始研究Vue seo优化问题。本来想用官方的服务端渲染的方法,但是这样会出很多问题。由于我的功能已经开发完成,如果我使用服务器渲染,我的整个项目将不得不重构,这很耗时。费力。而我用的阿里云学生服务器,性能还不够!所以我采用了预渲染的方法。对于蜘蛛爬虫,我在服务器上给它开了一个小炉子,服务器判断是否是爬虫(根据请求头判断)。如果是爬虫,我把请求转发给预渲染服务器,然后再把渲染好的页面返回给爬虫,大概是这样的。因为程序太多,前后尝试了几种方法。终于用上了(性能不错)

渲染

是开发团队2017年发布的一个Node.js包,用来模拟浏览器的操作

由于我还是不熟练,所以使用的宝塔面板可以由宝塔面板中的下一个pm2管理器(管理你的节点进程,包括node.js和npm)来配置。安装成功后,可以进行如下配置。

下一步是配置服务器代码

.js性能优化,去掉不必要的功能,提升性能。

const puppeteer = require('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

.js 呈现请求的页面

const puppeteer = require('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;

.js,通过打开服务器。接受转发的请求

var express = require('express');var app = express();var spider = require("./spider1.js")var minify = require('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);});//监听3000端口app.listen(3000, () => {	console.log('预渲染服务已启动!');});

配置

upstream spider_server {  server localhost:3000;}server{    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://spider_server;        }        try_files $uri $uri/ @router;    }    location @router {        rewrite ^(.*)$ /index.html last;    }    ……

这是我第一次接触到的方法,但是在我了解之后,开发人员停止了维护。也与性能相比,性能并不好。这还不是最关键的。当我使用百度站长工具抓取我的文章时,我发现文章没有渲染,可能是因为使用了新的语法。毕竟,开发人员不维护它。所以直接放代码就不解释太多了。

// spider.js"use strict";// 单个资源等待时间,避免资源加载后还需要加载其他资源var resourceWait = 500;var resourceWaitTimer;// 最大等待时间var maxWait = 5000;var maxWaitTimer;// 资源计数var resourceCount = 0;// PhantomJS WebPage模块var page = require('webpage').create();// NodeJS 系统模块var system = require('system');// 从CLI中获取第二个参数为目标URLvar url = system.args[1];// 设置PhantomJS视窗大小page.viewportSize = {    width: 1280,    height: 1014};// 获取镜像var capture = function(errCode){    // 外部通过stdout获取页面内容    console.log(page.content);    // 清除计时器    clearTimeout(maxWaitTimer);    // 任务完成,正常退出    phantom.exit(errCode);};// 资源请求并计数page.onResourceRequested = function(req){    resourceCount++;    clearTimeout(resourceWaitTimer);};// 资源加载完毕page.onResourceReceived = function (res) {    // chunk模式的HTTP回包,会多次触发resourceReceived事件,需要判断资源是否已经end    if (res.stage !== 'end'){        return;    }    resourceCount--;    if (resourceCount === 0){        // 当页面中全部资源都加载完毕后,截取当前渲染出来的html        // 由于onResourceReceived在资源加载完毕就立即被调用了,我们需要给一些时间让JS跑解析任务        // 这里默认预留500毫秒        resourceWaitTimer = setTimeout(capture, resourceWait);    }};// 资源加载超时page.onResourceTimeout = function(req){    resouceCount--;};// 资源加载失败page.onResourceError = function(err){    resourceCount--;};// 打开页面page.open(url, function (status) {    if (status !== 'success') {        phantom.exit(1);    } else {        // 当改页面的初始html返回成功后,开启定时器        // 当到达最大时间(默认5秒)的时候,截取那一时刻渲染出来的html        maxWaitTimer = setTimeout(function(){            capture(2);        }, maxWait);    }});

.js

// server.js// ExpressJS调用方式var express = require('express');var app = express();// 引入NodeJS的子进程模块var child_process = require('child_process');app.get('*', function(req, res){    // 完整URL    var url = req.protocol + '://'+ req.hostname + req.originalUrl;    // 预渲染后的页面字符串容器    var content = '';    // 开启一个phantomjs子进程    var phantom = child_process.spawn('phantomjs', ['spider.js', url]);    // 设置stdout字符编码    phantom.stdout.setEncoding('utf8');    // 监听phantomjs的stdout,并拼接起来    phantom.stdout.on('data', function(data){        content += data.toString();    });    // 监听子进程退出事件    phantom.on('exit', function(code){        switch (code){            case 1:                console.log('加载失败');                res.send('加载失败');                break;            case 2:                console.log('加载超时: '+ url);                res.send(content);                break;            default:                res.send(content);                break;        }    });});app.listen(3000, function () {  console.log('Spider app listening on port 3000!');});

使用优化的seo,经过我的测试,这个方法比较好,但没有那么好(都是在服务器上测试的,访问同一个页面),也用

安装

是一个使用的服务,可以静态下载页面。

git clone https://github.com/prerender/prerender.gitcd prerendernpm install#启动server.js, 默认监听3000端口node server.js

通过curl命令解析你要访问的URL,如果返回渲染的html,说明说明成功。

curl http://localhost:3000/你的网站路径

配置

location / {	# 表示是否需要代理	set $prerender 0;	# 代理地址	set $prerender_url "http://127.0.0.1:3000";	# 判断请求是否来自蜘蛛,如果是则表示需要代理	if ($http_user_agent ~* "baiduspider|Googlebot|360Spider|Bingbot|Sogou Spider|Yahoo! Slurp China|Yahoo! Slurp|twitterbot|facebookexternalhit|rogerbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") { 		set $prerender 1; 	} 	if ($prerender = 1) {		proxy_pass $prerender_url;		rewrite ^(.*)$ /https://$host$1 break;	}}

总结

这三个我在我的网站服务器上测试了所有方法,通过了百度官方的爬虫诊断测试,也使用了该工具进行本地批量爬虫测试。虽然响应时间短,但不适合我的项目,因为有些页面没有渲染(文章),爬的时候服务器快满了。并且有些页面没有完全呈现。继续百度之后,终于用的简单不复杂,配置语句基本看懂了。

效果

目前本博客的部分文章和页面已被谷歌收录。

image.png

百度只有一个首页,不知道为什么,蜘蛛爬的频率不高,可能是有点懒!其实百度已经做了很久了,谷歌也提交了好几个网址,效率不高!也许我的更新也很慢!

本文中的配置未经严格测试。如有不足,请指出

免责声明:本文来自网络用户投稿,不代表本站观点和立场。如有侵权请发送邮件至tzanseo@163.com告知本站删除,本站不负任何责任及承诺。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

发表评论

登录后才能评论