Node.js meitulu圖片批量下載爬蟲1.051

原有1.05版程序沒有斷點續傳模式,現在在最近程序基礎上改寫一版1.051.

復制代碼
//======================================================
// meitulu圖片批量下載爬蟲1.051
// 用最近的斷點續傳框架改寫原有1.05版程序
// 2017年11月21日
//======================================================// 內置https模塊
var https=require("https");// 內置http模塊
var http=require("http");// 用于解析gzip網頁(ungzip,https得到的網頁是用gzip進行壓縮的)
var zlib = require('zlib'); // 內置文件處理模塊,用于創建目錄和圖片文件
var fs=require('fs');// 用于轉碼。非Utf8的網頁如gb2132會有亂碼問題,需要iconv將其轉碼
var iconv = require('iconv-lite');// cheerio模塊,提供了類似jQuery的功能,用于從HTML code中查找圖片地址和下一頁
var cheerio = require("cheerio");// 請求參數JSON。http和https都有使用
var options;// request請求
var req;// 圖片數組,找到的圖片地址會放到這里
var pictures=[];// 存放圖片的目錄
var folder="";//--------------------------------------
// 爬取網頁,找圖片地址,再爬
// pageUrl sample:https://www.meitulu.com/item/12161.html
// pageUrl sample:
//--------------------------------------
function crawl(pageUrl){console.log("Current page="+pageUrl);// 得到hostname和pathvar currUrl=pageUrl.replace("https://","");var pos=currUrl.indexOf("/");var hostname=currUrl.slice(0,pos);        var path=currUrl.slice(pos);    //console.log("hostname="+hostname);//console.log("path="+path);// 初始化options  options={hostname:hostname,port:443,path:path,// 子路徑method:'GET',        };req=https.request(options,function(resp){var html = [];resp.on("data", function(data) {html.push(data);})resp.on("end", function() {var buffer = Buffer.concat(html);//var body = buffer.toString();//console.log(body);
zlib.gunzip(buffer, function(err, decoded) {if(err){console.log("[findPageUrls]不能得到頁面:"+batchPageUrl+"對應的html文本,錯誤是:"+err);console.log(err);}else{var body=decoded.toString();   //console.log(body);var $ = cheerio.load(body);        var picCount=0;// 找圖片放入數組$(".content  img").each(function(index,element){var picUrl=$(element).attr("src");console.log(picUrl);if(picUrl.indexOf('.jpg')!=-1){pictures.push(picUrl); picCount++;} })   console.log("找到圖片"+picCount+"張.");                var nextPageUrl=null;// 找下一頁$("#pages a").each(function(index,element){var text=$(element).text();if(text.indexOf('下一頁')!=-1){nextPageUrl=$(element).attr("href");  nextPageUrl="https://www.meitulu.com"+nextPageUrl;console.log("找到下一頁="+nextPageUrl);}         })if(nextPageUrl==null || nextPageUrl==pageUrl){console.log(pageUrl+"已經是最后一頁了.\n");saveFile(pageUrl,pictures);// 保存
                        download(pictures);}else{console.log("繼續下一頁");crawl(nextPageUrl);}               }    })}).on("error", function() {saveFile(pageUrl,pictures);// 保存console.log("crawl函數失敗,請進入斷點續傳模式繼續進行");})});// 超時處理req.setTimeout(7500,function(){req.abort();});// 出錯處理req.on('error',function(err){console.log('請求發生錯誤'+err);  saveFile(pageUrl,pictures);// 保存console.log("crawl函數失敗,請進入斷點續傳模式繼續進行");});// 請求結束
    req.end();
}//--------------------------------------
// 下載圖片
//--------------------------------------
function download(pictures){var total=0;total=pictures.length;console.log("總計有"+total+"張圖片將被下載.");appendToLogfile(folder,"總計有"+total+"張圖片將被下載.\n");for(var i=0;i<pictures.length;i++){var picUrl=pictures[i];downloadPic(picUrl,folder);}
}//--------------------------------------
// 寫log文件
//--------------------------------------
function appendToLogfile(folder,text){fs.appendFile('./'+folder+'/log.txt', text, function (err) {if(err){console.log("不能書寫log文件");console.log(err);}});
}//--------------------------------------
// 取得當前時間
//--------------------------------------
function getNowFormatDate() {var date = new Date();var seperator1 = "-";var seperator2 = "_";var month = date.getMonth() + 1;var strDate = date.getDate();if (month >= 1 && month <= 9) {month = "0" + month;}if (strDate >= 0 && strDate <= 9) {strDate = "0" + strDate;}var currentdate =date.getFullYear() + seperator1 + month + seperator1 + strDate+ " " + date.getHours() + seperator2 + date.getMinutes()+ seperator2 + date.getSeconds();return currentdate;
}//--------------------------------------
// 下載單張圖片
// picUrl sample:http://mtl.ttsqgs.com/images/img/12161/41.jpg
//--------------------------------------
function downloadPic(picUrl,folder){console.log("圖片:"+picUrl+"下載開始");// 得到hostname,path和portvar currUrl=picUrl.replace("http://","");var pos=currUrl.indexOf("/");var hostname=currUrl.slice(0,pos);        var path=currUrl.slice(pos);// 有端口加端口,沒有端口默認80var port=80;//console.log("hostname="+hostname);//console.log("path="+path);//console.log("port="+port);var picName=currUrl.slice(currUrl.lastIndexOf("/"));// 初始化options  options={hostname:hostname,port:port,path:path,method:'GET',/* headers:{'Referer':'https://www.meitulu.com',},*/};req=http.request(options,function(resp){var imgData = "";resp.setEncoding("binary"); resp.on('data',function(chunk){imgData+=chunk;            });resp.on('end',function(){        // 創建文件var fileName="./"+folder+picName;fs.writeFile(fileName, imgData, "binary", function(err){if(err){console.log("[downloadPic]文件   "+fileName+"  下載失敗.");console.log(err);appendToLogfile(folder,"文件  "+picUrl+"  下載失敗.\n");}else{appendToLogfile(folder,"文件  "+picUrl+"  下載成功.\n");console.log("文件"+fileName+"下載成功");}});    });});// 超時處理req.setTimeout(7500,function(){req.abort();});// 出錯處理req.on('error',function(err){if(err){console.log('[downloadPic]文件   '+picUrl+"  下載失敗,"+'因為'+err);appendToLogfile(folder,"文件"+picUrl+"下載失敗.\n");}});// 請求結束
    req.end();
}//--------------------------------------
// 程序入口 
//--------------------------------------
function getInput(){process.stdin.resume();    process.stdout.write("\033[33m 新建模式輸入第一頁URL,斷點續傳模式輸入0,請輸入: \033[39m");// 草黃色process.stdin.setEncoding('utf8');process.stdin.on('data',function(text){var input=text.trim();process.stdin.end();// 退出輸入狀態    if(text.trim()=='0'){process.stdout.write("\033[36m 進入斷點續傳模式. \033[39m");    // 藍綠色// Read Filefs.readFile('./save.dat','utf8',function(err,data){if(err){console.log('讀取文件save.dat失敗,因為'+err);}else{//console.log(data);var obj=JSON.parse(data);pictures=obj.pictures;console.log('提取圖片'+pictures.length+'張');folder=obj.folder;// 創建目錄fs.mkdir('./'+folder,function(err){if(err){console.log("目錄"+folder+"已經存在");}});crawl(obj.url);        }});// Resume crawl}else{process.stdout.write("\033[35m 進入新建模式. \033[039m");    //紫色
folder='pictures('+getNowFormatDate()+")";// 創建目錄fs.mkdir('./'+folder,function(err){if(err){console.log("目錄"+folder+"已經存在");}});crawl(input);            }});    
}//--------------------------------------
// 將爬行中信息存入數據文件
//--------------------------------------
function saveFile(url,pictures){var obj=new Object;obj.url=url;obj.pictures=pictures;obj.folder=folder;var text=JSON.stringify(obj);fs.writeFile('./save.dat',text,function(err){if(err){console.log('寫入文件save.dat失敗,因為'+err);}});
}// 調用getInput函數,程序開始
getInput();
復制代碼















本文轉自張昺華-sky博客園博客,原文鏈接:http://www.cnblogs.com/xiandedanteng/p/7871903.html,如需轉載請自行聯系原作者

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/540166.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/540166.shtml
英文地址,請注明出處:http://en.pswp.cn/news/540166.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[轉載] Java實現歸并排序(超詳細,新手請進)

參考鏈接&#xff1a; Java中將數組合并為的新數組 歸并排序 大家好&#xff0c;這是我第一次在CSDN上寫東西&#xff0c;因為我一直覺得有需要就去找別人的blog看看就好&#xff0c;但我發現自己寫出來的東西確實能加深記憶。我半路出家&#xff0c;屬實是個菜鳥&#xff0…

centos6設置靜態IP

#編輯配置文件,添加修改以下內容 vim /etc/sysconfig/network-scripts/ifcfg-eth0 BOOTPROTOstatic #啟用靜態IP地址 ONBOOTyes #開啟開機自動啟用網絡連接 IPADDR192.168.21.129 #設置IP地址 NETMASK255.255.255.0 #設置子網掩碼 GATEWAY192.168…

[轉載] 1022 D進制的A+B (20分)【java題解】【80ms】

參考鏈接&#xff1a; Java流Stream 題解 使用 toUnsignedString&#xff08;&#xff09;即可 我有仔細讀過toUnsignedString&#xff08;&#xff09;&#xff0c;有興趣可以看看 第3章 java的基本程序設計結構【補缺學習】【注釋與數據類型】【核心技術卷I】 impor…

mysql 5.6.4以上版本innodb支持全文索引的測試

對于mysql 5.6.4以上版本innodb支持全文索引的測試 在mysql官網&#xff0c;innodb引擎在5.6.4版本提供了對全文索引的支持&#xff0c;筆者對此做了測試&#xff0c;發現對中文全文檢索的支持依然不理想&#xff0c;但卻確實提供了對英文的全文支持。 12.9.5 Full-Text Restri…

[轉載] Java字符串分割方法

參考鏈接&#xff1a; Java中的StringTokenizer方法的示例 2 [sizemedium]1.用split()方法進行分割&#xff0c;分割開的子字符串放入數組&#xff0c;然后進行處理。 示例代碼如下&#xff1a; public class SplitTest { /** * param args * author colin */ …

[轉載] Java StringBuilder StringJoiner

參考鏈接&#xff1a; 何時在StringBuilder上使用StringJoiner 1. StringBuilder Java編譯器對String做了特殊處理&#xff0c;使得我們可以直接用拼接字符串。 雖然可以直接拼接字符串&#xff0c;但是&#xff0c;在循環中&#xff0c;每次循環都會創建新的字符串對象&a…

EMC VMAX的磁盤構成,fast policy(重要)

首先是流程&#xff0c; 不同種類的磁盤&#xff08;sata&#xff0c;fc&#xff0c;flah&#xff09;->disk group->raid->DATA volume->thin pool->TDEV and BCVDEV (lun) 然后細看&#xff1a; 1&#xff09; 不同種類的磁盤叫做disk&#xff0c;這是可見的物…

[轉載] Java反射是什么?看這篇絕對會了!

參考鏈接&#xff1a; Java中的util.Arrays與Reflection.Array的示例 作者&#xff1a;火星十一郎 https://www.cnblogs.com/hxsyl 一.概念 反射就是把Java的各種成分映射成相應的Java類。 Class類的構造方法是private&#xff0c;由JVM創建。 反射是java語言的一個特性…

[精講-3]Offline Domain Join

從windows 2008 ,windows 7開始起就具備脫機加入域的功能,就是它們在未連接DC的情況下,也可以加入域. 假如環境lab.com ,一臺已加入域的PC (WIN7Client) 和即將加入域的PC(win7-2) 在win7client上run下面這個命令 DC已作了一次預先的動作:創建了computer object 在win7-2上,用本…

[轉載] Java——toArray,集合轉換為數組

參考鏈接&#xff1a; 從ArrayList到Java的Array數組轉換&#xff1a;toArray()方法 package day04; import java.util.ArrayList; import java.util.Collection; /** * 集合轉換為數組 * Collection中定義了兩個方法 * Object[] toArray * <T>Y[] toArray(T[] array) …

c#匿名方法

//以下示例和說明都源于《visual c# 2005 技術內幕》 //匿名函數就是沒有名字的函數&#xff0c;是專用于委托的函數。 using System; using System.Collections.Generic; using System.Text; namespace 匿名方法 { public delegate void DelegateClass(); public dele…

[轉載] JAVA8 創建流的5種方式

參考鏈接&#xff1a; 用Java創建流的10種方法 java8中的流式操作是一個很重要的內容 1、通過 stream 方法把 List 或數組轉換為流&#xff0c;如Arr.stream()&#xff1b; //通過stream方法把List或數組轉換為流 Arrays.asList("a1", "a2", "a3&…

用戶反饋:對 Rafy 開發框架的一些個人建議

對Rafy開發框架的一些個人建議 1、潛在使用群體分析 個人認為使用類似Rafy、AgileEAS.NET、PDF.NET及OpenWorks框架的群體主要為以下幾種&#xff1a; 1.1、小微軟件企業 小微軟件企業&#xff0c;這類軟件公司的開發人員一般在10人以下&#xff0c;多以項目實施為主基本談不上…

[轉載] Java8新特新--Stream語法應用在ArrayList的元素移除和排序

參考鏈接&#xff1a; 如何在Java 8中打印Stream的元素 單元測試&#xff1a; Test public void Test02(){ // 源 ArrayList<Integer> IdsSour new ArrayList<>(); IdsSour.add(5); IdsSour.add(1); IdsSour.add(3); IdsSour.add(2); IdsSour.add(6); IdsSour.a…

搭建iscsi存儲系統

搭建iscsi存儲系統 NAS和SAN服務器概述 NAS網絡附屬存儲&#xff1a; NAS&#xff08;Network Attached Storage)&#xff0c;NAS服務器是連接在網絡上&#xff0c;具備資料存儲功能的服務器&#xff0c;一種與用數據存儲服務器。網絡附屬存儲基于標準網絡協議&#xff08;Tcp/…

[轉載] Java8 Stream流遍歷 如何使用索引

參考鏈接&#xff1a; Java 8中迭代帶有索引的流Stream 1. 問題來源 Java8的Stream流為我們的遍歷集合帶來了方便&#xff0c;基本可以取代for循環了。但是有一些情況需要知道當前遍歷的索引&#xff0c;使用for循環當然可以輕易獲得&#xff0c;但使用stream就很難了。 比如…

Jquery簡單的右側浮動菜單

今天有空稍微看了下Jquery動畫函數animate這個方法&#xff0c;發現可以用這個方法來做下簡單的右側浮動菜單 因為經常做淘寶頁面時候會碰到這樣的效果 以前都是用人家的javascript組件代碼 發現老是用人家也不好&#xff0c;所以今天有空用jqeury中的animate這個方法寫了一個簡…

[轉載] Java8-Stream API 詳解

參考鏈接&#xff1a; 如何在Java 8中從Stream獲取ArrayList 摘要 Stream 作為 Java 8 的一大亮點&#xff0c;它與 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 對 XML 解析的 Stream&#xff0c;也不是 Amazon Kinesis 對大數據實時處理…

在Microsoft System Center中利用您的現有投資管理VMware--Veeam MP v6.5

在 Microsoft System Center 中利用您的現有投資管理 VMware VeeamManagement Pack (MP) v6.5 適用于物理、虛擬和備份基礎架構的單一的虛擬管理平臺 前段時間介紹了Veeam Management Pack (MP) v6.0產品&#xff0c;昨天發布了新版本VeeamManagement Pack (MP) v6.5&#xff0…

[轉載] Java關鍵字(Java 8版本)

參考鏈接&#xff1a; 所有Java關鍵字列表 定義 被Java語言賦予了特殊含義&#xff0c;用作專門用途的字符串&#xff08;單詞&#xff09;&#xff0c;這些關鍵字不能用于常量、變量、和任何標識符的名稱。 Java關鍵字(Java 8版本) Java關鍵字(Java 8 以后版本) 注意事…