node.js之妙用cheerio模块多方案爬取网上资源

加油,每天总结一点点进步生活每一天!

cheerio模块

http模块配合cheerio爬数据
cheerio模块的作用是分析数据的内容/具体信息

用 fs.writeFile()方法下载数据

下载一张图片案例

var https=require("https")
var fs=require("fs")
var url="https://img04.sogoucdn.com/net/a/04/link?url=http%3A%2F%2Fimg03.sogoucdn.com%2Fapp%2Fa%2F100520024%2F968013acbc34fa232b16607a4b519eab&appid=122"
https.get(url,(res)=>{
    // 如果你想下载文本就要设置成res.setEncoding('utf8');
    res.setEncoding("binary")
    // 如上 res.setEncoding("binary")
    // 是吧把请求的格式转成图片的格式,不然下载的图片失效
    var t=""
    res.on("data",(chunk)=>{
        t+=chunk
    })
    res.on("end",(chunk)=>{
        fs.writeFile("./图片/tp.jpg",t,"binary",function(err){
            if(err){
                console.log("图片下载失败!",err);
            }else{
                console.log("图片下载成功!");
            }
        })
    })
}).on("err",function(err){
    if(err){
        console.log("图片下载失败!");
    }
}
)

爬虫爬取图片地址信息

// 通过http模块发起网络请求
const https=require("https");
const { on } = require("process");
const fs=require("fs")
var cheerio=require("cheerio")
let url="https://www.qunar.com/" //https://www.baidu.com/  
//https://www.qunar.com/
https.get(url, (res) => {
    // 请求成功的回调!
  const { statusCode } = res;
  const contentType = res.headers['content-type'];
console.log(statusCode,contentType);
var t=""
// 监听数据的改变,流读取,当一个数据片段传递完毕后触发
// 每个网页的数据片段都不一样的大小,和不一样的数据片段个数
// 所以上面let出来的url不同监听数据的改变也可能不一样的次数
// 可以理解为 on data事件和on end 事件他们都是监听作用
res.on("data",(chunk)=>{
    t=t+chunk
// console.log("数据改变了!",chunk.toString());
})
// 数据传输结束,所有数据都传输完毕之后触发
res.on("end",()=>{
    // fs.writeFile("./qunar.html",t,(err)=>{
    // if(err){
    //     console.log("下载失败,报错信息为→",err);
    // }else{
    //     console.log("完美下载成功!");
    // }
    // })
    // console.log("全部整合的数据",t);
    // console.log("数据传输结束!");

    // 使用cheerio 分析数据的内容
    const $=cheerio.load(t)
    $("img").each((index,el)=>{
        console.log("图片"+index);
        console.log($(el).attr("src"));
    })
})
}).on('error', (e) => {
    // on方法通常是事件监听
    // 监听如果请求错误就执行这个回调函数
  console.error(`出现错误: ${e.message}`);
});

我们用request请求配合 fs.createWriteStream爬数据,以李宁官网数据为准.搞他数据就完事儿.

在这里插入图片描述
在这里插入图片描述

因为下面的cheerio使用的方法和jQuery方法类似所以我们先讲解方法

JQUERYFIND()方法
find()
作用是查找某元素下的某后代元素的集合
find()方法的参数是js里面的选择器
$(".x").find(".sp")
如上代码表示获取类名为x的元素线下的子元素中所有类名为所有sp的元素
$(".x")是jquery的实例,如果想让jquery实例变成dom元素就写成
$(".x")[0]如果想让dom元素变成jquery实例就直接把dom
元素放到
$()方法的括号内部如
    var x=document.querySelector(".x")
    console.log(x);
    console.log($(x));

例子如下:
$(".d1").find("span").each((idex, el) => {
        console.log("索引:", idex, "元素:", el)
        const name = $(el).text()
        console.log(name)
    })

JQUERYEACH()方法
each(index,el)这个方法主要用作循环东西的参数一为index索引参数二为元素el,el这个参数用console.log(index,el);
打印出来会是一个dom元素
<body>
    <div class="d1">
        <span class="s1">心心相印</span>
        <span class="s2">洁柔</span>
    </div>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
<script>
    // jquery中each方法
    // 有两种语法的写法
    // 如下是法一:
    // each()方法有两个参数
    // 第一个是参数是数组或者对象,
    // 第一个参数可以写在each()方法的小括号里面也可以写在小括号外面
    // 但是第二个参数callback必须写在each()方法的小括号内部
    // 第一个参数写在each()方法外面的时候连接方法的时候必须用.
    $(".d1").find("span").each((idex, el) => {
        console.log("索引:", idex, "元素:", el)
        const name = $(el).text()
        console.log(name)
    })

    // 如下是法二:
    
    $.each($(".d1").find("span"), (idex, el) => {
        console.log("索引:", idex, "元素:", el)
        const name = $(el).text()
        console.log(name)
    })
</script>

下面是我们爬图正文代码

var express = require("express")
var cheerio = require("cheerio")
var request = require("request")
var path=require("path")
var fs=require("fs")
const {
    response
} = require("express")
var app = express()
var url = "https://store.lining.com/shop/goodsCate-sale,desc,1,15s15_122,15_122,15_122_m,15_122s15_122_11-0-0-15_122_11-0s0-0-0-min,max-0.html"
// 获取目标地址的html结构
var shuju=0
request.get(url, (err, response, body) => {
    // 定义一个空数组
    var goodsArry = []
    var $ = cheerio.load(body)
    $(".cate_search_content").find(".selItem").each((index, el) => {
        var $el=$(el)
        var name=$el.find(".hgoodsName").text()
        var price=$el.find(".price").text()
        price=price.match(/[\d\.]+/)[0]
        var imgurl=$el.find(".selMainPic img").attr("orginalsrc")
        var fileName=path.basename(imgurl)
        // 先创建好一个文件写入流,定义好在某个文件夹下写入什么文件,文件名和文件格式类型
        const fileStream=fs.createWriteStream("./img/"+fileName)
        // request(填入参数是地址的时候,返回值是一个数据流)
        // 我们把请求回来的图片的数据流导入到文件写入流当中
        // 他就把图片写入到文件夹里了
        // ★const fileStream=fs.createWriteStream("./img/"+fileName)
        // 这段代码其实可以是告诉程序要在某个地址当中写入某个文件,然而并没有数据可以写入
        // 下面这行代码,是我们请求回来了数据然后,导入到创建好的写入流当中,已经有数据了所以就可以写入了
        request(imgurl).pipe(fileStream)
        // 可以有个简单的比喻如下去理解上面的流文件写入👇
        // 比如说我先在千峰教育预定一个座位告诉招生老师我改天交学费,让老师给你在某个教室留了一个座位并且告诉班主任,这个座位是某某某名字同学预定了的座位,让班主任先别安排别的同学入座,过了几天后你交学费了,这个座位就名副其实了,你就坐到你预定的那个座位去上课了.
        var goods={
            name,
            price,
            imgurl:"./img/"+fileName
        }
        goodsArry.push(goods)
        console.log(goodsArry);
        shuju=goodsArry
    })
})
app.get("/shuju",(req,res)=>{
 res.send(shuju)
})
app.listen(3840, () => {
    console.log("服务器端口号3840已经成功开启!");
})

经典总结
如上我们用了fs.write方法和文档写入流的形式爬取数据
二者之间的区别在哪里呢?
如果我们请求的数据或者下载的数据内存过大,使用fs.write这个方法很可能就会报错,而用流的形式是分段式写入所以不会报错.所以尽量用流的形式去请求或者下载数据。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值