Nodejs批量下载脚本:在JSONStream“on”事件中发出HTTP请求

时间:2013-09-13 11:45:14

标签: node.js http request

我有一个奇怪的问题。如果我调用此代码在主执行行中发出http请求:

var request = require('request');
request('http://www.google.com', function (error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body) // Print the google web page.
    }
})

正如预期的那样打印Google页面HTML。

但是,我正在进行批量下载脚本/爬虫,所以我正在解析一个非常大的JSON文件,然后对我从该文件生成的每个URL执行请求。

要进行解析,我使用的是JSONStream解析器。这是代码:

parser.on('data', function (obj) {
    console.log("Found uri");
    console.log(obj);
});

正在正确运行代码,因为URI正在我的控制台中打印。

但是,如果我在解析块中发出请求,则永远不会执行请求回调....这是代码:

parser.on('data', function (obj) {

    console.log("Found uri");
    console.log(obj);

    var identifierArray = obj['dc.identifier'];

    if(identifierArray != null && identifierArray instanceof Array)
    {
        for(var i = 0; i < identifierArray.length; i++)
        {
            var dryadIdentifier = identifierArray[i];
            if(dryadIdentifier.indexOf("dryad") != -1)
            {
                var fullUrl = "http://datadryad.org/resource/"+dryadIdentifier+"/mets.xml"
                //var fileDestination = __dirname +"/"+downloadSubDir+"/"+dryadIdentifier.replace("/","_")+".xml"
                var fileDestination = __dirname +"/"+downloadSubDir+"/"+fileCounter+".xml";

                fileCounter++;

                console.log("Sending request to "+ fullUrl + "   ...");

               //REQUEST SENT HERE; SAME CODE AS ABOVE.

                var request = require('request');
                request('http://www.google.com', function (error, response, body) {
                    if (!error && response.statusCode == 200) {
                        console.log(body) // Print the google web page.
                    }
                })

                sleep.usleep(500000); //dont hammer the server
            }
        }
    }
});

日志显示

Sending request to http://datadryad.org/resource/doi:10.5061/dryad.s737f/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.s737f/1/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.1fd83/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.1fd83/1/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.4vk6d/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.c3k8m/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.5410v/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.492r0/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.m6g1b/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.m6g1b/1/mets.xml   ...
Sending request to http://datadryad.org/resource/doi:10.5061/dryad.4dm30/mets.xml   ...

但是没有打印html(它应该多次打印google主页,因为我还没有使用我从json解析的url,以排除目标服务器的问题。

很抱歉这封长信,但我对这种行为感到茫然(仍在学习nodejs ......: - O)

1 个答案:

答案 0 :(得分:1)

似乎该问题与“sleep”调用有关,因此我使用semaphore库实现了一个基本连接队列。我现在指定最多10个同时连接,这是我的代码:

var makeRequestAndSaveToFile = function(url, absolutePath)
{
    sem.take(function(){
        console.log("Sending request to "+ url + "   ... and saving to file "+absolutePath);
        request(url, function(error,response, body) {
            if (!error && response.statusCode == 200) {
                fs.writeFile(absolutePath, body, function(err) {
                    sem.leave();

                    if(err) {
                        console.log(err);
                    } else {
                        console.log("The file was saved!");
                    }
                });
            }
        });
    });
}

我为每个要下载的链接调用此函数。

请注意,这不会处理大量下载,因为没有管道,链接将以Slavo在评论中所说的无序方式下载。