CNode

用nodejs爬文件遇到的问题,请各位大大来看看

Xxieren58发布于14 年前最后回复14 年前28 回复9179 浏览0 收藏

我想用nodejs 的http.get爬一堆文件下来,但是这个网站做了限制每次只能同时下载2个文件,而nodejs是异步的,问题来了..例如:


var urlArr = [ /* 一堆文件的url */ ];

for(/* 遍历urlArr */ ) {
  http.get(url, ...); // http.get 下载文件 
}

怎样做到每次只爬2个文件,或者第一次爬2个文件,然后这两个文件某个爬完了,又自动去爬下一个,总之每次只能有2个下载的请求,因为多了的那些请求是没法下载文件。。

期待大家的解答~~ 灰常感谢~~

查看回复

回复 (26)

X
xieren58#1·14 年前

@jeffz 麻烦老赵过来看看~~~

R
ruandao#2·14 年前

var urlArr = [...]; count =0; for(...){ while(count==2){ // 休息10分钟 } // 在callback 里面 count-=1; http.get(url,...); count +=1; }

不知道可以不?

X
xieren58#3·14 年前
引用 ruandaovar urlArr = [...]; count =0; for(...){ while(count==2){ // 休息10分钟 } // 在callback 里面 count =1; h...

文件有大有小,时间不好设置,太长了浪费时间,太短了,那就没法控制2个请求

G
guilin#4·14 年前

你這是黑@jeffz 啊

給個不用jscex的例子, 一起爬5個文件

async. forEachLimit(urlArr, 5, function(url, _callback) {
  request(url, _callback);
}, function(err) {
  console.log('damn err');
});
X
xieren58#5·14 年前
引用 guilin你這是黑@jeffz 啊 給個不用jscex的例子, 一起爬5個文件

哈哈,async 这个不是很熟悉,我自己用EventEmitter搞定了~~

L
leizongmin#7·14 年前

/**
 * 下载文件
 *
 * @param {array} urlArr 一堆文件的url
 * @param {int} threadCount 线程总数
 * @param {function} callback 下载完成后的回调函数
 */
var download = function (urlArr, callback) {

  // 模拟的线程
  var thread = function () {
    var url = urlArr.shift();   // 从URL列表中取一个出来
    if (typeof url !== 'string') {
      return threadDone();
    }
    http.get(url, function () { // http.get 下载文件 
      // 处理下载回来的文件
      // ...
      thread();
    });
  };

  var finishThread = 0;     // 已完成的线程数

  var threadDone = function () {
    finishThread++;
    if (finishThread >= threadCount) {
      return callback();
    }
  };

  for (var i = 0; i < threadCount; i++) {
    thread();
  }
};
L
leizongmin#8·14 年前
引用 leizongmin

使用方法:

download(['url1', 'url2', 'url3'], 2, function () {
  // 下载完成了...
});
X
xieren58#9·14 年前

综合起来貌似用async的forEachLimit最简单~~

X
xieren58#10·14 年前
引用 leizongmin

@leizongmin 方法不错,谢谢

A
atian25#11·14 年前
引用 xieren58综合起来貌似用async的forEachLimit最简单~~

我觉得用node.io最简单, 内建一个参数就支持几个线程下载

X
xieren58#12·14 年前
A
atian25#13·14 年前
引用 xieren58综合起来貌似用async的forEachLimit最简单~~

@xieren58

var nodeio = require('node.io');
var options = {
  timeout: 10,
  //线程个数
  max:2
};

var url = [
  'http://www.google.com/search?q=hello',
  'http://www.google.com/search?q=keyword',
  'http://www.google.com/search?q=ok',
  'http://www.google.com/search?q=xxxx',
  'http://www.google.com/search?q=hi',
  'http://www.google.com/search?q=url2'
]

exports.job = new nodeio.Job(options, {
    input: url,
    run: function (keyword) {
        this.getHtml(url, function (err, $) {
            var results = $('#resultStats').text.toLowerCase();
            this.emit(keyword + ' has ' + results);
        });
    }
});
J
jeffz#14·14 年前
引用 xieren58@jeffz 麻烦老赵过来看看~~~

就跟很多人说了用async.forEachLimit就行了,forEachLimit里面用Jscex写逻辑。如果你真要用Jscex——虽然我不觉得Jscex是处理这些事情的,就在循环里用whenAny吧,whenAny就是等待任意一个完成。还有真的,看看文档吧,不要搞到最后文档是白写的……

X
xieren58#15·14 年前
X
xieren58#16·14 年前
引用 xieren58@jeffz 麻烦老赵过来看看~~~

@jeffz 真心觉得Jscex不错,暂时还是不大会用,看来得认真看文档~~

J
jeffz#17·14 年前
引用 xieren58@jeffz 麻烦老赵过来看看~~~

@xieren58 只要把原本写JavaScript的方法用来写Jscex就行了,剩下的只是了解一个Task。现在发现好多同学是写了回调以后,就不知道怎么写普通JavaScript了……

X
xieren58#18·14 年前
引用 xieren58@jeffz 麻烦老赵过来看看~~~

@jeffz 回调太多,头晕了~

J
JacksonTian#20·14 年前
引用 leizongmin

太复杂 有没有。

J
JacksonTian#21·14 年前

不用EventProxy, 用Bagpipe马到功成。 https://github.com/JacksonTian/bagpipe

J
JacksonTian#22·14 年前
var urlArr = [ /* 一堆文件的url */ ];

var Bagpipe = require('bagpipe');
var bagpipe = new Bagpipe(2);

for(/* 遍历urlArr */ ) {
  // http.get(url, ...); // http.get 下载文件 
  bagpipe.push(http.get, url, ..., callback);
}

代码基本不用怎么改

J
JacksonTian#23·14 年前
引用 leizongmin

太复杂 有没有。

V
varworld#24·14 年前

用老赵的 jscex

X
xieren58#25·14 年前
引用 varworld用老赵的 jscex

正在尝试,但是不知道如何实现,求请教~

C
cony138#26·14 年前

如果用 @Jackson 的eventproxy应该也可以吧,每次成功后抛出事件,然后再次发出爬虫

参与回复
登录后即可参与回复。登录