0

我正在尝试使用 Node.js 构建一个基本的网络爬虫。我已经尝试了尽可能多的爬虫模块,但它们都不适合我,所以我想我会尝试自己动手。基本上,我正在使用“请求”模块,并为我在页面上找到的每个链接递归调用“请求”函数。

它似乎运行良好,在 100 页之后,内存使用率仍然很低,但是在大约 14 页之后,我收到了关于最大事件发射器和可能的内存泄漏的 Node 警告。

这是编写网络爬虫的安全方法吗?有什么我需要考虑的吗?有没有更好的方法来解决它?

谢谢!

更新:下面的代码:

var request = require('request');
var $       = require('jquery');
var _       = require("underscore");
var S       = require('string');
var jsdom   = require('jsdom');

var startURL    = 'http://www.cnn.com/sitemap/';
var host        = 'http://www.cnn.com';
var blocked     = [];
var totalDepth  = 1;

var urls        = [];
var ignored     = [];
var results     = [];
var counter     = 0;

processURL(startURL,totalDepth);

function processURL(url,depth) {

    request(url, function (error, response, html) {

      if (!error && response.statusCode == 200) {

        var title = html.match("<title>(.*?)</title>");
            title=title ? title[1] : '';


        var myURL=url;
        myURL = myURL.split(',').join(' ');
        title = title.split(',').join(' ');
        displayURL = myURL.replace(host,'');
        results.push(myURL + ',' + title);
        counter++;

        if(results.length==100) {
            saveResults();
        }


        if(depth>0) {
            jsdom.env({
                html: html,
                scripts: ['http://code.jquery.com/jquery-1.7.min.js']
                }, function (err, window) {
                var $ = window.jQuery;
                if($!=undefined) {
                $('a').each(function() {
                    var href=$(this).attr('href');
                    href=fixURL(href);
                    if(checkURL(href)) {
                        addToQueue(href,depth-1);                       
                    } 
                })
              }
            });
        }
    }   
});
}

var int=setInterval(function(){checkExit()},10000);

function checkExit() {

    if(results.length==0) {
        process.exit();
    }

    saveResults();

}

function checkURL(url) {

    if(url==undefined) return false;
    if(url=='')  return false;
    if(url=='#') return false;
    if(url=='')  return false;
    if(url=='/') return false;
    if(S(url).startsWith('#')) return false;
    if(url.indexOf('javascript')==0) return false;

    if(url.indexOf("/")==0) {
        url=host+url;
    }

    if(_.contains(urls,url)) {        
        return false;
    }

    if(_.contains(ignored,url)) {        
        return false;
    }    

    $.each(blocked,function(i,d) {
        if(S(url).contains(d)) {
            ignored.push(url);
            return false;
        }
    })

    if(url.indexOf('http')==0) {
        if(S(url).startsWith(host)) {
            return true;
    }   else
            return false;
    }

    return true;                  
}

function addToQueue(url,depth) {

    if(_.contains(urls,url)) {        
        return false;
    }

    if(url.indexOf("/")==0) {
        url=host+url;
    }

    if(!validURL(url)) {
        return;
    }

    processURL(url,depth);
    urls.push(url); 

}

function saveResults() {
    var csv = '';
    $.each(results,function(i,d) {
        csv+=d + '\n';
    })
    writeData(csv);
    results = [];
}

function writeData(data) {
    var fs = require('fs');    
    fs.appendFile(__dirname+'/results.csv', data, function(err) {
        if(err) {
            console.log(err);
        } else {
            console.log("******The file was saved!******");            
        }
    }); 
}

function validURL(value) {
    var urlregex = new RegExp("^(http:\/\/www.|https:\/\/www.|ftp:\/\/www.|www.){1}([0-9A-Za-z]+\.)");
    if (urlregex.test(value)) {
        return (true);
    }
    return (false);
}

function fixURL(url) {
    if(url==undefined) return '';
    if(url.indexOf("/")==0) {
        return host+url;
    } else {
        return url;
    }
}
4

1 回答 1

2

对于给定的事件发射器,您正在达到节点的最大事件侦听器的非常保守/低阈值。最有可能的是,您的代码中有一个错误,您将一遍又一遍地添加侦听器到可以重用它们的同一个发射器。您需要发布您的代码以便我们对其进行分析,但要么您有正当需要增加此值,要么您错误地将冗余侦听器添加到同一个发射器。

您可能还想了解maxSockets参数,但可能不会对其进行调整,因为这可能会将您的代码从行为良好的爬虫转移到令人讨厌的拒绝服务机器人中。

于 2013-03-20T03:34:59.570 回答