【问题标题】:iterate node.js request function迭代 node.js 请求函数
【发布时间】:2016-08-06 03:16:52
【问题描述】:

这个问题是关于 node.js 中的爬虫的。 一个start_url 在他爬取URL 的地方给出,并将它们“推送”到一个.json-文件(output.json)。 目前,他只用start_url运行请求函数,并将收集到的URL保存在output.json中。我希望他通过将 start_url 替换为第一个收集的 URL 并再次收集链接来使用保存的 URL……等等……

var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');

var start_url = ["http://stackoverflow.com/"]

var req = function(url){
    request(url, function(error, response, html){
        var $ = cheerio.load(html);

        var data = [];

        $("a").each(function() {
            var link = $(this);
                var exurls = {exurl: new Array(link.attr("href"))}

                data.push(exurls);

                // Queue "exurls" for "start_url" and call the same function with the new URL (endless loop)
                // save to "output.json" from time to time, so you can stop it anytime
        });

        fs.writeFile("output.json", JSON.stringify(data, null, 4), function(err){
            if(err){
                console.log(err);
            } else {
                console.log("File successfully written!");
            }
        });
    });
}
for (var i = 0; i < start_url.length; i++){
    req(start_url[i]);
}

【问题讨论】:

  • 我不明白您想如何更改您提供的代码:它似乎已经按照您的要求工作:它将所有找到的链接排队并调用函数 (req())网址...
  • @MarcoS:现在,他使用 start_url 只运行一次请求函数,创建 .json 文件并停止。
  • ... 并要求您要求 ...
  • @MarcoS:他还使用从 start_url 抓取的找到的 URL 运行请求函数(有点没完没了)。
  • 你想用找到的网址做什么?例如,保存它们的内容?

标签: javascript jquery arrays json node.js


【解决方案1】:

所以你可以做的是递归调用函数。下面的例子应该可以工作:

var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');

var start_url = ["http://stackoverflow.com/"]

var req = function(url){
  var count = 0;
  
  request(url, function(error, response, html){
    var $ = cheerio.load(html);

    $("a").each(function() {
      var link = $(this);
      var exurls = {exurl: new Array(link.attr("href"))}

      start_url.push(exurls);

      // Queue "exurls" for "start_url" and call the same function with the new URL (endless loop)
      // save to "output.json" from time to time, so you can stop it anytime
    });

    try {
      fs.writeFileSync("output.json");
      console.log("File successfully written!");
     }catch(err){
       console.log(err);
     }
      
      ++count;
      
      if(start_url.length > count) {
        req(start_url[count]);
      }
  });
}

return req(start_url[0]);

这样做的问题是您每次都在完全重写文件。如果这种情况持续一段时间,您将耗尽内存。另一种选择是创建一个写入流

var fs = require('fs');
    var request = require('request');
    var cheerio = require('cheerio');

    var start_url = ["http://stackoverflow.com/"]
    
    var wstream = fs.createWriteStream("output.json");

    var req = function(url){
      
      request(url, function(error, response, html){
        var $ = cheerio.load(html);

        $("a").each(function() {
          var link = $(this);
          var exurls = {exurl: new Array(link.attr("href"))}

          start_url.push(exurls);

          // Queue "exurls" for "start_url" and call the same function with the new URL (endless loop)
          // save to "output.json" from time to time, so you can stop it anytime
          wstream.write('"'+ exurls + '",');
        });
          
        start_url.shift();
        if(start_url.length > 0) {
          return req(start_url[0]);
        }
          
          wstream.end();
      });
    }

    req(start_url[0]);

编辑:切换到基本队列以解决内存问题



【讨论】:

  • 谢谢。我更喜欢你的第二个解决方案,但它显示了一个错误......我没有足够的内存......
  • 这可能是因为您仍在推送到start_url。变量完全保留在内存中,因此您很快就会耗尽内存。您需要考虑创建一个队列。我编辑了我的回复,现在它只是从第一个元素start_url 中抓取,并在每次迭代后删除第一个元素。这在足够的时间后仍然不起作用,因为您很可能会在每次迭代中添加多个项目。但是试试看
  • 似乎内存问题已解决(至少......),但现在我与cheerio cheerio\lib\parse.js:55 发生冲突。为什么不阅读 output.json (同时)并每次下一个链接。感谢您的努力!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-20
  • 2017-05-19
  • 2011-05-29
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
相关资源
最近更新 更多