Node.js图片爬虫

最近一直在写微信小程序,没时间看nodejs,今天就把之前写的图片爬虫拉出来晒一晒,免得彻底忘记~写的还不完善,还没时间继续,请开始嘲笑我的烂代码~

 首页展示

 

开始爬取图片

 

下载图片

前端界面 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;

转载于:https://www.cnblogs.com/xiaomingSun/p/8548919.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值