Node.js圖片爬蟲

最近一直在寫微信小程序,沒時間看nodejs,今天就把以前寫的圖片爬蟲拉出來曬一曬,省得完全忘記~寫的還不完善,還沒時間繼續,請開始嘲笑個人爛代碼~javascript

 首頁展現

 

開始爬取圖片

 

下載圖片

前端界面 index.html

<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="UTF-8">
		<title>圖片爬蟲</title>
		<style>
		</style>
		
	</head>
	<body>	
			<form method="post" autocomplete="off" action="/Interface/downloadImage">
				<div><span class="title">網站 URL:</span><input name="url" type="text" value="https://www.cnblogs.com">
				</div>
				
				<div><span class="title">存儲路徑:</span><input type="text" name="savePath" value="./images" /></div>
				<div>
					<span class="title">分       頁:</span>
					<span>第</span>
					<input name="beginPage" placeholder="#p1" class="page" value="#p1" />
					<span>到</span>
					<input placeholder="#p3" name="endPage" class="page"value="#p3" />
					<span>頁</span> 
					<span style="color: red;font-size: 12px;">(支持兩種格式分頁,例如連接上的#p20、#pn20或者?p=20、?pn=20,根據目標URL判斷是否屬於這兩種中的一種,不屬於或不分頁不填)</span>
				</div>
				<div><input type="submit" class="submit" value="開始爬取"></div>
			</form>				
	</body>
</html>

  

index.js(啓動 node index.js)

var http = require('http');
var fs = require('fs');
var url = require('url');
var path = require("path");
var querystring = require('querystring');
var downloadImg = require('./downloadimg');

// 建立服務器
http.createServer(function(request, response) {

	var body = "";
	request.on('data', function(chunk) {
		body += chunk;
	});
	request.on('end', function() {
		// 解析參數
		body = querystring.parse(body);

		if(body.url) { // 輸出提交的數據
			POST(body, response)

		} else {
			// 解析請求,包括文件名
			var pathname = url.parse(request.url).pathname.substr(1);
			if(pathname == "") {
				pathname = "index.html"
			}
			// 從文件系統中讀取請求的文件內容
			fs.readFile(pathname, function(err, data) {

				if(err) {
					console.log(err);
					response.writeHead(404, {
						'Content-Type': 'text/html'
					});
				} else {
					// HTTP 狀態碼: 200 : OK
					// Content Type: text/plain
					switch(path.extname(pathname)) {
						case ".html":
							response.writeHead(200, {
								'Content-Type': 'text/html'
							});
							break;
						case ".js":
							response.writeHead(200, {
								'Content-Type': 'text/javascript'
							});
							break;
					}

					// 響應文件內容
					response.write(data.toString());
				}
				//  發送響應數據
				response.end();
			});
		}
	});

}).listen(8081);

//處理post請求
function POST(body, response) {
	if(body.url) {
		// 設置響應頭部信息及編碼
		response.writeHead(200, {
			'Content-Type': 'text/html; charset=utf8'
		});
		response.write("<p style='margin:2px 0;padding:3px 0;'>正在準備下載..</p>")
		setTimeout(function() {
			downloadImg.downloadimg(
				body,
				function(msg, err) {
					if(err) {

						response.write("<p style='color:#2196f3;margin:2px 0;border-bottom:1px solid #CCC;padding:3px 0;font-size:12px;'>" + err + '</p>')
					} else {
						response.write("<p style='color:green;margin:2px 0;border-bottom:1px solid #CCC;padding:3px 0;font-size:12px;'>" + msg + '</p>')

					}
				},
				function(successMsg, errMsg) {
					if(successMsg) response.end("<p style='background:green;color:#FFF;position:fixed;top:0;left:0;width:100%;padding:10px;margin:0'>" + successMsg + "</p>")
					if(errMsg) response.end("<p style='background:red;color:#FFF;position:fixed;top:0;left:0;width:100%;padding:10px;margin:0'>" + errMsg + "</p>")
				}
			)
		}, 2000)

	}

}

downloadimg.js

//依賴模塊
var fs = require('fs');
var request = require("request");
var cheerio = require("cheerio");
var mkdirp = require('mkdirp');
var http = require('http');
var urlm = require('url');
var querystring = require("querystring");

//建立目標網址http請求模塊
var downloadimg = function(body, imgcallback, endcallback) {
	//解析post參數
	var url = body.url;
	var dir = body.savePath || './images'; //獲取保存目錄
	var page = {
		begin: body.beginPage,
		end: body.endPage
	};

	//建立目錄
	mkdirp(dir, function(err) {
		if(err) {
			console.log(err);
		}
	});

	//第一次發送請求
	getRequest(url, dir, imgcallback, endcallback, page);

}

//請求目標地址
var getRequest = function(url, dir, imgcallback, endcallback, page) {
	//獲取地址真實
	var pageUrl = getPageUrl(page, url)
	//打印當前請求地址
	if(page.currentIndex) {
		imgcallback(0, "正在分析第" + page.currentIndex + "頁," + pageUrl)
	} else {
		imgcallback(0,"正在分析" + pageUrl)
	}
	//開始請求
	request(url, function(error, response, body) {
		if(!error && response.statusCode == 200) {

			images = imageArrangement(body, url,
				function(errmsg) {
					//網站分析失敗回調,傳回錯誤信息
					endcallback(0, errmsg)
				},
				function(imageSrcArr) {
					console.log(imageSrcArr)
					//網站body分析成功,返回圖片完整地址數組:imageSrcArr
					//初始化完成數量
					var complateImageLength = 0;

					for(var i = 0; i < imageSrcArr.length; i++) {
						var item = imageSrcArr[i];
						//獲取圖片名
						var fileName = item.split('/').pop();

						//建立下載
						download(item, dir, fileName, function(imagsrc, err) {
							complateImageLength++;
							//一張下載完成						
							imgcallback(imagsrc + "下載成功", err)
							//所有下載完成
							if(complateImageLength == imageSrcArr.length) {
								//分頁
								if(page.currentIndex < page.EndIndex) {
									page.currentIndex++;
									//獲取分頁地址
									//var pageUrl = getPageUrl(page,urldata)
									getRequest(url, dir, imgcallback, endcallback, page);

								} else {

									endcallback('下載完成,保存在' + dir)

								}
							}
						});
					}
				})
		}
	});
}
//網站body分析,圖片整理,返回圖片地址數組
var imageArrangement = function(body, url, errorcallback, successcallback) {
	//errorcallback:網站爬取失敗回調
	var $ = cheerio.load(body);
	//找到img所在標籤目錄
	var images = $('img');

	//排除非正常圖片
	images.each(function(index, item) {
		var img = $(this)
		var src = img.attr('src') + "";
		//base64暫時不下載
		if(src == 'undefined' || src.length == 0 || src.indexOf('base64') > -1) {
			images.splice(index, 1)
			return;
		}

	});
	var imageSrcArr = [];
	images.each(function(index, item) {
		var img = $(this)
		var src = item.attribs.src.split('?')[0]; //下載文件路徑含有search時會形成下載失敗
		//獲取文件根路徑
		var rootPathname = urlm.parse(src).pathname.substr(0, 1) == '/' ? urlm.parse(src).pathname : '/' + urlm.parse(src).pathname;
		//防止圖片地址不完整重新拼接
		if(!/(http|https)/.test(src)) {
			src = src.substr(0, 2) == '//' ? 'http:' + src : 'http://' + urlm.parse(url).host + rootPathname;
		} else if(!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(src)) {
			//排除非圖片後綴
			return;
		}
		imageSrcArr.push(src)
	})
	//圖片數目爲0,返回錯誤結束響應
	if(!imageSrcArr.length) {
		//網站不包含圖片標籤,結束下載
		errorcallback('下載失敗:該網站不包含圖片或者網站禁止爬蟲')
		return;
	}
	successcallback(imageSrcArr)
}
//圖片下載方法,保存到dir
var download = function(url, dir, filename, callback) {
	request.head(url, function(err, res, body) {
		if(err) console.log(err)
		//callback下載完成回調
		//傳入流:fsa.pipe(fsb),fsa必須是存在的流,但fsb不存在會建立;pipe方法是可讀流導入可寫流
		request(url).pipe(fs.createWriteStream(dir + "/" + filename)).on('close', function() {
			//下載完成傳回地址,錯誤信息
			callback(url, err)
		})
	});
};
//獲取分頁真實地址
function getPageUrl(page, url) {
	var urldata = urlm.parse(url);
	if(!urldata.protocol && !urldata.host) {
		//請求出地址不完整,結束
		//return;
	}
	if( page.begin && page.end ) {
		page.BeginIndex = page.begin.replace(/[^0-9]/ig, "");
		page.EndIndex = page.end.replace(/[^0-9]/ig, "");
		var pageIag = page.begin.replace(/\d+/g, '');
		page.currentIndex = page.currentIndex || page.BeginIndex;
		if(page.BeginIndex && page.EndIndex) {
			//hash分頁			
			if(/#/.test(page.begin) && /#/.test(page.end)) {
				url = urldata.protocol + '//' + urldata.host + urldata.path + pageIag + page.currentIndex
				//querystring分頁
			} else if(/=/.test(page.begin) && /=/.test(page.end)) {
				var querystringData = querystring.parse(url);
			}
		}
	}
	return url;
}
//導出下載模塊
exports.downloadimg = downloadimg;
相關文章
相關標籤/搜索