引入
在上一篇文章我们利用Node.js实现了一个基本的爬虫,但是要写很长的正则--实在太累了而且需要对正则绝对熟悉。 在写前端我们都知道jQuery能方便帮我我们进行各种DOM操作,通过DOM操作我们可以方便的获取元素的各种属性,不过jqDOM操作只能运行在客户端,如果服务端有这样的一个工具能帮我们进行DOM操作那不是就解决了之前不断写正则的问题? 当然有---cheerio
cheerio是jquery核心功能的一个快速灵活而又简洁的实现,主要是为了用在服务器端需要对DOM进行操作的地方
你可以把cheerio当做服务端的jQuery
我们先来看一个案例---爬取百度logo 如果是之前的方式我们要写一堆正则才能匹配到某网站的logo,而使用了cheerio后我们可以进行DOM操作直接获取数据
可以看到终端直接输出了百度logo
案例爬取表情包
安装cheerio npm i cheerio
如图我们要爬取该网站的表情包
分析
1.我们以列表页为起始页,该页面展示了表情包的分类,我们要获取所有分类的url
2.获取分类名称,根据分类名称创建文件夹
3.根据分类url获取到该分类的所有图片url
4.根据图片url,进行流请求将图片下载到相应的文件夹下面
1.首先通过入口页获取分类url 经过调试发现分类绑定在.bqba
类名上,我们可以直接进行dom操作获取url
const axios = require('axios')
const cheerio = require('cheerio')
const fs = require('fs')
const path = require('path')
const url = require('url')
let host = 'https://www.fabiaoqing.com'
async function getData(url){
let res = await axios.get(url)
let $ = cheerio.load(res.data)
$('.bqba').each(async (i,e)=>{
//图片分类地址
let url = host $(e).attr('href')
console.log(url)
})
}
getData('https://www.fabiaoqing.com/bqb/lists/page/1.html')
获取到分类url
代码语言:javascript复制https://www.fabiaoqing.com/bqb/detail/id/54195.html
https://www.fabiaoqing.com/bqb/detail/id/54176.html
https://www.fabiaoqing.com/bqb/detail/id/54194.html
https://www.fabiaoqing.com/bqb/detail/id/54198.html
https://www.fabiaoqing.com/bqb/detail/id/54193.html
https://www.fabiaoqing.com/bqb/detail/id/54196.html
https://www.fabiaoqing.com/bqb/detail/id/54186.html
https://www.fabiaoqing.com/bqb/detail/id/54185.html
https://www.fabiaoqing.com/bqb/detail/id/54169.html
https://www.fabiaoqing.com/bqb/detail/id/54135.html
接下来我们要获取到分类名并且创建分类文件夹
代码语言:javascript复制async function getData(url){
let res = await axios.get(url)
let $ = cheerio.load(res.data)
$('.bqba').each(async (i,e)=>{
//图片分类地址
let url = host $(e).attr('href')
//图片分类名称
let folderReg = /\|/|:|*|?|<|>||/g
let title = $(e).find('h1').text().replace(folderReg,'-')
// 创建图片分类文件夹
fs.mkdir('./img/' title,function(err){
if(!err){
console.log('成功创建目录' title)
}
})
})
}
我们对分类名称进行了替换使其符合文件夹创建规则
接下来我们要根据分类url获取到相应的图片url 经过调试发现图片绑定了类名 bqbppdetail
async function getData(url){
....
// 下载图片
parsePage(url,title)
})
}
async function parsePage(url,title){
let res = await axios.get(url)
let $ = cheerio.load(res.data)
$('.bqbppdetail').each((i,e)=>{
let imgUrl = $(e).attr('data-original')
console.log(imgUrl)
})
}
获取到图片url
代码语言:javascript复制...
http://wx2.sinaimg.cn/bmiddle/006GJQvhgy1ghovr2w8gtj31fr1ln4k0.jpg
http://wx1.sinaimg.cn/bmiddle/006GJQvhgy1ghovr51917j31rl1rlx4r.jpg
...
接下来我们将这些图片下载下来以流请求的方式下载
代码语言:javascript复制async function getData(url){
....
// 下载图片
parsePage(url,title)
})
}
async function parsePage(url,title){
let res = await axios.get(url)
let $ = cheerio.load(res.data)
$('.bqbppdetail').each((i,e)=>{
let imgUrl = $(e).attr('data-original')
//图片后缀
let ext = path.extname(imgUrl)
//图片文件名
let imgPath = `./img/${title}/${title}-${i}${ext}`
//创建写入流
const ws = fs.createWriteStream(imgPath,function(err){
if(err){
console.log(err)
}
})
//流的形式请求图片资源
axios.get(imgUrl,{responseType:'stream'}).then(function(res){
//写入流
res.data.pipe(ws)
console.log("图片加载完成:" imgPath)
//监听关闭流操作
res.data.on('close',function(){
// ws.close()
console.log('创建完毕' imgPath)
})
})
})
}
图片下载成功
到此一个简单的爬虫完毕。
但是我们只爬取了单页的图片,一般网站都会涉及到分页,接下来我们将分页的数据一并爬取
分析
1.我们从起始页就可以获取到该网站的总页数
2.循环总页数获取数据每次url后缀 1
代码语言:javascript复制https://www.fabiaoqing.com/bqb/lists/page/2.html
||
https://www.fabiaoqing.com/bqb/lists/page/3.html
||
...
https://www.fabiaoqing.com/bqb/lists/page/1066.html
代码语言:javascript复制async function spider(url){
let res = await axios.get(url)
let $ = cheerio.load(res.data)
//获取总页数
let allPage = 30
/*$('.disabled.item').next().text().trim()==1066*/
//循环总页数下载图片
for(let i=0;i<allPage;i ){
getData('https://www.fabiaoqing.com/bqb/lists/page/' i '.html')
}
}
这里我们获取总页面进行循环,由于数据太多我这里只设置了30页,当请求的较多时我们应该控制请求,设置每秒请求多少次,这样尽可能保证资源的完整性也不至于将对方服务端搞崩溃。
如下构建延迟函数
代码语言:javascript复制function witeMe(mis){
return new Promise((resolve,reject)=>{
setTimeout(function(){
resolve("成功执行延迟函数,延迟:" mis)
},mis)
})
}
在请求多的地方调用该函数
代码语言:javascript复制...
for(let i=0;i<allPage;i ){
await witeMe(2000*i)
getData('https://www.fabiaoqing.com/bqb/lists/page/' i '.html')
}
...