Node.js meitulu图片批量下载爬虫1.051

原有1.05版程序没有断点续传模式,现在在最近程序基础上改写一版1.051.

复制代码
//======================================================
// meitulu图片批量下载爬虫1.051
// 用最近的断点续传框架改写原有1.05版程序
// 2017年11月21日
//======================================================// 内置https模块
var https=require("https");// 内置http模块
var http=require("http");// 用于解析gzip网页(ungzip,https得到的网页是用gzip进行压缩的)
var zlib = require('zlib'); // 内置文件处理模块,用于创建目录和图片文件
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:https://www.meitulu.com/item/12161.html
// pageUrl sample:
//--------------------------------------
function crawl(pageUrl){console.log("Current page="+pageUrl);// 得到hostname和pathvar currUrl=pageUrl.replace("https://","");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:443,path:path,// 子路径method:'GET',        };req=https.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 = buffer.toString();//console.log(body);
zlib.gunzip(buffer, function(err, decoded) {if(err){console.log("[findPageUrls]不能得到页面:"+batchPageUrl+"对应的html文本,错误是:"+err);console.log(err);}else{var body=decoded.toString();   //console.log(body);var $ = cheerio.load(body);        var picCount=0;// 找图片放入数组$(".content  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;// 找下一页$("#pages a").each(function(index,element){var text=$(element).text();if(text.indexOf('下一页')!=-1){nextPageUrl=$(element).attr("href");  nextPageUrl="https://www.meitulu.com"+nextPageUrl;console.log("找到下一页="+nextPageUrl);}         })if(nextPageUrl==null || nextPageUrl==pageUrl){console.log(pageUrl+"已经是最后一页了.\n");saveFile(pageUrl,pictures);// 保存
                        download(pictures);}else{console.log("继续下一页");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<pictures.length;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:http://mtl.ttsqgs.com/images/img/12161/41.jpg
//--------------------------------------
function downloadPic(picUrl,folder){console.log("图片:"+picUrl+"下载开始");// 得到hostname,path和portvar currUrl=picUrl.replace("http://","");var pos=currUrl.indexOf("/");var hostname=currUrl.slice(0,pos);        var path=currUrl.slice(pos);// 有端口加端口,没有端口默认80var port=80;//console.log("hostname="+hostname);//console.log("path="+path);//console.log("port="+port);var picName=currUrl.slice(currUrl.lastIndexOf("/"));// 初始化options  options={hostname:hostname,port:port,path:path,method:'GET',/* headers:{'Referer':'https://www.meitulu.com',},*/};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+"  下载失败.");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 Filefs.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();
复制代码















本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/xiandedanteng/p/7871903.html,如需转载请自行联系原作者

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/540166.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转载] Java实现归并排序(超详细,新手请进)

参考链接&#xff1a; Java中将数组合并为的新数组 归并排序 大家好&#xff0c;这是我第一次在CSDN上写东西&#xff0c;因为我一直觉得有需要就去找别人的blog看看就好&#xff0c;但我发现自己写出来的东西确实能加深记忆。我半路出家&#xff0c;属实是个菜鸟&#xff0…

centos6设置静态IP

#编辑配置文件,添加修改以下内容 vim /etc/sysconfig/network-scripts/ifcfg-eth0 BOOTPROTOstatic #启用静态IP地址 ONBOOTyes #开启开机自动启用网络连接 IPADDR192.168.21.129 #设置IP地址 NETMASK255.255.255.0 #设置子网掩码 GATEWAY192.168…

[转载] 1022 D进制的A+B (20分)【java题解】【80ms】

参考链接&#xff1a; Java流Stream 题解 使用 toUnsignedString&#xff08;&#xff09;即可 我有仔细读过toUnsignedString&#xff08;&#xff09;&#xff0c;有兴趣可以看看 第3章 java的基本程序设计结构【补缺学习】【注释与数据类型】【核心技术卷I】 impor…

mysql 5.6.4以上版本innodb支持全文索引的测试

对于mysql 5.6.4以上版本innodb支持全文索引的测试 在mysql官网&#xff0c;innodb引擎在5.6.4版本提供了对全文索引的支持&#xff0c;笔者对此做了测试&#xff0c;发现对中文全文检索的支持依然不理想&#xff0c;但却确实提供了对英文的全文支持。 12.9.5 Full-Text Restri…

[转载] Java字符串分割方法

参考链接&#xff1a; Java中的StringTokenizer方法的示例 2 [sizemedium]1.用split()方法进行分割&#xff0c;分割开的子字符串放入数组&#xff0c;然后进行处理。 示例代码如下&#xff1a; public class SplitTest { /** * param args * author colin */ …

[转载] Java StringBuilder StringJoiner

参考链接&#xff1a; 何时在StringBuilder上使用StringJoiner 1. StringBuilder Java编译器对String做了特殊处理&#xff0c;使得我们可以直接用拼接字符串。 虽然可以直接拼接字符串&#xff0c;但是&#xff0c;在循环中&#xff0c;每次循环都会创建新的字符串对象&a…

EMC VMAX的磁盘构成,fast policy(重要)

首先是流程&#xff0c; 不同种类的磁盘&#xff08;sata&#xff0c;fc&#xff0c;flah&#xff09;->disk group->raid->DATA volume->thin pool->TDEV and BCVDEV (lun) 然后细看&#xff1a; 1&#xff09; 不同种类的磁盘叫做disk&#xff0c;这是可见的物…

[转载] Java反射是什么?看这篇绝对会了!

参考链接&#xff1a; Java中的util.Arrays与Reflection.Array的示例 作者&#xff1a;火星十一郎 https://www.cnblogs.com/hxsyl 一.概念 反射就是把Java的各种成分映射成相应的Java类。 Class类的构造方法是private&#xff0c;由JVM创建。 反射是java语言的一个特性…

[精讲-3]Offline Domain Join

从windows 2008 ,windows 7开始起就具备脱机加入域的功能,就是它们在未连接DC的情况下,也可以加入域. 假如环境lab.com ,一台已加入域的PC (WIN7Client) 和即将加入域的PC(win7-2) 在win7client上run下面这个命令 DC已作了一次预先的动作:创建了computer object 在win7-2上,用本…

[转载] Java——toArray,集合转换为数组

参考链接&#xff1a; 从ArrayList到Java的Array数组转换&#xff1a;toArray()方法 package day04; import java.util.ArrayList; import java.util.Collection; /** * 集合转换为数组 * Collection中定义了两个方法 * Object[] toArray * <T>Y[] toArray(T[] array) …

c#匿名方法

//以下示例和说明都源于《visual c# 2005 技术内幕》 //匿名函数就是没有名字的函数&#xff0c;是专用于委托的函数。 using System; using System.Collections.Generic; using System.Text; namespace 匿名方法 { public delegate void DelegateClass(); public dele…

[转载] JAVA8 创建流的5种方式

参考链接&#xff1a; 用Java创建流的10种方法 java8中的流式操作是一个很重要的内容 1、通过 stream 方法把 List 或数组转换为流&#xff0c;如Arr.stream()&#xff1b; //通过stream方法把List或数组转换为流 Arrays.asList("a1", "a2", "a3&…

用户反馈:对 Rafy 开发框架的一些个人建议

对Rafy开发框架的一些个人建议 1、潜在使用群体分析 个人认为使用类似Rafy、AgileEAS.NET、PDF.NET及OpenWorks框架的群体主要为以下几种&#xff1a; 1.1、小微软件企业 小微软件企业&#xff0c;这类软件公司的开发人员一般在10人以下&#xff0c;多以项目实施为主基本谈不上…

[转载] Java8新特新--Stream语法应用在ArrayList的元素移除和排序

参考链接&#xff1a; 如何在Java 8中打印Stream的元素 单元测试&#xff1a; Test public void Test02(){ // 源 ArrayList<Integer> IdsSour new ArrayList<>(); IdsSour.add(5); IdsSour.add(1); IdsSour.add(3); IdsSour.add(2); IdsSour.add(6); IdsSour.a…

搭建iscsi存储系统

搭建iscsi存储系统 NAS和SAN服务器概述 NAS网络附属存储&#xff1a; NAS&#xff08;Network Attached Storage)&#xff0c;NAS服务器是连接在网络上&#xff0c;具备资料存储功能的服务器&#xff0c;一种与用数据存储服务器。网络附属存储基于标准网络协议&#xff08;Tcp/…

[转载] Java8 Stream流遍历 如何使用索引

参考链接&#xff1a; Java 8中迭代带有索引的流Stream 1. 问题来源 Java8的Stream流为我们的遍历集合带来了方便&#xff0c;基本可以取代for循环了。但是有一些情况需要知道当前遍历的索引&#xff0c;使用for循环当然可以轻易获得&#xff0c;但使用stream就很难了。 比如…

Jquery简单的右侧浮动菜单

今天有空稍微看了下Jquery动画函数animate这个方法&#xff0c;发现可以用这个方法来做下简单的右侧浮动菜单 因为经常做淘宝页面时候会碰到这样的效果 以前都是用人家的javascript组件代码 发现老是用人家也不好&#xff0c;所以今天有空用jqeury中的animate这个方法写了一个简…

[转载] Java8-Stream API 详解

参考链接&#xff1a; 如何在Java 8中从Stream获取ArrayList 摘要 Stream 作为 Java 8 的一大亮点&#xff0c;它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream&#xff0c;也不是 Amazon Kinesis 对大数据实时处理…

在Microsoft System Center中利用您的现有投资管理VMware--Veeam MP v6.5

在 Microsoft System Center 中利用您的现有投资管理 VMware VeeamManagement Pack (MP) v6.5 适用于物理、虚拟和备份基础架构的单一的虚拟管理平台 前段时间介绍了Veeam Management Pack (MP) v6.0产品&#xff0c;昨天发布了新版本VeeamManagement Pack (MP) v6.5&#xff0…

[转载] Java关键字(Java 8版本)

参考链接&#xff1a; 所有Java关键字列表 定义 被Java语言赋予了特殊含义&#xff0c;用作专门用途的字符串&#xff08;单词&#xff09;&#xff0c;这些关键字不能用于常量、变量、和任何标识符的名称。 Java关键字(Java 8版本) Java关键字(Java 8 以后版本) 注意事…