nodejs批量下载图片的实现方法
今天想获取一大批猫的图片,然后就在360流浪器搜索框中输入猫,然后点击图片。就看到了一大波猫的图片:http://image.so.com/i?q=%E7%8...,我在想啊,要是审查元素,一张张手动下载,多麻烦,所以打算写程序来实现。不写不知道,一写发现里面还是有很多道道的。
1. 爬取图片链接
因为之前也写过nodejs爬虫功能,所以觉得应该很简单,就用cheerio来处理dom啦,结果打印一下啥也没有,后来查看源代码:
发现waterfall_zoom里面空空如也,查找了一下,发现所有的数据都是写在<script>里面,然后动态加载到页面的,所以用cheerio.load到的页面里面其实没数据的。真实数据:
分析完毕,刷刷写代码:
var request = require('request'); var cheerio = require('cheerio'); var url = 'http://image.so.com/i?q=%E7%8C%AB&src=tab_www'; request(url,function(err,res,body){ if(!err && res.statusCode === 200){ var $ = cheerio.load(body); var imgList = [] JSON.parse($('script[id="initData"]').html()).list.forEach(function(item){ imgList.push(item.img) }); console.log(imgList); } });
2. 下载图片到本地
2.1 粗糙的方案
最初的思路很简单,简单的fs.createWriteStream()就能解决:
var downloadPic = function(src, dest){ request(src).pipe(fs.createWriteStream(dest)).on('close',function(){ console.log('pic saved!') }) }
使用方式:
downloadPic(imgList[0],'./catpics/1.jpg');
成功捕获一只猫!然后写了一个循环准备捕获所有猫。然而这种方式是串行的,速度很慢!下载一大批图片要花大量时间。
2.2 使用async异步批量下载
关于async的map操作,详见:async_demo/map.js,对集合中的每一个元素,执行某个异步操作,得到结果。所有的结果将汇总到最终的callback里。与forEach的区别是,forEach只关心操作不管最后的值,而map关心的最后产生的值。
提供了两种方式:
- 并行执行。async.map同时对集合中所有元素进行操作,结果汇总到最终callback里。如果出错,则立刻返回错误以及已经执行完的任务的结果,未执行完的占个空位
- 顺序执行。async.mapSeries对集合中的元素一个一个执行操作,结果汇总到最终callback里。如果出错,则立刻返回错误以及已经执行完的结果,未执行的被忽略。
在此处:
async.mapSeries(imgList,function(item, callback){ setTimeout(function(){ downloadPic(item, './catpics/'+ (new Date()).getTime() +'.jpg'); callback(null, item); },400); }, function(err, results){});
注:此处使用setTimeout,是因为下载需要一定时间,在笔者较慢网速下,需要400ms的间隔能确保每张图片下载完全。
成功捕获一批猫猫!
2.3 使用bagpipe批量
bagpipe是朴灵大大做的一个在nodejs中控制并发执行的模块。其安装和使用也比较简单:
npm install bagpipe --save
使用:
var Bagpipe = require('bagpipe'); var bagpipe = new Bagpipe(10); var files = ['这里有很多很多文件']; for(vari =0; i < files.length; i++){ bagpipe.push(fs.readFile, files[i], 'utf-8',function(err, data){ ... }); }
在此处:
var bagpipe = new Bagpipe(10,{timeout: 100}); for(var i = 0; i < imgList.length; i++) { console.log('i:'+i) bagpipe.push(downloadPic, imgList[i], './catpics/'+ i +'.jpg', function(err, data){ // }); }
3.总结
作为一个程序员,能用程序解决就不手动解决。每一次尝都会有新的收获。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
- 使用闪回查询备份数据(r2笔记43天)
- 生产环境sql语句调优实战第四篇(r2笔记41天)
- 生产环境sql语句调优实战第五篇(r2笔记41天)
- python实现逻辑logistic回归:预测病马的死亡率
- 开发 | 图片数据集太少?看我七十二变,Keras Image Data Augmentation 各参数详解
- linux过滤空文件的命令总结(r2笔记40天)
- shell脚本自动化采集性能sql(r2笔记39天)
- R语言与点估计学习笔记(EM算法与Bootstrap法)
- 开发 | 为个人深度学习机器选择合适的配置
- 阿里音乐流行趋势预测竞赛数据清洗整合——纯python
- 生产环境sql语句调优实战第二篇(r2第38天)
- 生产环境sql语句调优实战第三篇(r2笔记38天)
- 简单易学的机器学习算法——K-Means算法
- 通过shell脚本定位性能sql和生成报告(r2笔记37天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ubuntu16.04配置samba解决linux的svn使用舒适问题
- Erlang学习笔记(1)
- 结合公司现状浅谈CMDB
- SQLAlchemy使用
- 常用Oracle SQL集锦
- Python、PyGame游戏项目
- windows 认证机制
- 谷歌地球引擎python文档(GEE_python_API)
- react基础
- 基于ASP.NET Core 3.x的端点路由(Endpoint Routing)实现控制器(Controller)和操作(Action)分离的接口服务
- 流量转发映射
- 什么情况用ArrayList or LinkedList呢?
- 拒绝服务攻击
- 协议攻击(一)
- 百亿级图数据JanusGraph迁移之旅