您现在的位置:首页 >> 前端 >> 内容

Node.js应用–––爬取pixiv上的高分图片

时间:2016/11/7 9:58:00 点击:

  核心提示:对ACG有了解的朋友们应该都熟悉有名的P站,P站的特点就是有大量的精美二次元图片,但P站连个搜索功能都不开放给非付费用户,遂有了这个项目,有兴趣可以移步PHelper-Github这里使用了Node....

对ACG有了解的朋友们应该都熟悉有名的P站,P站的特点就是有大量的精美二次元图片,但P站连个搜索功能都不开放给非付费用户,遂有了这个项目,有兴趣可以移步

PHelper-Github

这里使用了Node.js作为爬虫的服务器,不断获取的页面评分来筛选出高质量的图片

实现

技术选型

  • request.js-Github –发起HTTP请求
  • cheerio –解析response
  • mongodb –图片信息存储

在开始之前,我们要先熟悉一下Pixiv对爬虫技术做的限制

对于这类图片类网站来说,URL就是其最大的财富了,当然要做相应的防护

不过我还是要吐槽,这破站程序员的水平也太差了

对于反爬虫的策略只有一种,就是cookie限制

在国内常用的一些反爬虫策略,例如针对ip段的封锁,随机拒绝高频请求,蜜罐战术等等的防护一个都没有

我随便弄一段前端代码,大家可以看看

<script>
        new function() {
            var user_id = "";
            var service = 'www.pixiv.net';
            var api = 'https://www.pixiv.net/rpc/js_error.php';

            window.onerror = function(message, url, line) {
                window.onerror = null;
                if (!url && line === 0)return;

// Googleのスクリプトがエラー出しまくってるので一時的に対処
                if (url.indexOf('https://apis.google.com/_/scs/apps-static/') === 0) {
                    if (Math.random() > 0.01) return;
                }
//..........
// Safariがエラー出しまくってるので一時的に対処
                if ((message === null || message === "null") && line === 0 && window.navigator.userAgent.indexOf("Safari") >= 0) {
                    if (Math.random() > 0.01) return;
                }
                window._send(message, url, line);
            };

这种针对浏览器的错误处理让我大开眼界

pixiv的页面URl形式非常固定,都是统一的前缀+连续的图片id(再次吐槽),不拿来当爬虫的靶子都浪费这设计啊

先看请求单一页面的代码,

var createOption = require("./requestHeader");
var request = require("request");


var option = createOption("45358677")
console.log("begin time :",process.uptime());
    request(option,function(err,response){
        if(err){
            console.log("error");
        }
        if(response.statusCode == 200){
            console.log("success,end time:",process.uptime());
            console.log(response.body);//需要后续解析
        }else{
            console.log("get http response error,check your network");
        }
    });

获取response的html页面后,就可以使用cheerio把相应的数据清洗出来了,随后存入mongo就好,这个过程不表

还有一个问题是在面对数十万个连续请求时,如何控制流程的问题,for循环肯定是不能用的,还要控制回调队列的大小,于是采用了折中的方法,

采用定时器,每隔五秒发出一个请求,一般在网络顺畅的情况下,可以完成http请求并返回,进行下一个请求,即使在五秒内没有返回,也不会造成多个事件等待返回的情况

function myFunction(){
  console.log(begin);

  var option = createOption(begin.toString());
  console.log("begin time :",process.uptime());

  request(option,function(err,response){
    if(err){
      console.log("error");
      return;
    }
    if(response.statusCode == 200){
      console.log("success,end time:",process.uptime());
      parseRes.processPage(response)
    }else{
      console.log(begin," warning:get http response exception ");
    }
  });

  begin++;
  if(begin < end){
    setTimeout(myFunction, 5000);
  }else{
    process.exit();
  }
}

同时,我觉得单个进程跑太费时间怎么办,多进程走起

把上面的代码fork五份,作为五个单独的进程,速度就能提升五倍

Tags:NO OD DE EJ 
作者:网络 来源:空気力学少女の诗