在网上冲浪时看到有个插画家的画特别具有现实讽刺意味,就想把他的插画都收藏起来,找到了他的官方网站,但是页面长这样。
刷新好几次,图片都加载得特别慢。一看请求,好家伙,加载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));
成果
最后看看成果吧