phantomJS+nodeJS+nginx完美解决前后端分离SEO问题
来源:互联网 发布:淘宝产品摄影报价 编辑:程序博客网 时间:2024/05/27 12:21
此文至项目已经采用前后端分离,但遇到SEO问题的工程师们。
写在前面:
公司网站属于信息类网站,在项目立项的时候想降低前后端开发的耦合性,于是就采用了前后端分离的做法,这种方式在开发期间确实便捷了不少,前端负责界面和数据渲染,后台负责API接口开发和文档编写,一切都来得那么的有序。但是当运营部开始投百度广告的时候问题来了,百度的spider只会爬取页面数据,不会爬取执行JS后的页面数据,问题已经出现,不可能叫程序猿们重新撸一次代码吧,不管是从人力物力财力角度出发,公司都不会同意这样的事情发生,无限头大中。。。。
正文:
为了解决问题,就必须先要知道问题出在哪里?我们先来看看前后端分离spider工作流程,JS并不会执行。
于是我想到是否能在spider和web服务器之间加一个自己的spider帮助其他spider抓取执行JS后的页面数据。
朝着这个思路,的确找到存在这样一种spider程序可以抓取执行JS后的页面数据,phantomJS下载地址:http://npm.taobao.org/dist/phantomjs/,入门教程:http://javascript.ruanyifeng.com/tool/phantomjs.html,phantomJS是一个类似于nodeJS的程序,执行JS代码,下面是抓取指定数据的JS文件代码spider.js
/*global phantom*/"use strict";// 单个资源等待时间,避免资源加载后还需要加载其他资源var resourceWait = 500;var resourceWaitTimer;// 最大等待时间var maxWait = 5000;var maxWaitTimer;// 资源计数var resourceCount = 0;// PhantomJS WebPage模块var page = require('webpage').create();page.settings.loadImages = false; //为了提升加载速度,不加载图片 // 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(requestData, request) { resourceCount++; clearTimeout(resourceWaitTimer); //过滤页面不想加载的链接,我这里是过滤了我页面的百度统计代码和cnzz统计代码,你可以自定义自己的过滤规则(正则表达式) var _url = requestData['url']; if ((/.+?(baidu|cnzz).+?/gi).test(_url)){ //console.log('Skipping:'+requestData['url']+'------------------------------------------------------------------------------'); request.abort(); }else{ //console.log('NoSkipping:'+requestData['url']+'-----------------------------------------------------------------------------------------'); }};// 资源加载完毕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('https://www.yuejia.me', function (status) { if (status !== 'success') { phantom.exit(1); } else { // 当改页面的初始html返回成功后,开启定时器 // 当到达最大时间(默认5秒)的时候,截取那一时刻渲染出来的html maxWaitTimer = setTimeout(function(){ capture(2); }, maxWait); }});
然后执行js,怎么执行我就不想详细说了,作为程序猿的基础知识还是要了解,实在不知道的在后面留言,我详细回复你。
执行后就会得到执行了JS的页面数据了,然后我们需要把phantomjs的数据返回给代理服务,在了解后发现,nodejs可以直接调用phantomJS,当然你也可以用Java执行命令的方式来调用phantomJS,这里就用nodejs来做为phantomJS的中转件了,nodeJS下载地址:http://nodejs.cn/download/
下面是nodeJS作为服务器,监听8081,端口传递请求url到phantomJS抓取数据的JS,其中.replace(‘baiduPC[E]-QUYU’,”)是我在测试的时候发现不知道为什么如果后面链接加了这个玩意儿,phantomJS就会爬取失败,所以我加把它替换了,如果知道的朋友麻烦留言说下,谢谢啦。
// 引入NodeJS的子进程模块var child_process = require('child_process');var http = require("http");http.createServer(onRequest).listen(8081);function onRequest(req, res) { // 完整URL var url = req.originalUrl.replace('baiduPC[E]-QUYU',''); console.log("url:"+url) // 预渲染后的页面字符串容器 var content = ''; // 开启一个phantomjs子进程 var phantom = child_process.spawn('phantomjs.exe', ['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('load error'); res.write('加载失败'); break; case 2: console.log('timeout: '+ url); res.write(content); break; default: res.write(content); break; } res.end(); });}
到这里我们的nodeJS+phantomJS的配置就已经完成了,不过记得把phantomJS page.open(‘https://www.yuejia.me‘, function (status){…中的’https://www.yuejia.me‘替换成参数url,及page.open(url, function (status){…让需要抓取的页面从nodeJS传入,接下来就是需要把爬虫的请求转发到我们的nodeJS了,我这里采用了主流的Nginx来做
以下是nginx监听请求是否爬虫请求,是就转发到nodeJS去,不是就去取我们正常的页面数据。
location / { proxy_set_header Host $host:$proxy_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #爬虫特殊处理 if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot"){ proxy_pass http://spider_server; } root c:/webapps/website; index index.html index.htm; }
结束语:
前后端分离确实是在开发的时候给我们带来便捷,不过在API安全方面 SEO方面还有些欠缺或者说存在问题。这个对SEO检索出的方案个人觉得效果不是最好的,有时候会加载超时或者加载错误等等,不过这也是目前来说觉得最好的解决方案之一了,如果有更好的方案,希望大家留言,谢谢啦,关于前后端分离API通信安全问题我个人采用的是JWT验证的方式,感兴趣的朋友可以去看看我另外一篇文章,前后端问题API安全校验之JWT
- phantomJS+nodeJS+nginx完美解决前后端分离SEO问题
- 前后端分离nginx配置,同时解决跨域问题
- nodejs前后端分离
- 前后端分离问题
- 前后端分离,nginx配置解决js、css无法加载
- Nginx 前后端分离配置
- 前端后端分离,怎么解决SEO优化的问题?
- 基于NodeJS的前后端分离
- 基于NodeJS的前后端分离
- spring boot 前后端分离,解决ajax跨域问题
- 解决java前后端分离跨域的问题
- nginx前后端分离的配置
- nginx+vue.js实现前后端分离
- nginx搭建前后端分离架构
- Nginx + Uwsgi + Django前后端分离部署
- 前后端分离的思考与实践----基于NodeJS的前后端分离
- 前后端分离为什么不利于网站的SEO?
- 基于NODEJS的前后端项目分离实践
- pandas.Series.quantile
- PAT考试乙级1037(C语言实现)
- CF——Codeforces 891 C Envy
- 利用tensorflow训练简单的DNN
- 算法练习-1、放苹果(分治算法)
- phantomJS+nodeJS+nginx完美解决前后端分离SEO问题
- MongoDB入门学习(1)创建删除
- unity mac 破解
- sublime vue stylus 高亮
- 初步使用ideaUI
- 容器的未来是怎么样的?
- 14个超级牛X的免费开源小工具!
- 固定大小的环形buf
- myeclipse 删除文件恢复