5

HTTP Getリクエストがあり、レスポンスを解析してデータベースに保存したいと思います。

独立してcrawl(i)を呼び出すと、良い結果が得られます。しかし、1から2000までcroll()を呼び出す必要があります。良い結果が得られますが、一部の応答が失われたように見え、一部の応答が重複しています。何千もの非同期関数を呼び出す方法がわからないと思います。非同期モジュールキュー機能を使用していますが、これまでのところ、いくつかのデータが欠落しており、いくつかの重複があります。私はここで何が間違っているのですか?ご協力いただきありがとうございます。

私が這っているもの

私のノード機能:

 function getOptions(i) {
    return {
        host: 'magicseaweed.com',
        path: '/syndicate/rss/index.php?id='+i+'&unit=uk',
        method: 'GET'
    }
};

function crawl(i){
var req = http.request(getOptions(i), function(res) {
    res.on('data', function (body) {
        parseLocation(body);
    });
});
req.end();

}

function parseLocation(body){
    parser.parseString(body, function(err, result) {
        if(result && typeof result.rss != 'undefined') {
            var locationTitle = result.rss.channel[0].title;
            var locationString = result.rss.channel[0].item[0].link[0];
            var location = new Location({
                id: locationString.split('/')[2],
                name: locationTitle
            });
            location.save();
        }
    });
  }

N = 2 //# of simultaneous tasks
var q = async.queue(function (task, callback) {
        crawl(task.url);
        callback();
}, N);


q.drain = function() {
    console.log('Crawling done.');
}

for(var i = 0; i < 100; i++){
   q.push({url: 'http://magicseaweed.com/syndicate/rss/index.php?id='+i+'&unit=uk'});
}

[編集]まあ、たくさんのテストの後、私がクロールしているサービスはそれほど多くのリクエストをそれほど速く処理できないようです。それぞれのリクエストを順番に行うと、すべての良い応答を得ることができるからです。

ASYNCキューメソッドをスローダウンする方法はありますか?

4

5 に答える 5

18

このような非同期タスクを簡素化するこの素晴らしいモジュール、asyncをご覧ください。キューを使用できます。簡単な例:

N = # of simultaneous tasks
var q = async.queue(function (task, callback) {
    somehttprequestfunction(task.url, function(){
    callback();
    } 
}, N);


q.drain = function() {
    console.log('all items have been processed');
}

for(var i = 0; i < 2000; i++){
   q.push({url:"http://somewebsite.com/"+i+"/feed/"});
}

進行中のアクションのウィンドウがあり、コールバック関数のみを呼び出すと、タスクルームが将来のタスクに使用できるようになります。違いは、コードがすぐに2000の接続を開くようになり、明らかに失敗率が高いことです。妥当な値である5,10,20(サイトと接続によって異なります)に制限すると、成功率が向上します。リクエストが失敗した場合は、いつでも再試行するか、タスクを別の非同期キューにプッシュして別の試行を行うことができます。重要な点は、キュー関数でcallback()を呼び出すことです。これにより、完了時にルームが使用可能になります。

于 2013-01-16T21:35:34.703 に答える
10
var q = async.queue(function (task, callback) {
    crawl(task.url);
    callback();
}, N);

前のタスクを開始した直後に次のタスクを実行しているため、このようにキューは無意味です。次のようにコードを変更する必要があります。

// first, modify your 'crawl' function to take a callback argument, and call this callback after the job is done.

// then
var q = async.queue(function (task, next/* name this argument as 'next' is more meaningful */) {
    crawl(task.url, function () {
        // after this one is done, start next one.
        next();
    });     
    // or, more simple way, crawl(task.url, next);
}, N);
于 2013-04-16T09:14:25.323 に答える
1

必要に応じて別のオプション。派手なライブラリのないVanillaJS。

var incrementer = 0;
var resultsArray = [];

var myInterval = setInterval(function() {
    incrementer++
    if(incrementer == 100){
        clearInterval(myInterval)
        //when done parse results array
    }
    //make request here
    //push request result to array here

}, 500);

0.5秒ごとに関数を呼び出します。xリクエスト後に同期を強制して終了する簡単な方法。

于 2014-02-17T19:49:45.070 に答える
0

質問に少し遅れていることはわかっていますが、ノード4またはノード5を使用して、APIエンドポイントをテストするときにリクエストの数を遅くするために作成したソリューションは次のとおりです。

var fs = require('fs');
var supertest = require('supertest');
var request = supertest("http://sometesturl.com/api/test/v1/")
var Helper = require('./check.helper');
var basicAuth = Helper.basicAuth;
var options = Helper.options;

fs.readFile('test.txt', function(err, data){
  var parsedItems = JSON.parse(data);
  var urlparts = []
  // create a queue
  for (let year of range(1975, 2016)) {
    for (var make in parsedItems[year]){
      console.log(year, make, '/models/' + year + '/' + make)
      urlparts.push({urlpart:'/models/' + year + '/' + make, year: year, make: make})
    }
  }
  // start dequeue
  waitDequeue();

  // This function calls itself after the makeRequest promise completes
  function waitDequeue(){
    var item = urlparts.pop()
    if (item){
      makeRequest(item)
        .then(function(){
          // wait this time before next dequeue
          setTimeout(function() {
            waitDequeue();
          }, 3000);
        })
    } else {
      write(parsedItems)
    }
  }

  // make a request, mutate parsedItems then resolve
  function makeRequest(item){
    return new Promise((resolve, reject)=>{
      request
        .get(item.urlpart)
        .set(options.auth[0], options.auth[1])
        .set(options.type[0], options.type[1])
        .end(function(err, res) {
          if (err) return done1(err);
          console.log(res.body)
          res.body.forEach(function(model){
            parsedItems[item.year][item.make][model] = {}
          });
          resolve()
        })
      })
  }

  // write the results back to the file
  function write(parsedItems){
    fs.writeFile('test.txt', JSON.stringify(parsedItems, null, 4), function(err){
      console.log(err)
    })
  }

})
于 2015-11-25T01:49:36.600 に答える
0

少し遅れましたが、私はこれがうまくいくのを見つけました!asyncを使用すると、タスクハンドラー内でを使用してキューを遅くすることができます。例:

var q = async.priorityQueue(function(task, callback) {
// your code process here for each task
//when ready to complete the task delay it by calling
async.whilst( //wait 6 seconds
   function() {         
        return count < 10;      
   },
   function(callback) {
      count++;
      setTimeout(function() {
        callback(null, count);
      }, 1000);
   },
   function (err, n) {
    // n seconds have passed  
    callback(); //callback to q handler 
   }
 ); //whilst
} , 5);
于 2017-03-10T10:06:37.637 に答える