nodejs批量下載圖片

今天想獲取一大批貓的圖片,而後就在360流浪器搜索框中輸入,而後點擊圖片。就看到了一大波貓的圖片:http://image.so.com/i?q=%E7%8...,我在想啊,要是審查元素,一張張手動下載,多麻煩,因此打算寫程序來實現。不寫不知道,一寫發現裏面仍是有不少道道的。html

圖片描述

1. 爬取圖片連接

由於以前也寫過nodejs爬蟲功能(參見:nodejs微信公衆號開發——9.爬取網站素材定時推送消息),因此以爲應該很簡單,就用cheerio來處理dom啦,結果打印一下啥也沒有,後來查看源代碼:node

圖片描述

發現waterfall_zoom裏面空空如也,查找了一下,發現全部的數據都是寫在<script>裏面,而後動態加載到頁面的,因此用cheerio.load到的頁面裏面其實沒數據的。真實數據:git

圖片描述

分析完畢,刷刷寫代碼:程序員

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 粗糙的方案

最初的思路很簡單,簡單的fs.createWriteStream()就能解決:github

var downloadPic = function(src, dest){
    request(src).pipe(fs.createWriteStream(dest)).on('close',function(){
        console.log('pic saved!')
    })
}

使用方式:npm

downloadPic(imgList[0],'./catpics/1.jpg');

圖片描述

成功捕獲一隻貓!而後寫了一個循環準備捕獲全部貓。然而這種方式是串行的,速度很慢!下載一大批圖片要花大量時間。segmentfault

2.2 使用async異步批量下載

關於async的map操做,詳見:async_demo/map.js,對集合中的每個元素,執行某個異步操做,獲得結果。全部的結果將彙總到最終的callback裏。與forEach的區別是,forEach只關心操做無論最後的值,而map關心的最後產生的值。微信

提供了兩種方式:併發

  • 並行執行。async.map同時對集合中全部元素進行操做,結果彙總到最終callback裏。若是出錯,則馬上返回錯誤以及已經執行完的任務的結果,未執行完的佔個空位dom

  • 順序執行。async.mapSeries對集合中的元素一個一個執行操做,結果彙總到最終callback裏。若是出錯,則馬上返回錯誤以及已經執行完的結果,未執行的被忽略。

在此處:

async.mapSeries(imgList,function(item, callback){
    setTimeout(function(){
        downloadPic(item, './catpics/'+ (new Date()).getTime() +'.jpg');
        callback(null, item);
    },400);
}, function(err, results){});

注:此處使用setTimeout,是由於下載須要必定時間,在筆者較慢網速下,須要400ms的間隔能確保每張圖片下載徹底。

圖片描述

成功捕獲一批貓貓!

2.3 使用bagpipe批量

bagpipe是樸靈大大作的一個在nodejs中控制併發執行的模塊。其安裝和使用也比較簡單:

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.總結

做爲一個程序員,能用程序解決就不手動解決。每一次嘗都會有新的收穫。

相關文章
相關標籤/搜索