说到爬虫,很多人都认为是很高大上的东西。哇塞,是不是可以爬妹纸图啊,是不是可以爬小片片啊。答案就是对的。爬虫可以完成这些东西的操作。但是,作为一个正直的程序员,我们要在法律允许范围内用爬虫来为我们服务,而不是为所欲为。(ps:此处应有掌声,谢谢。)

  今天,我带来一个用Node.js写的爬虫。一说到教程呢,可能大多数人认为比较枯燥无味。那这样好了,我教大家爬妹纸图,上干货:

  是不是瞬间有了动力了?

  说到爬虫呢,其实从客观上来说,“所有网站皆可爬”。互联网的内容都是人写出来的,而且都是偷懒写出来的(不会第一页是a,下一页是8),所以肯定有规律,这就给人有了爬取的可能,可以说,天下没有不能爬的网站。而且即使网站不同,但是原理都类似,大部分爬虫都是从 发送请求——>获得页面——>解析页面——>下载内容——>储存内容 这样的流程来进行,只是用的工具不同,可能你用python,我用Node,他用PHP,但是思路也是与上面相同。

  既然是用node完成爬虫,那么我们就要用到node环境,如果不会配的话,请参考我的第一篇博客。

  好的,我们从爬虫流程开始分析我们需要的一些模块。

  首先,我们需要发送请求获得页面,在这里呢,我们用到了request-promise模块。

const rp = require("request-promise"), //进入request-promise模块
async getPage(URL) {
const data = {
url,
res: await rp({
url: URL
})
};
return data //这样,我们返回了一个对象,就是这个页面的url和页面内容。
}

  其次,解析页面,我们使用一个叫做Cheerio的模块将上面返回的对象中的res解析成类似JQ的调用模式。Cheerio使用一个非常简单,一致的DOM模型。因此解析,操作和渲染非常高效。初步的端到端基准测试表明cheerio 比JSDOM快大约8倍。

const cheerio = require("cheerio");//引入Cheerio模块
const $ = cheerio.load(data.res); //将html转换为可操作的节点

  此时,我们要对我们即将进行爬取的页面进行分析。“www.mzitu.com/125685”,这是我们进行爬取的网址,F12查看DOM结构:

  根据这个结构我们可以使用$(".main-image").find("img")[0].attribs.src来爬取这张图片的地址(如果不知道为什么是attribs.src的话可以一步一步console.log()一下看看)。

  最后,到了最关键的时候,我们使用fs模块进行创建文件夹以及下载文件。这里用到了fs模块的几个指令:

    1.fs.mkdirSync(downloadPath):查看是否存在这个文件夹。

    2.fs.mkdirSync(downloadPath):创建文件夹。

    3.fs.createWriteStream(`${downloadPath}/${index}.jpg`):写入文件,这里需要注意的是fs.createWriteStream 似乎不会自己创建不存在的文件夹,所以在使用之前需要注意,保存文件的文件夹一定要提前创建。

  好的,大体的方法就是以上的几个模块和步骤。

  在这里,我针对这个网站的一些情况进行一下分析:

    1.这个网站一个页面只有一张图片,但是每个页面的网址都是有根据的。“http://www.mzitu.com/125685”(当你输入“http://www.mzitu.com/125685/1”时也会跳转此页面),“http://www.mzitu.com/125685/2”等等。那么我们可以根据这个规律去爬取,并且我们需要在页面的下方的页码栏中获得这一组图图片的页码:

  

    2.我们一般不会只爬取一组图片,但是这个网站的图片的标题也就是最后的六位数基本没有规律可言,那么我们只能从最开始的首页入手。具体方法不多做描述,与获取图片的URL方式相同。

    3.同理,我们爬取完一页的目录之后会进行对第二个目录的爬取,“http://www.mzitu.com/page/2/”,其原理和第一条相同。

    4.但是,有的网站存在防盗链的情况,面对这种措施,我们需要伪造一个请求头来避开这个情况。这个可以从F12的Network中查到,看到这里的朋友我想也会明白。

let headers = {
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
Host: "i.meizitu.net",
Pragma: "no-cache",
"Proxy-Connection": "keep-alive",
Referer: data.url,//根据爬取的网址跟换
"Upgrade-Insecure-Requests": 1,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.19 Safari/537.36"
};

  以上就是我的全部思路。

  代码:

    业务代码:

const rp = require("request-promise"), //进入request-promise模块
fs = require("fs"), //进入fs模块
cheerio = require("cheerio"), //进入cheerio模块
depositPath = "D:/blog/reptile/meizi/"; //存放照片的地址
let downloadPath; //下载图片的文件夹地址
module.exports = {
async getPage(url) {
const data = {
url,
res: await rp({
url: url
})
};
return data;
},
getUrl(data) {
let list = [];
const $ = cheerio.load(data.res); //将html转换为可操作的节点
$("#pins li a")
.children()
.each(async (i, e) => {
let obj = {
name: e.attribs.alt, //图片网页的名字,后面作为文件夹名字
url: e.parent.attribs.href //图片网页的url
};
list.push(obj); //输出目录页查询出来的所有链接地址
});
return list;
},
getTitle(obj) {
downloadPath = depositPath + obj.name;
if (!fs.existsSync(downloadPath)) {//查看是否存在这个文件夹
fs.mkdirSync(downloadPath);//不存在就建文件夹
console.log(`${obj.name}文件夹创建成功`);
return true;
} else {
console.log(`${obj.name}文件夹已经存在`);
return false;
}
},
getImagesNum(res, name) {
if (res) {
let $ = cheerio.load(res);
let len = $(".pagenavi")
.find("a")
.find("span").length;
if (len == 0) {
fs.rmdirSync(`${depositPath}${name}`);//删除无法下载的文件夹
return 0;
}
let pageIndex = $(".pagenavi")
.find("a")
.find("span")[len - 2].children[0].data;
return pageIndex;//返回图片总数
}
},
//下载相册照片
async downloadImage(data, index) {
if (data.res) {
var $ = cheerio.load(data.res);
if ($(".main-image").find("img")[0]) {
let imgSrc = $(".main-image").find("img")[0].attribs.src;//图片地址
let headers = {
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "no-cache",
Host: "i.meizitu.net",
Pragma: "no-cache",
"Proxy-Connection": "keep-alive",
Referer: data.url,
"Upgrade-Insecure-Requests": 1,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.19 Safari/537.36"
};//反防盗链
await rp({
url: imgSrc,
resolveWithFullResponse: true,
headers
}).pipe(fs.createWriteStream(`${downloadPath}/${index}.jpg`));//下载
console.log(`${downloadPath}/${index}.jpg下载成功`);
} else {
console.log(`${downloadPath}/${index}.jpg加载失败`);
}
}
}
};

    主体逻辑代码:

const model = require("./model"),
basicPath = "http://www.mzitu.com/page/";
let start = 1,
end = 10;
const main = async url => {
let list = [],
index = 0;
const data = await model.getPage(url);
list = model.getUrl(data);
downLoadImages(list, index);//下载
};
const downLoadImages = async (list, index) => {
if (index == list.length) {
start++;
if (start < end) {
main(basicPath + start);//进行下一页图片组的爬取。
}
return false;
}
if (model.getTitle(list[index])) {
let item = await model.getPage(list[index].url),//获取图片所在网页的url
imageNum = model.getImagesNum(item.res,list[index].name);//获取这组图片的数量
for (var i = 1; i <= imageNum; i++) {
let page = await model.getPage(list[index].url + `/${i}`);//遍历获取这组图片每一张所在的网页
await model.downloadImage(page, i);//下载
}
index++;
downLoadImages(list, index);//循环完成下载下一组
} else {
index++;
downLoadImages(list, index);//下载下一组
}
};
main(basicPath + start);

  此次项目已上传我的Github仓库https://github.com/lunlunshiwo/NodeJs-crawler,求star,谢谢。

  总结:

  至于后续操作,比如存到分类保存到本地和MongoDB数据库这样的操作,我下次再写,请关注我。

  郑重提升,爬虫虽好,一定不能触犯法律。

  如果本本文触犯您的利益,请留言。

  如果觉得本文不错,不要吝啬您的点赞和关注。谢谢。

  

用Node.js写爬虫,撸羞羞的图片的更多相关文章

  1. Node.js 使用爬虫批量下载网络图片到本地

    图片网站往往广告众多,用Node.js写个爬虫下载图片,代码不长,省事不少,比手动一张张保存简直是天与地的区别.以前用Java也做过远程图片下载,但Node.js的下载速度更让人咂舌,这也是非阻塞式变 ...

  2. Node.js写文件的三种方法

    Node.js写文件的三种方式: 1.通过管道流写文件 采用管道传输二进制流,可以实现自动管理流,可写流不必当心可读流流的过快而崩溃,适合大小文件传输(推荐) var readStream = fs. ...

  3. 使用 Node.js 写一个代码生成器

    背景 第一次接触代码生成器用的是动软代码生成器,数据库设计好之后,一键生成后端 curd代码.之后也用过 CodeSmith , T4.目前市面上也有很多优秀的代码生成器,而且大部分都提供可视化界面操 ...

  4. 用node.js写一个简单爬虫,并将数据导出为 excel 文件

    引子 最近折腾node,最开始像无头苍蝇一样到处找资料,然而多数没什么卵用,都在瞎比比.在一阵瞎搞后,我来分享一下初步学习node的三个过程: 1 撸一遍NODE入门,对其有个基本的了解: 2 撸一遍 ...

  5. 基于node.js制作爬虫教程

    前言:最近想学习node.js,突然在网上看到基于node的爬虫制作教程,所以简单学习了一下,把这篇文章分享给同样初学node.js的朋友. 目标:爬取 http://tweixin.yueyishu ...

  6. Node.js 网页爬虫再进阶,cheerio助力

    任务还是读取博文标题. 读取app2.js // 内置http模块,提供了http服务器和客户端功能 var http=require("http"); // cheerio模块, ...

  7. dotnet调用node.js写的socket服务(websocket/socket/socket.io)

    https://github.com/jstott/socketio4net/tree/develop socket.io服务端node.js,.里面有js写的客户端:http://socket.io ...

  8. node.js+mongodb 爬虫

    demo截图: 本demo爬瓜子二手车北京区的数据 (注:需要略懂 node.js / mongodb 不懂也没关系 因为我也不懂啊~~~) 之所以选择爬瓜子二手车网站有两点: 一.网站无需登录,少做 ...

  9. 用node.js写个在Bash上对字符串进行Base64或URL的encode和decode脚本

    一:自己这段时间经常要用到Base64编码和URL编码,写个编译型语言有点麻烦干脆就用node.js弄了个,弄好后在/etc/profile里加上alias就能完成工具的配置,先上代码: functi ...

随机推荐

  1. Hibernate学习(一)创建数据表

    (1)生成数据库表的创建: // 默认读取hibernate.cfg.xml文件 Configuration cfg = new Configuration().configure(); // 生成并 ...

  2. Mysql利用存储过程插入400W条数据

    CREATE TABLE dept( /*部门表*/ deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*编号*/ dname VARCHAR(20) NO ...

  3. javascript正则表达式的一些笔记

    正则表达式:Regular Expression.使用单个字符串来描述,匹配一系列符合某个句法规则的字符串.即按照某种规则去匹配符合条件的字符串.正则表达式就是规则. \b 单词边界 regexp对象 ...

  4. numpy模块中的sum(axis)方法

    1.sum函数声明 sum(a, axis=None, dtype=None, out=None, keepdims=<class 'numpy._globals._NoValue'>) ...

  5. spring cloud熔断监控Hystrix Dashboard和Turbine

    参考: http://blog.csdn.net/ityouknow/article/details/72625646 完整pom <?xml version="1.0" e ...

  6. python 小练习之删除文件夹下的所有文件,包括子文件夹中的文件

    先屡一下思路 一步步怎么实现 1  要求是要删除所有文件(只是删除文件 而不是文件夹),所以 我们肯定要遍历这个文件目录 (for  in遍历) 2 每遍历一个元素时(文件),我们要判断该元素的属性是 ...

  7. NLP+VS=>Image Caption︱自动生成图像标题技术论文+相关项目

    读聪明人的笔记,是不是也能变聪明呢? Image Caption是一个融合计算机视觉.自然语言处理和机器学习的综合问题,它类似于翻译一副图片为一段描述文字. Image Caption问题可以定义为二 ...

  8. HighCharts之2D回归直线的散点

    HighCharts之2D回归直线的散点 1.实例源码 ScatterLine.html: <!DOCTYPE html> <html> <head> <me ...

  9. Naive Bayes (NB Model) 初识

    1,Bayes定理 P(A,B)=P(A|B)P(B); P(A,B)=P(B|A)P(A); P(A|B)=P(B|A)P(A)/P(B);    贝叶斯定理变形 2,概率图模型 2.1  定义 概 ...

  10. SUSE(Linux操作系统)

    suse linux 即 SUSE (Linux操作系统) . SUSE(发音为/zuz?/),发音的音频文件.SUSE Linux 原来是德国的 SuSE Linux AG公司发行维护的Linux发 ...