详解如何使用Node.js开发一个简单图片爬取功能

来自:互联网
时间:2022-06-30
阅读:

爬虫的主要目的是收集互联网上公开的一些特定数据。利用这些数据我们可以能进行分析一些趋势对比,或者训练模型做深度学习等等。本期我们就将介绍一个专门用于网络抓取的 node.js 包—— node-crawler ,并且我们将用它完成一个简单的爬虫案例来爬取网页上图片并下载到本地。

正文

node-crawler 是一个轻量级的 node.js 爬虫工具,兼顾了高效与便利性,支持分布式爬虫系统,支持硬编码,支持http前级代理。而且,它完全是由 nodejs 写成,天生支持非阻塞异步IO,为爬虫的流水线作业机制提供了极大便利。同时支持对 DOM 的快速选择(可以使用 jQuery 语法),对于抓取网页的特定部分的任务可以说是杀手级功能,无需再手写正则表达式,提高爬虫开发效率。

安装引入

我们先新建一个项目,在里面创建index.js作为入口文件。

然后进行爬虫库 node-crawler 的安装。

# PNPM
pnpm add crawler
# NPM
npm i -S crawler
# Yarn 
yarn add crawler

然后用过 require 引入进去。

// index.js
const Crawler = require("crawler");

创建实例

// index.js
let crawler = new Crawler({
    timeout:10000,
    jQuery:true,
})
function getImages(uri) {
    crawler.queue({
        uri,
        callback: (err, res, done) => {
            if (err) throw err;
        }
    })
}

从现在我们将开始写一个拿到html页面的图片的方法,crawler 实例化后,在其队列中主要是为了写入链接和回调方法。在每个请求处理完毕后将调这个回调函数。

这里还要说明一下, Crawler 使用了 request 库,所以 Crawler 可供配置的参数列表是 request 库的参数的超集,即 request 库中所有的配置在 Crawler 中均适用。

元素捕获

刚才或许你也看到了 jQuery 这个参数,你猜的没错,它可以使用 jQuery 的语法去捕获 DOM 元素的。

// index.js
let data = []
function getImages(uri) {
    crawler.queue({
        uri,
        callback: (err, res, done) => {
            if (err) throw err;
            let $ = res.$;
            try {
                let $imgs = $("img");
                Object.keys($imgs).forEach(index => {
                    let img = $imgs[index];
                    const { type, name, attribs = {} } = img;
                    let src = attribs.src || "";
                    if (type === "tag" && src && !data.includes(src)) {
                        let fileSrc = src.startsWith('http') ? src : `https:${src}`
                        let fileName = src.split("/")[src.split("/").length-1]
                        downloadFile(fileSrc, fileName) // 下载图片的方法
                        data.push(src)
                    }
                });
            } catch (e) {
                console.error(e);
                done()
            }
            done();
        }
    })
}

可以看到刚才通过 $ 来完成对请求中 img 标签的捕获。然后我们下面的逻辑去处理补全图片的链接和剥离出名字为了后面可以保存取名用。这里还定义了一个数组,它的目的是保存已经捕获到的图片地址,如果下次捕获发现同一个图片地址,那么就不再重复处理下载了。

以下是掘金首页html用 $("img") 捕获到的信息打印:

详解如何使用Node.js开发一个简单图片爬取功能

下载图片

下载之前我们还要安装一个 nodejs 包—— axios ,是的你没看错,axios 不仅提供给前端,它也可以给后端去使用。但是因为下载图片要把它处理成数据流,所以把 responseType 设置成 stream 。然后才可以用 pipe 方法保存数据流文件。

const { default: axios } = require("axios");
const fs = require('fs');

async function downloadFile(uri, name) {
    let dir = "./imgs"
    if (!fs.existsSync(dir)) {
        awAIt fs.mkdirSync(dir)
    }
    let filePath = `${dir}/${name}`
    let res = await axios({
        url: uri,
        responseType: 'stream'
    })
    let ws = fs.createWriteStream(filePath)
    res.data.pipe(ws)
    res.data.on("close",()=>{
        ws.close();
    })
}

因为可能图片很多,所以要统一放在一个文件夹下,就要判断有没有这个文件夹如果没有就创建一个。然后通过 createWriteStream 方法来把获取到的数据流以文件的形式保存到文件夹里面。

然后我们可以尝试一下,比如我们捕获用一下掘金首页html下的图片:

// index.js
getImages("https://juejin.cn/")

执行后发现就可以发现已经捕获到静态html里面的所有图片了。

node index.js

详解如何使用Node.js开发一个简单图片爬取功能

结语

到了最后,你也可以看到,此代码可能不适用于SPA(单页面应用)。由于单页应用程序中只有一个 HTML 文件,并且网页上的所有内容都是动态呈现的,但是万变不离其宗,不管怎样,你可以直接处理其数据请求,来收集到想要的信息也未尝不可。

还有一点要说的是,很多小伙伴处理下载图片的请求用到了 request.js ,当然这样可以的,甚至代码量更少,但是,我想说的是这个库在2020年的时候就已经被弃用了,最好换一个一直在更新维护的库比较好。

详解如何使用Node.js开发一个简单图片爬取功能

返回顶部
顶部