功能:批量下載www.27270.com的圖片,輸入首頁網址,其他的事情程序幫完成。
本程序只用來研究爬蟲技術。
//======================================================
// 27270圖片批量下載爬蟲1.00
//
// 2018年3月22日
//======================================================
// 內置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:http://www.27270.com/ent/meinvtupian/2017/232865.html
// pageUrl sample:http://www.27270.com/ent/lianglimeimo/2015/51083.html
//--------------------------------------
function crawl(pageUrl){
console.log("Current page="+pageUrl);
// 獲得hostname和path
var currUrl=pageUrl.replace("http://","");
var pos=currUrl.indexOf("/");
var hostname=currUrl.slice(0,pos);
var path=currUrl.slice(pos);
pos=currUrl.lastIndexOf("/");
var dir="http://"+currUrl.slice(0,pos+1);
//console.log("hostname="+hostname);
//console.log("path="+path);
//console.log("dir="+dir);
// 初始化options
options={
hostname:hostname,
port:80,
path:path,// 子路徑
method:'GET',
};
req=http.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 = iconv.decode(buffer,'gb2312'); // 特意增長的,爲了讓漢字不亂碼,header裏面有<meta http-equiv="Content-Type" content="text/html; charset=gb2312">字樣都須要iconv幫忙轉碼
//console.log("body="+body);
var $ = cheerio.load(body);
var picCount=0;
// 找圖片放入數組
$("#picBody p a 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;
// 找下一頁
$("#nl a").each(function(index,element){
var text=$(element).text();
if(text.indexOf('下一頁')!=-1){
nextPageUrl=dir+$(element).attr("href");
console.log("找到下一頁.="+nextPageUrl);
}
})
if(nextPageUrl==null){
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://www.avbaike.net/wp-content/uploads/2016/08/108.jpg
//--------------------------------------
function downloadPic(picUrl,folder){
console.log("圖片:"+picUrl+"下載開始");
// 獲得hostname,path和port
var currUrl=picUrl.replace("http://","");
var pos=currUrl.indexOf("/");
var hostname=currUrl.slice(0,pos);
var path=currUrl.slice(pos);
// 有端口加端口,沒有端口默認80
var port=80;
if(hostname.indexOf(":")!=-1){
var arr=hostname.split(":");
hostname=arr[0];
port=arr[1];
}
//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.nvshens.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 File
fs.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();