序言
闲的无聊, 看到一个段子网站的美女福利还不错, 迫于福利加载太慢看的不过瘾, 就想用 Nodejs 写个简单爬虫全部爬下来看多好..... 此处省略 5000 字.....
准备
要爬, 首先得要有目标, 我呢, 就把目标锁定到了 某哈, 然后呢就是用浏览器来分析分析其中的规律
从中可以看到每一条段子都是一个 .joke-list-item, 当点击下一页的时候 url 中地址的最后一位数就表示分页的页码. 有些图片是缩略图, 我们把缩略图和正常图的地址进行了比较, 发现他们的地址格式是一样的, 缩略图在 small 文件夹下, 大图在 big 文件夹下. 分析完了我们就可以写代码了.
开始
这个简单爬虫分两个部分, 1, 获取图片地址. 2, 进行下载. 因为下载是一个耗时的操作, 所以两个部分分开了, 这样也有利于后期改动. 导入必要的模块, 使用 cheerio 是第三方模块, 可以使用 npm install cheerio 进行安装
html 代码
- var http = require('http'); // http 网路
- var cheerio = require('cheerio'); // html 解析
- var fs = require("fs"); // 流
- var queryHref = "http://www.haha.mx/topic/1/new/"; // 设置被查询的目标网址
- var querySearch = 1; // 设置分页位置
- var urls = []; // 所有待下载的图片地址
这个是解析图片地址方法
html 代码
- /**
- * 根据 url 和参数获取分页内容
- * @param {String}: url
- * @param {int}: serach
- */
- function getHtml(href, serach) {
- var pageData = "";
- var req = http.get(href + serach, function(res) {
- res.setEncoding('utf8');
- res.on('data', function(chunk) {
- pageData += chunk;
- });
- res.on('end', function() {
- $ = cheerio.load(pageData);
- var html = $(".joke-list-item .joke-main-content a img");
- for(var i = 0; i <html.length; i++) {
- var src = html[i].attribs.src;
- // 筛选部分广告, 不是真的段子
- if (src.indexOf("http://image.haha.mx")> -1) {
- urls.push(html[i].attribs.src)
- }
- }
- });
- });
- }
这个是下载图片的方法
html 代码
- /**
- * 下载图片
- * @param {String} imgurl: 图片地址
- */
- function downImg(imgurl) {
- var narr = imgurl.replace("http://image.haha.mx/", "").split("/")
- http.get(imgurl.replace("/small/", "/big/"), function(res) {
- var imgData = "";
- // 一定要设置 response 的编码为 binary 否则会下载下来的图片打不开
- res.setEncoding("binary");
- res.on("data", function(chunk) {
- imgData += chunk;
- });
- res.on("end", function() {
- var savePath = "./upload/topic1/" + narr[0] + narr[1] + narr[2] + "_" + narr[4];
- // 保存图片
- fs.writeFile(savePath, imgData, "binary", function(err) {
- if(err) {
- console.log(err);
- }
- });
- });
- });
- }
好, 到这里核心的东西就写完了, 然后就是组装一下, 让他运行起来
附一个完整代码:
html 代码
- var http = require('http'); // http 网路
- var cheerio = require('cheerio'); // html 解析
- var fs = require("fs"); // 流
- // 设置被查询的目标网址
- var queryHref = "http://www.haha.mx/topic/1/new/";
- // 设置分页位置
- var querySearch = 1;
- var urls = [];
- /**
- * 根据 url 和参数获取分页内容
- * @param {String}: url
- * @param {int}: serach
- */
- function getHtml(href, serach) {
- var pageData = "";
- var req = http.get(href + serach, function(res) {
- res.setEncoding('utf8');
- res.on('data', function(chunk) {
- pageData += chunk;
- });
- res.on('end', function() {
- $ = cheerio.load(pageData);
- var html = $(".joke-list-item .joke-main-content a img");
- for(var i = 0; i <html.length; i++) {
- var src = html[i].attribs.src;
- // 筛选部分广告, 不是真的段子
- if (src.indexOf("http://image.haha.mx")> -1) {
- urls.push(html[i].attribs.src)
- }
- }
- if (serach == pagemax) {
- console.log("图片链接获取完毕!" + urls.length);
- console.log("链接总数量:" + urls.length);
- if (urls.length> 0) {
- downImg(urls.shift());
- } else {
- console.log("下载完毕");
- }
- }
- });
- });
- }
- /**
- * 下载图片
- * @param {String} imgurl: 图片地址
- */
- function downImg(imgurl) {
- var narr = imgurl.replace("http://image.haha.mx/", "").split("/")
- http.get(imgurl.replace("/small/", "/big/"), function(res) {
- var imgData = "";
- // 一定要设置 response 的编码为 binary 否则会下载下来的图片打不开
- res.setEncoding("binary");
- res.on("data", function(chunk) {
- imgData += chunk;
- });
- res.on("end", function() {
- var savePath = "./upload/topic1/" + narr[0] + narr[1] + narr[2] + "_" + narr[4];
- fs.writeFile(savePath, imgData, "binary", function(err) {
- if(err) {
- console.log(err);
- } else {
- console.log(narr[0] + narr[1] + narr[2] + "_" + narr[4]);
- if (urls.length> 0) {
- downImg(urls.shift());
- } else {
- console.log("下载完毕");
- }
- }
- });
- });
- });
- }
- var pagemax = 10; // 获取 10 页的内容
- function start(){
- console.log("开始获取图片连接");
- for (var i = 1 ; i <= pagemax ; i++) {
- getHtml(queryHref, i);
- }
- }
- start();
因为 nodejs 是异步的, 所以在 start 方法中的 for 之后调用下载是不行, 这个时候显示的 urls 中是没有数据的. 所以就是在 getHtml 中 等所有的连接分析完毕之后在调用 downImg,downImg 下载完成之后在进行下一个下载. 项目目录很简单, 如图:
然后我们切换到项目目录, 执行 node app , 然后就静静的等待把, 每次下载完一个会有对应的文件名打印出来的.
最后会出现 下载完毕!, 之后就....... 你懂得......
这个是一个很简单的, 当然后续你可以加上数据库, 数据更新之类的.....
放几张我爬到的图
- .
- .
- .
- .
- .
- .
- .
- .
- .
注意前方高能
注意前方高能
注意前方高能
- .
- .
- .
- .
- .
- .
- .
- .
- .
- .
- .
- .
来源: http://www.qdfuns.com/article/31109/7f57d65b1c79531f05bd495f9cbf2995.html