nodejs制作爬蟲實(shí)現(xiàn)批量下載圖片
今天想獲取一大批貓的圖片,然后就在360流浪器搜索框中輸入 貓 ,然后點(diǎn)擊圖片。就看到了一大波貓的圖片: http://image.so.com/i?q=%E7%8... ,我在想啊,要是審查元素,一張張手動(dòng)下載,多麻煩,所以打算寫程序來(lái)實(shí)現(xiàn)。不寫不知道,一寫發(fā)現(xiàn)里面還是有很多道道的。

1. 爬取圖片鏈接
因?yàn)橹耙矊戇^(guò)nodejs爬蟲功能(參見:NodeJS制作爬蟲全過(guò)程 ),所以覺得應(yīng)該很簡(jiǎn)單,就用cheerio來(lái)處理dom啦,結(jié)果打印一下啥也沒有,后來(lái)查看源代碼:

發(fā)現(xiàn) waterfall_zoom 里面空空如也,查找了一下,發(fā)現(xiàn)所有的數(shù)據(jù)都是寫在 <script> 里面,然后動(dòng)態(tài)加載到頁(yè)面的,所以用cheerio.load到的頁(yè)面里面其實(shí)沒數(shù)據(jù)的。真實(shí)數(shù)據(jù):

分析完畢,刷刷寫代碼:
var request = require('request');
var cheerio = require('cheerio');
var url = 'http://image.so.com/i?q=%E7%8C%AB&src=tab_www';
request(url,function(err,res,body){
if(!err && res.statusCode === 200){
var $ = cheerio.load(body);
var imgList = []
JSON.parse($('script[id="initData"]').html()).list.forEach(function(item){
imgList.push(item.img)
});
console.log(imgList);
}
});

2. 下載圖片到本地 2.1 粗糙的方案
最初的思路很簡(jiǎn)單,簡(jiǎn)單的 fs.createWriteStream() 就能解決:
var downloadPic = function(src, dest){
request(src).pipe(fs.createWriteStream(dest)).on('close',function(){
console.log('pic saved!')
})
}
使用方式:
downloadPic(imgList[0],'./catpics/1.jpg');

成功捕獲一只貓!然后寫了一個(gè)循環(huán)準(zhǔn)備捕獲所有貓。然而這種方式是串行的,速度很慢!下載一大批圖片要花大量時(shí)間。
2.2 使用async異步批量下載
關(guān)于async的map操作,詳見: async_demo/map.js ,對(duì)集合中的每一個(gè)元素,執(zhí)行某個(gè)異步操作,得到結(jié)果。所有的結(jié)果將匯總到最終的callback里。與forEach的區(qū)別是,forEach只關(guān)心操作不管最后的值,而map關(guān)心的最后產(chǎn)生的值。
提供了兩種方式:
并行執(zhí)行。 async.map 同時(shí)對(duì)集合中所有元素進(jìn)行操作,結(jié)果匯總到最終callback里。如果出錯(cuò),則立刻返回錯(cuò)誤以及已經(jīng)執(zhí)行完的任務(wù)的結(jié)果,未執(zhí)行完的占個(gè)空位
順序執(zhí)行。 async.mapSeries 對(duì)集合中的元素一個(gè)一個(gè)執(zhí)行操作,結(jié)果匯總到最終callback里。如果出錯(cuò),則立刻返回錯(cuò)誤以及已經(jīng)執(zhí)行完的結(jié)果,未執(zhí)行的被忽略。
在此處:
async.mapSeries(imgList,function(item, callback){
setTimeout(function(){
downloadPic(item, './catpics/'+ (new Date()).getTime() +'.jpg');
callback(null, item);
},400);
}, function(err, results){});
注: 此處使用setTimeout,是因?yàn)橄螺d需要一定時(shí)間,在筆者較慢網(wǎng)速下,需要400ms的間隔能確保每張圖片下載完全。

成功捕獲一批貓貓!
2.3 使用bagpipe批量
bagpipe 是樸靈大大做的一個(gè)在nodejs中控制并發(fā)執(zhí)行的模塊。其安裝和使用也比較簡(jiǎn)單:
npm install bagpipe --save
使用:
var Bagpipe = require('bagpipe');
var bagpipe = new Bagpipe(10);
var files = ['這里有很多很多文件'];
for(vari =0; i < files.length; i++){
bagpipe.push(fs.readFile, files[i], 'utf-8',function(err, data){
...
});
}
在此處:
var bagpipe = new Bagpipe(10,{timeout: 100});
for(var i = 0; i < imgList.length; i++) {
console.log('i:'+i)
bagpipe.push(downloadPic, imgList[i], './catpics/'+ i +'.jpg', function(err, data){
//
});
}
3.總結(jié)
作為一個(gè)程序員,能用程序解決就不手動(dòng)解決。每一次嘗都會(huì)有新的收獲。
相關(guān)文章
使用NestJS開發(fā)Node.js應(yīng)用的方法
這篇文章主要介紹了使用NestJS開發(fā)Node.js應(yīng)用的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
node.js中的模塊化標(biāo)準(zhǔn)CommonJS與自定義模塊
這篇文章介紹了node.js中的模塊化標(biāo)準(zhǔn)CommonJS與自定義模塊,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
Node.js高級(jí)編程cluster環(huán)境及源碼調(diào)試詳解
這篇文章主要為大家介紹了Node.js高級(jí)編程cluster環(huán)境及源碼調(diào)試詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
如何使用docker直接運(yùn)行不同版本nodejs命令
這篇文章主要介紹了如何使用docker直接運(yùn)行不同版本nodejs命令,在不支持高版本Node.js的舊版操作系統(tǒng)上,可以通過(guò)Docker容器技術(shù)解決兼容性問(wèn)題,需要的朋友可以參考下2024-10-10
Nodejs下用submit提交表單提示cannot post錯(cuò)誤的解決方法
這篇文章主要介紹了Nodejs下用submit提交表單提示cannot post錯(cuò)誤的解決方法,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2016-11-11

