技术笔记:Node.jsmm131图片批量下载爬虫1.01增加断点续传功能

简介: 技术笔记:Node.jsmm131图片批量下载爬虫1.01增加断点续传功能

这里的断点续传不是文件下载时的断点续传,而是指在爬行页面时有时会遇到各种网络中断而从中断前的页面及其数据继续爬行的过程,这个过程和断点续传原理上相似故以此命名。我的具体做法是:在下载出现故障或是图片已经全部获得时,将存储目录,当前爬行页面和已经获取的图片地址以json形式存储到数据文件中,而用户选择断点续传模式时提取数据文件中的这三条信息,继而从上次中断之处重新运行。


数据文件示例:


{"url":"","pictures":【"","","",""】,"folder":"pictures(2017-11-18 15_531)"}


Node.js 代码如下:


//======================================================


// mm131图片批量下载爬虫1.01


// 1.00 具备功能


// 1.01 增加断点续传


// 2017年11月15日


//======================================================


// 内置http模块


var http=require("http");


// 内置文件处理模块,用于创建目录和图片文件


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:


// pageUrl sample:


// pageUrl sample:


//--------------------------------------


function crawl(pageUrl){


console.log("Current page="+pageUrl);


// 得到hostname和path


var currUrl=pageUrl.replace("","");


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: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'); // 特地增加的,为了让汉字不乱码


//console.log(body);


var $ = cheerio.load(body);


var picCount=0;


// 找图片放入数组


$(".content-pic 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;


// 找下一页


$(".content-page a").each(function(index,element){


var text=$(element).text();


if(text.indexOf('下一页')!=-1){


nextPageUrl=$(element).attr("href");


nextPageUrl=""+nextPageUrl;// 把省略部分加上


console.log("找到下一页.");


}


})


if(nextPageUrl==null){


console.log(pageUrl+"已经是最后一页了.\n");


saveFile(pageUrl,pictures);// 保存


download(pictures);


}else{


//console.log("下一页是"+nextPageUrl);


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



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:


//--------------------------------------


function downloadPic(picUrl,folder){


console.log("图片:"+picUrl+"下载开始");


// 得到hostname,path和port


var currUrl=picUrl.replace("","");


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);


//代码效果参考: http://www.jhylw.com.cn/324937419.html

//console.log("port="+port);


var picName=currUrl.slice(currUrl.lastIndexOf("/"));


// 初始化options


options={


hostname:hostname,


port:port,


path:path,// 子路径


method:'GET',


headers:{


'Referer':'',


}


};


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+" 下载失败.");


//代码效果参考:http://www.jhylw.com.cn/233941497.html

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();


2017年11月16日

相关文章
|
24天前
|
Web App开发 JavaScript 前端开发
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念,包括事件驱动、单线程模型和模块系统;探讨其安装配置、核心模块使用、实战应用如搭建 Web 服务器、文件操作及实时通信;分析项目结构与开发流程,讨论其优势与挑战,并通过案例展示 Node.js 在实际项目中的应用,旨在帮助开发者更好地掌握这一强大工具。
44 1
|
2月前
|
JavaScript 前端开发 中间件
探索后端技术:Node.js与Express框架的完美融合
【10月更文挑战第7天】 在当今数字化时代,Web应用已成为日常生活不可或缺的一部分。本文将深入探讨后端技术的两大重要角色——Node.js和Express框架,分析它们如何通过其独特的特性和优势,为现代Web开发提供强大支持。我们将从Node.js的非阻塞I/O和事件驱动机制,到Express框架的简洁路由和中间件特性,全面解析它们的工作原理及应用场景。此外,本文还将分享一些实际开发中的小技巧,帮助你更有效地利用这些技术构建高效、可扩展的Web应用。无论你是刚入门的新手,还是经验丰富的开发者,相信这篇文章都能为你带来新的启发和思考。
|
2月前
|
JavaScript 前端开发 API
探索后端技术:Node.js的优势和实际应用
【10月更文挑战第6天】 在当今数字化时代,后端开发是任何成功软件应用的关键组成部分。本文将深入探讨一种流行的后端技术——Node.js,通过分析其核心优势和实际应用案例,揭示其在现代软件开发中的重要性和潜力。
158 2
|
1月前
|
JavaScript 前端开发 中间件
JS服务端技术—Node.js知识点
本文介绍了Node.js中的几个重要模块,包括NPM、Buffer、fs模块、path模块、express模块、http模块以及mysql模块。每部分不仅提供了基础概念,还推荐了相关博文供深入学习。特别强调了express模块的使用,包括响应相关函数、中间件、Router和请求体数据解析等内容。文章还讨论了静态资源无法访问的问题及其解决方案,并总结了一些通用设置。适合Node.js初学者参考学习。
38 1
|
3月前
|
JavaScript 前端开发
Vue、ElementUI配合Node、multiparty模块实现图片上传并反显_小demo
如何使用Vue和Element UI配合Node.js及multiparty模块实现图片上传并反显的功能,包括前端的Element UI组件配置和后端的Node.js服务端代码实现。
52 1
Vue、ElementUI配合Node、multiparty模块实现图片上传并反显_小demo
|
3月前
|
前端开发 JavaScript
node接收前端上传的图片,单文件、多文件同name、多文件不同name
本文介绍了在Node.js中使用multer模块接收前端上传的图片,包括单文件上传、多文件上传(同name和不同name)以及任意类型文件上传的方法。
92 0
|
3月前
|
存储 JSON 前端开发
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘
本文介绍了在Node.js中使用token实现前端验证码和登录功能的详细流程,包括生成验证码、账号密码验证以及token验证和过期处理。
59 0
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘
|
2月前
|
数据采集 安全 定位技术
Burpsuite Spider爬虫功能
Burpsuite Spider爬虫功能
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的图像识别技术深入理解Node.js事件循环及其在后端开发中的应用
【8月更文挑战第27天】本文将介绍深度学习中的图像识别技术,包括其原理、应用领域及未来发展。我们将探讨如何通过神经网络实现图像识别,并分析其在医疗、交通等领域的应用。最后,我们将展望图像识别技术的发展前景。
|
4月前
|
JavaScript 关系型数据库 MySQL
node连接mysql,并实现增删改查功能
【8月更文挑战第26天】node连接mysql,并实现增删改查功能
98 3