用Node.js通过sitemap.xml批量抓取美女图片


Posted in Javascript onMay 28, 2015

之前看了很多个版本,自己也搞一个。

1. 支持指定保存到哪个目录
2. 按文章进行分目录存放
3. 支持设置并行下载上限

下次有空再搞个整站下载的。

package.json

{
 "name": "me2sex-images",
 "version": "0.0.1",
 "description": "Batch download images from http://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

var node = {
  async: require('async'),
  cheerio: require('cheerio'),
  fs: require('fs'),
  mkdirp: require('mkdirp'),
  path: require('path'),
  request: require('request'),
  url: require('url'),
  xml2js: require('xml2js'),
};
 
var Me2SexImages = {
 
  /**
   * 配置选项
   */
  options: {
    // 网站sitemap地址
    sitemap: 'http://sexy.faceks.com/sitemap.xml',
    // 保存到此文件夹
    saveTo: '/Users/Fay/Pictures/me2sex',
    // 图片并行下载上限
    downLimit: 5,
  },
 
  posts: [],
 
  /**
   * 开始下载(程序入口函数)
   */
  start: function() {
    var self = this;
    var async = 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) {
    var self = this;
    return function() {
      var args = [].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) {
    var self = 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) {
    var self = this;
    var async = node.async;
    console.log('开始批量下载');
    async.eachSeries(self.posts, self.wrapTask(self.downPostImages), callback);
  },
 
 
  /**
   * 下载单个post的图片
   * @param {Object} post 文章
   */
  downPostImages: function(post, callback) {
    var self = this;
    var async = 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) {
    var path = node.path;
    var url = 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) {
    var url = node.url.parse(imgsrc);
    var fileName = node.path.basename(url.pathname);
    var toPath = 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();

以上所述就是本文的全部内容,希望大家能够喜欢。

Javascript 相关文章推荐
Jquery Change与bind事件代码
Sep 29 Javascript
iScroll中事件点击触发两次解决方案
Mar 11 Javascript
JS实现窗口加载时模拟鼠标移动的方法
Jun 03 Javascript
Windows系统下Node.js的简单入门教程
Jun 23 Javascript
jQuery实现滑动页面固定顶部显示(可根据显示位置消失与替换)
Oct 28 Javascript
JavaScript编写Chrome扩展实现与浏览器的交互及时间通知
May 16 Javascript
js中的面向对象入门
Mar 06 Javascript
ajax实现加载页面、删除、查看详细信息 bootstrap美化页面!
Mar 14 Javascript
JavaScript实现的超简单计算器功能示例
Dec 23 Javascript
React事件处理的机制及原理
Dec 03 Javascript
详解基于 Node.js 的轻量级云函数功能实现
Jul 08 Javascript
vue addRoutes路由动态加载操作
Aug 04 Javascript
javascript转换静态图片,增加粒子动画效果
May 28 #Javascript
jQuery实现限制textarea文本框输入字符数量的方法
May 28 #Javascript
javascript实现行拖动的方法
May 27 #Javascript
JavaScript操作Cookie方法实例分析
May 27 #Javascript
JavaScript通过事件代理高亮显示表格行的方法
May 27 #Javascript
jquery预加载图片的方法
May 27 #Javascript
jQuery仿gmail实现fixed布局的方法
May 27 #Javascript
You might like
PHP版国家代码、缩写查询函数代码
2011/08/14 PHP
PHP中的命名空间详细介绍
2015/07/02 PHP
老生常谈PHP面向对象之标识映射
2017/06/21 PHP
php apache开启跨域模式过程详解
2019/07/08 PHP
Windows服务器中PHP如何安装redis扩展
2019/09/27 PHP
PHP配合fiddler抓包抓取微信指数小程序数据的实现方法分析
2020/01/02 PHP
PHP设计模式(九)外观模式Facade实例详解【结构型】
2020/05/02 PHP
高性能WEB开发 flush让页面分块,逐步呈现 flush让页面分块,逐步呈现
2010/06/19 Javascript
JS动态显示表格上下frame的方法
2015/03/31 Javascript
微信小程序授权获取用户详细信息openid的实例详解
2017/09/20 Javascript
微信小程序 动画的简单实例
2017/10/12 Javascript
浅谈vue.js导入css库(elementUi)的方法
2018/03/09 Javascript
利用Node.js批量抓取高清妹子图片实例教程
2018/08/02 Javascript
Vue的watch和computed方法的使用及区别介绍
2018/09/06 Javascript
浅谈express.js框架中间件(middleware)
2019/04/07 Javascript
Vue 自定义标签的src属性不能使用相对路径的解决
2019/09/17 Javascript
javascript网页随机点名实现过程解析
2019/10/15 Javascript
JS实现旋转木马轮播图
2020/01/01 Javascript
js实现图片实时时钟
2020/01/15 Javascript
Vue前端判断数据对象是否为空的实例
2020/09/02 Javascript
Handtrack.js库实现实时监测手部运动(推荐)
2021/02/08 Javascript
[01:00:54]TI4正赛第二日开场
2014/07/20 DOTA
[00:27]DOTA2战队VP、Secret贺新春
2018/02/11 DOTA
pandas 数据索引与选取的实现方法
2019/06/21 Python
Python程序控制语句用法实例分析
2020/01/14 Python
Footshop罗马尼亚:最好的运动鞋选择
2019/09/10 全球购物
俄罗斯领先的移动和数字设备在线商店:Svyaznoy.ru
2020/12/21 全球购物
高中毕业自我鉴定
2013/12/16 职场文书
高一物理教学反思
2014/01/24 职场文书
《我的第一本书》教学反思
2014/02/15 职场文书
《商鞅南门立木》教学反思
2014/02/16 职场文书
计算机网络工程专业职业生涯规划书
2014/03/10 职场文书
法院信息化建设方案
2014/05/21 职场文书
2014年四风问题自我剖析材料
2014/09/15 职场文书
授权委托书协议书
2014/10/16 职场文书
go开发alertmanger实现钉钉报警
2021/07/16 Golang