nodejs批量下载文件

397 阅读2分钟

在网上冲浪时看到有个插画家的画特别具有现实讽刺意味,就想把他的插画都收藏起来,找到了他的官方网站,但是页面长这样。

刷新好几次,图片都加载得特别慢。一看请求,好家伙,加载8分钟都加载不出来。直接点链接进去,加载得还是挺快的,几十张图片一个个下载也怪累的,还是用代码解决吧。

获取所有的图片链接

知道网页的地址,想要获取图片的链接,怎么办?观察页面的图像元素,都是img标签,alt属性是图像名字,src是图像链接。 格式如此统一,使用document.querySelectorAll就可以搞定。

const imgs = []; 
document.querySelectorAll('img').forEach(item => imgs.push({'alt': item.alt, 'src': item.src}));

拿到所有的图像信息。

异步批量下载

接下来就是下载了,使用万能的Node.js。需要使用https模块拿到图片资源以及fs模块把图片保存到本地。为了避免请求太多而失败,需要使用到异步请求,等一个图片下载完了,再发请求下载下一张图片。

import https from 'https';
import fs from 'fs';

// 发请求下载图片并保存到本地
function requestPromise(fileURL, downloadPath) {
  const file = fs.createWriteStream(downloadPath);

  return new Promise((resolve, reject) => {
    https.get(fileURL, function (response) {
      response.pipe(file);
      file
        .on('finish', function () {
          file.close();
          console.log('文件已经下载到本地');
          resolve();
        })
        .on('error', function () {
          reject();
        });
    });
  });
}

这段代码首先创建了一个fs.WriteStream对象,用于将下载的文件写入本地文件系统。然后创建了一个promise,在promise中 使用https.get方法从指定的fileURL中获取文件数据,将数据通过管道传递到fs.WriteStream对象中。当所有数据写入完成后,关闭文件流并在控制台输出一条消息,并resolve这个promise。当遇到错误时,reject这个promise

然后就是利用循环语句,处理好参数,循环调用这个请求函数了。

async function batchDownload() {
  for (let index = 0; index < imgs.length; index++) {
    const fileURL = imgs[index].src;
    const fileName = imgs[index].alt + '.png';
    const downloadPath = `./imgs/${fileName}`;
    await requestPromise(fileURL, downloadPath);
  }
}

上面的requestPromise函数,可以直接使用got模块替代,这是一个封装好的自带promise的模块

import got from 'got';

await got.stream(fileURL).pipe(fs.createWriteStream(downloadPath));

成果

最后看看成果吧