phantomJS+nodeJS+nginx完美解决前后端分离SEO问题

此文至项目已经采用前后端分离,但遇到SEO问题的工程师们。

写在前面:
公司网站属于信息类网站,在项目立项的时候想降低前后端开发的耦合性,于是就采用了前后端分离的做法,这种方式在开发期间确实便捷了不少,前端负责界面和数据渲染,后台负责API接口开发和文档编写,一切都来得那么的有序。但是当运营部开始投百度广告的时候问题来了,百度的spider只会爬取页面数据,不会爬取执行JS后的页面数据,问题已经出现,不可能叫程序猿们重新撸一次代码吧,不管是从人力物力财力角度出发,公司都不会同意这样的事情发生,无限头大中。。。。

正文:
为了解决问题,就必须先要知道问题出在哪里?我们先来看看前后端分离spider工作流程,JS并不会执行。
前后端分离spider工作流程
于是我想到是否能在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中获取第二个参数为目标URL
var 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

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Selenium是一个用于自动化浏览器操作的工具,而PhantomJS是一个无界面的浏览器。它们可以结合使用来进行爬虫操作。使用Selenium和PhantomJS,你可以模拟用户在浏览器中的操作,例如点击、填写表单等。这样就可以实现爬取网页数据的功能。 安装Selenium和PhantomJS的步骤如下: 1. 首先确保你已经安装了Python 3.5以及pip。 2. 使用pip安装Selenium,运行以下命令: ``` pip install selenium ``` 3. 下载PhantomJS并解压到Python的Scripts目录中。具体下载链接请参考中提供的系统环境下载说明。 安装完成后,你就可以开始使用Selenium和PhantomJS来实现爬虫功能了。你可以参考中提供的示例代码来学习如何使用Selenium和PhantomJS进行网页爬取。 此外,关于使用Selenium和PhantomJS进行数据爬取的方法,你可以按照以下步骤进行: 1. 使用Selenium和PhantomJS打开目标网页,模拟用户在浏览器中的操作来获取数据。 2. 如果网页使用了ajax接口来加载数据,你可以通过分析网页源代码或使用开发者工具来找到数据来源的接口,并发送请求获取数据。 3. 如果你只需要获取列表页的数据,可以在第一次爬取时只爬取列表页,将详情页的URL放到每条数据中心。这样可以避免增加请求数量。 4. 如果需要获取详情页的数据,可以在第二次爬取时从数据库中提取详情页URL,并使用Selenium和PhantomJS来爬取详情页的数据。 希望这些信息能对你有所帮助。如果你有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值