用Node.js通过sitemap.xml批量抓取美女图片
之前看了很多个版本,自己也搞一个。
1.支持指定保存到哪个目录
2.按文章进行分目录存放
3.支持设置并行下载上限
下次有空再搞个整站下载的。
package.json
{ "name":"me2sex-images", "version":"0.0.1", "description":"Batchdownloadimagesfromhttp://me2-sex.lofter.com", "main":"index.js", "author":"Fay", "license":"MIT", "dependencies":{ "async":"^0.9.0", "cheerio":"^0.18.0", "mkdirp":"^0.5.0", "request":"^2.51.0", "url":"^0.10.2", "xml2js":"^0.4.4" } }
index.js
varnode={ async:require('async'), cheerio:require('cheerio'), fs:require('fs'), mkdirp:require('mkdirp'), path:require('path'), request:require('request'), url:require('url'), xml2js:require('xml2js'), }; varMe2SexImages={ /** *配置选项 */ options:{ //网站sitemap地址 sitemap:'http://sexy.faceks.com/sitemap.xml', //保存到此文件夹 saveTo:'/Users/Fay/Pictures/me2sex', //图片并行下载上限 downLimit:5, }, posts:[], /** *开始下载(程序入口函数) */ start:function(){ varself=this; varasync=node.async; async.waterfall([ self.wrapTask(self.sitemapXML), self.wrapTask(self.sitemapJSON), self.wrapTask(self.downAllImages), ],function(err,result){ if(err){ console.log('error:%s',err.message); }else{ console.log('success:下载成功'); } }); }, /** *包裹任务,确保原任务的上下文指向某个特定对象 *@param{Function}task符合asycs.js调用方式的任务函数 *@param{Any}context上下文 *@param{Array}exArgs额外的参数 *@return{Function}符合asycs.js调用方式的任务函数 */ wrapTask:function(task,context,exArgs){ varself=this; returnfunction(){ varargs=[].slice.call(arguments); args=exArgs?exArgs.concat(args):args; task.apply(context||self,args); }; }, /** *获取站点sitemap.xml */ sitemapXML:function(callback){ console.log('开始下载sitemap.xml'); node.request(this.options.sitemap,function(err,res,body){ if(!err)console.log('下载sitemap.xml成功'); callback(err,body); }); }, /** *将sitemap.xml转成json */ sitemapJSON:function(sitemapXML,callback){ varself=this; console.log('开始解析sitemap.xml'); node.xml2js.parseString(sitemapXML,{explicitArray:false},function(err,json){ if(!err){ self.posts=json.urlset.url; self.posts.shift(); console.log('解析sitemap.xml成功,共有%d个页面',self.posts.length); } callback(err,self.posts); }); }, /** *下载整站图片 */ downAllImages:function(callback){ varself=this; varasync=node.async; console.log('开始批量下载'); async.eachSeries(self.posts,self.wrapTask(self.downPostImages),callback); }, /** *下载单个post的图片 *@param{Object}post文章 */ downPostImages:function(post,callback){ varself=this; varasync=node.async; async.waterfall([ self.wrapTask(self.mkdir,self,[post]), self.wrapTask(self.getPost), self.wrapTask(self.parsePost), self.wrapTask(self.downImages), ],callback); }, mkdir:function(post,callback){ varpath=node.path; varurl=node.url.parse(post.loc); post.dir=path.join(this.options.saveTo,path.basename(url.pathname)); console.log('准备创建目录:%s',post.dir); if(node.fs.existsSync(post.dir)){ callback(null,post); console.log('目录:%s已经存在',post.dir); return; } node.mkdirp(post.dir,function(err){ callback(err,post); console.log('目录:%s创建成功',post.dir); }); }, /** *获取post内容 */ getPost:function(post,callback){ console.log('开始请求页面:%s',post.loc); node.request(post.loc,function(err,res,body){ if(!err)post.html=body; callback(err,post); console.log('请求页面成功:%s',post.loc); }); }, /** *解析post,并获取post中的图片列表 */ parsePost:function(post,callback){ var$=post.$=node.cheerio.load(post.html); post.images=$('.img') .map(function(){return$(this).attr('bigimgsrc');}) .toArray(); callback(null,post); }, /** *下载post图片列表中的图片 */ downImages:function(post,callback){ console.log('发现%d张妹子图片,准备开始下载...',post.images.length); node.async.eachLimit( post.images, this.options.downLimit, this.wrapTask(this.downImage,this,[post]), callback ); }, /** *下载单个图片 */ downImage:function(post,imgsrc,callback){ varurl=node.url.parse(imgsrc); varfileName=node.path.basename(url.pathname); vartoPath=node.path.join(post.dir,fileName); console.log('开始下载图片:%s,保存到:%s,文件名:%s',imgsrc,post.dir,fileName); node.request(imgsrc) .pipe(node.fs.createWriteStream(toPath)) .on('close',function(){ console.log('图片下载成功:%s',imgsrc); callback(); }) .on('error',callback); } }; Me2SexImages.start();
以上所述就是本文的全部内容,希望大家能够喜欢。