0

Node.js を使用して基本的な Web クローラーを構築しようとしています。見つけられる限り多くのクローラー モジュールを試しましたが、どれもうまく機能しませんでした。基本的に、私は「リクエスト」モジュールを使用しており、ページで見つけたすべてのリンクに対して [リクエストの] 「取得」関数を再帰的に呼び出しています。

うまく機能しているようで、100 ページ後もメモリ使用量はまだ少ないですが、約 14 ページ後、イベント エミッターの最大数とメモリ リークの可能性に関する Node 警告が表示されます。

これは Web クローラーを作成するための安全な方法ですか? 考慮する必要があることはありますか? それについてもっと良い方法はありますか?

ありがとう!

更新: 以下のコード:

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 に答える