第一部分我们已经完成了表情包链接的获取,接下来我们开始批量下载表情包到本地。
下载表情包到本地
观察表情包地址我们发现表情包后面22位就是它完整且唯一的文件名。
我们首先判断本地是否存在这个文件,如果存在则跳过下载,如果不存在,
我们就创建一个可写的文件 stream
,然后请求表情包地址,并 pipe
到 stream
,
监听 close
事件,触发时完成Promise
。
function downloadMeMe (url) {
console.log(`下载: ${url}`);
let filePath = `./memes/${url.substr(-22)}`; // 取到后22位作为文件名
let stream = fs.createWriteStream(filePath); // 创建一个可写 stream 对象
// 请求表情包地址,并 pipe 到刚才创建的 stream 对象
request.get(url).pipe(stream);
}
限流器
假设我们打开表情包页面,他会同时请求一整页的表情包,所以我们只需要限制批量请求之间的间隔就好。 写个限流器,控制单次请求数,访问频率过快会导致爬虫被发现。你也可以设置随机延时。
function timerChunk(any, fn, limit, wait = 0) {
let run = async function () {
if (!any.length) {
return;
}
// 延时等待 这里是随机0到wait毫秒
await (new Promise((resolve, reject) => setTimeout(resolve, ~~(Math.random() * wait))));
let params = any.splice(0, limit); // 每次取出 limit 数量的任务
params.forEach((param) => fn(param));
return run();
}
return run();
}
组装函数
最后步骤就是搭积木把函数拼起来
(async function crawler() {
let keyword = '单身狗';
try {
// 获取该关键字所有的表情包链接
let links = await getLinksByPage(keyword, 1);
// 下载表情包到本地
await timerChunk(links, downloadMeMe, 5, 3000);
console.log('完成!');
} catch (err) {
console.error(err);
}
})();
我们来运行下我们的项目