技术笔记: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日

相关文章
|
25天前
|
数据采集 JSON API
自动化Reddit图片收集:Python爬虫技巧
自动化Reddit图片收集:Python爬虫技巧
|
2天前
|
数据采集 Web App开发 XML
详尽分享用Node.js写爬虫,撸羞羞的图片
详尽分享用Node.js写爬虫,撸羞羞的图片
11 0
|
1月前
|
JSON JavaScript 前端开发
❤Nodejs 第九章(token身份认证和express-jwt的安装认识)
【4月更文挑战第9天】Node.js第九章介绍了Token身份认证,特别是JWT(JSON Web Token)作为跨域认证的解决方案。JWT由Header、Payload和Signature三部分组成,用于在客户端和服务器间安全传输用户信息。前端收到JWT后存储在localStorage或sessionStorage中,并在请求头中发送。Express-JWT是一个中间件,用于解析JWT。基本用法包括设置secret和algorithms。注意安全问题,避免混合使用不同算法以防止降级攻击。
59 0
|
24天前
|
前端开发
windows10 安装node npm 等前端环境 并配置国内源
windows10 安装node npm 等前端环境 并配置国内源
42 3
|
1月前
|
移动开发 JavaScript 前端开发
为了学习vue3,安装nvm进行node的多版本管理
为了学习vue3,安装nvm进行node的多版本管理
83 2
|
1月前
|
资源调度 jenkins 持续交付
jenkins 自动安装nodejs16.16.0版本报错处理
jenkins 自动安装nodejs16.16.0版本报错处理
95 0
|
1天前
|
Dart JavaScript 前端开发
npm install node-sass 安装失败的解决方案:利用国内镜像加速安装
npm install node-sass 安装失败的解决方案:利用国内镜像加速安装
9 1
|
4天前
|
JavaScript Linux
Linux安装nodejs
Linux安装nodejs
16 2
|
5天前
|
JavaScript Ubuntu Linux
蓝易云 - linux中安装nodejs,卸载nodejs,更新nodejs,git
请根据自己的Linux发行版和版本选择合适的命令。
12 2
|
2天前
|
JavaScript Linux
Linux安装nodejs指定版本
Linux安装nodejs指定版本
5 0