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

相关文章
|
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,通过分析其核心优势和实际应用案例,揭示其在现代软件开发中的重要性和潜力。
146 2
|
3月前
|
数据采集 JavaScript C#
C#图像爬虫实战:从Walmart网站下载图片
C#图像爬虫实战:从Walmart网站下载图片
|
2月前
|
数据采集 存储 数据挖掘
深入探索 Python 爬虫:高级技术与实战应用
本文介绍了Python爬虫的高级技术,涵盖并发处理、反爬虫策略(如验证码识别与模拟登录)及数据存储与处理方法。通过asyncio库实现异步爬虫,提升效率;利用tesseract和requests库应对反爬措施;借助SQLAlchemy和pandas进行数据存储与分析。实战部分展示了如何爬取电商网站的商品信息及新闻网站的文章内容。提醒读者在实际应用中需遵守法律法规。
200 66
|
27天前
|
JavaScript 前端开发 中间件
JS服务端技术—Node.js知识点
本文介绍了Node.js中的几个重要模块,包括NPM、Buffer、fs模块、path模块、express模块、http模块以及mysql模块。每部分不仅提供了基础概念,还推荐了相关博文供深入学习。特别强调了express模块的使用,包括响应相关函数、中间件、Router和请求体数据解析等内容。文章还讨论了静态资源无法访问的问题及其解决方案,并总结了一些通用设置。适合Node.js初学者参考学习。
33 1
|
1月前
|
数据采集 Web App开发 iOS开发
如何利用 Python 的爬虫技术获取淘宝天猫商品的价格信息?
本文介绍了使用 Python 爬虫技术获取淘宝天猫商品价格信息的两种方法。方法一使用 Selenium 模拟浏览器操作,通过定位页面元素获取价格;方法二使用 Requests 和正则表达式直接请求页面内容并提取价格。每种方法都有详细步骤和代码示例,但需注意反爬措施和法律法规。
|
1月前
|
数据采集 存储 Web App开发
利用Python 的爬虫技术淘宝天猫销量和库存
使用 Python 爬虫技术获取淘宝天猫商品销量和库存的步骤包括:1. 安装 Python 和相关库(如 selenium、pandas),下载浏览器驱动;2. 使用 selenium 登录淘宝或天猫;3. 访问商品页面,分析网页结构,提取销量和库存信息;4. 处理和存储数据。注意网页结构可能变化,需遵守法律法规。
|
2月前
|
数据采集 Web App开发 JavaScript
Selenium爬虫技术:如何模拟鼠标悬停抓取动态内容
本文介绍了如何使用Selenium爬虫技术抓取抖音评论,通过模拟鼠标悬停操作和结合代理IP、Cookie及User-Agent设置,有效应对动态内容加载和反爬机制。代码示例展示了具体实现步骤,帮助读者掌握这一实用技能。
Selenium爬虫技术:如何模拟鼠标悬停抓取动态内容
|
2月前
|
数据采集 安全 定位技术
Burpsuite Spider爬虫功能
Burpsuite Spider爬虫功能
|
3月前
|
数据采集 机器学习/深度学习 搜索推荐
Python爬虫技术基础与应用场景详解
本文介绍了爬虫技术的基本概念、原理及应用场景,包括数据收集、价格监测、竞品分析和搜索引擎优化等。通过一个实战案例展示了如何使用Python爬取电商网站的商品信息。强调了在使用爬虫技术时需遵守法律法规和道德规范,确保数据抓取的合法性和合规性。