通常咱們在寫爬蟲的時候,不少網站會由於你併發請求數太多當作是在惡意請求,封掉你的IP,爲了防止這種狀況的發生,咱們通常會在代碼裏控制併發請求數,Node裏面通常藉助async模塊來實現。javascript
mapLimit(arr, limit, iterator, callback)java
arr中通常是多個請求的url,limit爲併發限制次數,mapLimit方法將arr中的每一項依次拿給iterator去執行,執行結果傳給最後的callback;node
下面是以前寫過的一個簡單的爬蟲示例,將爬取到的新聞標題和路徑保存在一個Excel表格中,限制併發數爲3,代碼以下git
webSpider.js:github
//request調用url主函數 (mapLimit iterator) function main(option, callback) { n++; timeline[option] = new Date().getTime(); console.log('如今的併發數是', n, ',正在抓取的是', option); request(option, function(err, res, body) { if(!err && res.statusCode == 200){ var $ = cheerio.load(body); $('#post_list .post_item').each(function(index, element) { // console.log(element); var item = [$(element).find('.post_item_body h3 a').text(),$(element).find('.post_item_body h3 a').attr('href')]; dataArr[0].data.push(item); }); console.log('抓取', option, '結束,耗時:', new Date().getTime()-timeline[option], '毫秒'); n--; callback(null, 'done!'); }else{ console.log(err); n--; callback(err, null); } }); } //限制請求併發數爲3 async.mapLimit(options, 3, main.bind(this), function(err, result){ if(err) { console.log(err); } else { fs.writeFile('data/cnbNews.xlsx', xlsx.build(dataArr), 'utf-8', function(err){ if(err){ console.log('write file error!'); }else{ console.log('write file success!'); } }); } });
這裏迭代器裏面第二個參數callback(即請求每一條url完成以後的回調方法)是關鍵,沒有異常的狀況下全部options中的url都請求完成以後會回調mapLimit方法的回調方法進行後續操做(如這裏的生成文件),若是單條url請求異常,回調方法中會接收到err並報出錯誤,不能執行後續生成文件的操做。web
async.mapLimit(options, 3, function(option, callback) { request(option, main); callback(null); }, function(err, result) { if(err) { console.log(err); } else { console.log('done!'); } });
如上,網上有些資料中是在迭代器中request方法執行完成以後調用callback,由於request方法異步接收請求數據,這種寫法會使async.mapLimit
方法limit參數無效,致使沒法達到限制請求併發數的目的,這裏須要注意下。併發
執行webSpider.js,異步
node webSpider.js
執行結果能夠看到併發數依次增長,增長到3時再也不繼續增長,等待前面一條請求執行完成後纔會請求下一條,這樣的話,若是咱們須要爬取1000條數據,就能夠併發10條請求,慢慢爬完這1000個連接,這樣就不用擔憂因併發太多被封IP這種狀況發生了。完整代碼已上傳GitHub,有興趣去試試吧!async