Puppeteer 使用实战:如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客(二)

文章目录

  • 上一篇
  • 效果演示
  • Puppeteer 修改浏览器的默认下载位置
  • 控制并发数
  • 错误重试
  • 并发控制 + 错误重试
  • 源码


上一篇

Puppeteer 使用实战:如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客(一)

效果演示

上一篇实现了一些基本功能,但是还有些问题

  • 有些时候页面会卡死,或者说找不到导出的元素,导致这篇文章下载不了
  • 不能控制标签页的打开数量,不够灵活(只能一个标签页、一个标签页的工作,效率低下)
  • 下载文件的默认位置没有修改

根据上面的问题,这次添加了并发控制,以及错误重试,效果如下图:

请添加图片描述

在这里插入图片描述

Puppeteer 修改浏览器的默认下载位置

查了官网好久的相关配置,没找到,然后谷歌,终于在这个网站上找到了答案

在这里插入图片描述

我的代码修改在这里了,注意声明的位置,一定要提前

在这里插入图片描述

import path from "path";
const __dirname = path.resolve(path.dirname(""));
const myDownloadPath = `${__dirname}\\my-post`;const page = await browser.newPage();const client = await page.createCDPSession();await client.send("Page.setDownloadBehavior", {behavior: "allow",downloadPath: myDownloadPath,});

这里提一嘴,我原先是把代码放到下图这个位置,(每次新建页面下重新设置),发现总是有些小 bug

  • 有的时候会下载到浏览器的默认目录(也就是代码根本没生效)
  • 多线程的时候会部分放到指定目录,部分放到默认目录,比方说双并发的时候,具体问题看我下面的图
    在这里插入图片描述
    给我的感觉,它算是一个全局的修改,所以只需要提前声明一次即可,不用每一次新建 newPage 就设置一次

控制并发数

在这里插入图片描述

这个可以参考一下这个叫 async-pool 的库的源码

我在这儿写了一个小案例,可以试试

// https://github.com/rxaviers/async-pool/blob/1.x/lib/es7.js
async function asyncPool(poolLimit, iterable, iteratorFn) {const ret = [];const executing = new Set();for (const item of iterable) {const p = Promise.resolve().then(() => iteratorFn(item));ret.push(p);executing.add(p);const clean = () => executing.delete(p);p.then(clean).catch(clean);if (executing.size >= poolLimit) {await Promise.race(executing);}}return Promise.all(ret);
}const timeout = (i) => {console.log("开始" + i);return new Promise((resolve) =>setTimeout(() => {resolve(i);console.log("结束" + i);}, 1000 + Math.random() * 1000));
};let urls = Array(10).fill(0).map((v, i) => i);
console.log(urls);(async () => {const res = await asyncPool(2, urls, timeout);console.log(res);
})();

错误重试

在这里插入图片描述

也是用了一个 demo 逻辑

const retry = (fn, times) => {return new Promise((res, rej) => {const attempt = () => {fn().then(res).catch((error) => {times-- > 0 ? attempt() : rej("机会用光了");});};attempt();});};let getNum = function () {console.log("函数执行一次");return new Promise((res, rej) => {let num = Math.random() * 10;num < 2 ? res("数字小于2") : rej("数字大于2");});};retry(getNum, 3).then((mes) => {console.log(mes);}).catch((err) => {console.log(err);});

并发控制 + 错误重试

结合之前的两个 demo,我们修改一下自己的逻辑

// tools.js
function retry(fn, times, item) {const allTime = times;const articleId = item.split("articleId=")[1] || "";return new Promise((res, rej) => {const attempt = () => {const currTime = allTime - times + 1;fn().then(() => {console.log(`Retry Success: 第 ${currTime} 次重试 ${articleId} 成功!`);res(item);}).catch((error) => {console.log(`Warning: 第 ${currTime} 次重试 ${articleId} `);if (times-- > 0) {attempt();} else {console.log(`Error:  已经重试 ${item} 文章 ${currTime} 次,机会已用光`);rej();}});};attempt();});
}// https://github.com/rxaviers/async-pool/blob/1.x/lib/es7.js
export async function asyncPool(poolLimit, iterable, iteratorFn) {const ret = [];const executing = new Set();for (let i = 0, len = iterable.length; i < len; i++) {const item = iterable[i];const articleId = item.split("articleId=")[1] || "";const p = Promise.resolve().then(() => iteratorFn(item)).catch(async (err) => {console.log(`${articleId} 解析失败,即将重试`);// 这里的 retry 也添加上 awaitawait retry(() => iteratorFn(item), 3, item).catch(() => {});});ret.push(p);executing.add(p);const clean = () => executing.delete(p);p.then(clean).catch(clean);if (executing.size >= poolLimit) {await Promise.race(executing);}}return Promise.all(ret);
}

然后调用一下

await asyncPool(3, baseWriteURLArray, handleURL);

在这里插入图片描述

源码

想要源码可以查看此仓库,如果有用记得 star 一下哦 https://github.com/Lovely-Ruby/CSDNBlogsExport

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/700368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

应用回归分析:非参数回归

非参数回归是一种统计方法&#xff0c;它在建模和分析数据时不假设固定的模型形式。与传统的参数回归模型不同&#xff0c;如线性回归和多项式回归&#xff0c;非参数回归不需要预先定义模型的结构&#xff08;例如&#xff0c;模型是否为线性或多项式&#xff09;。这使得非参…

[面试] 如何保证Redis和MySQL数据一致性?

为什么要在Redis存数据 Redis 用来实现应用和数据库之间读操作的缓存层&#xff0c;主要目的是减少数据 库 IO&#xff0c;还可以提升数据的 IO 性能。 因为Redis基于内存, 查询效率比MySQL快很多, 所以有限查询Redis中的数据,如果Redis没有就查询数据库然后同步到Redis 出…

低代码与大语言模型的探索实践

低代码系列文章&#xff1a; 可视化拖拽组件库一些技术要点原理分析可视化拖拽组件库一些技术要点原理分析&#xff08;二&#xff09;可视化拖拽组件库一些技术要点原理分析&#xff08;三&#xff09;可视化拖拽组件库一些技术要点原理分析&#xff08;四&#xff09;低代码…

1978-2021年全国及31省市农业机械总动力(万千瓦)

1978-2021年全国及31省市农业机械总动力&#xff08;万千瓦&#xff09; 1、时间&#xff1a;1978-2020年 2、范围&#xff1a;31省 3、来源&#xff1a;各省NJ 农业统计NJ 4、缺失情况&#xff1a;无缺失 5、指标&#xff1a;农业机械总动力 6、指标解释&#xff1a; 农…

每日五道java面试题之spring篇(二)

目录&#xff1a; 第一题 Spring事务传播机制第二题 Spring事务什么时候会失效?第三题 什么是bean的⾃动装配&#xff0c;有哪些⽅式&#xff1f;第四题 Spring中的Bean创建的⽣命周期有哪些步骤&#xff1f;第五题 Spring中Bean是线程安全的吗&#xff1f; 第一题 Spring事务…

LeetCode 448.找到所有数组中消失的数字

目录 1.题目 2.代码及思路 3.进阶 3.1题目 3.2代码及思路 1.题目 给你一个含 n 个整数的数组 nums &#xff0c;其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字&#xff0c;并以数组的形式返回结果。 示例 1&#xff1a; 输入&am…

Redis中的rdb和aof

Redis中的rdb和aof 持久化流程RDB机制redis.conf中rdb的配置save bgsave 自动化 rdb触发的三种方式save 命令bgsave命令自动触发 rdb的优势劣势 AOFaof原理aof配置文件重写原理aof的三种触发机制 appendfsyncaof fix工具 redis-check-aof练习aofaof的优缺点 redis是一个内存数据…

java——IO流基础

目录 IO流IO流的四大分类&#xff1a;IO流的体系&#xff1a;FileinputStream&#xff08;文件字节输入流&#xff09;FileOutputStream(文件字节输出流&#xff09;文件复制资源释放FileReader&#xff08;文件字符输入流&#xff09;FileWriter(文件字符输出流&#xff09;缓…

Python实战: 获取 后缀名(扩展名) 或 文件名

Python实战: 获取 后缀名(扩展名) 或 文件名 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 &#x1f448; 希望得到您的订阅和支持~ &…

mysql 事务详解一

前言 提到事务&#xff0c;大家肯定不陌生。在我们现实生活中也是存在的&#xff0c;比如我们去超市购物&#xff0c;然后去支付。虽然是两个步骤&#xff0c;必须保证同时成功&#xff0c;这个交易才可以完成。 如果这个场景&#xff0c;拿到我们购物系统&#xff0c;就是几…

VirtualBox+Vagrant安装linux

一、VirtualBox安装 VirtualBox官网&#xff1a;Oracle VM VirtualBox 这里采用VirtualBox--7.0.0 版本 二、Vagrant安装 Vagrant官网&#xff1a;Vagrant by HashiCorp Vagrant镜像仓库&#xff1a;Discover Vagrant Boxes - Vagrant Cloud 这里采用Vagrant--2.4.1版本 在…

神经网络系列---权重初始化方法

文章目录 权重初始化方法Xavier初始化&#xff08;Xavier initialization&#xff09;Kaiming初始化&#xff0c;也称为He初始化LeCun 初始化正态分布与均匀分布Orthogonal InitializationSparse Initializationn_in和n_out代码实现 权重初始化方法 Xavier初始化&#xff08;X…

关于uniapp H5应用无法在触摸屏正常显示的处理办法

关于uniapp H5应用无法在触摸屏正常显示的处理办法 1、问题2、处理3、建议 1、问题 前几天&#xff0c; 客户反馈在安卓触摸大屏上无法正确打开web系统&#xff08;uni-app vue3开发的h5 应用&#xff09;&#xff0c;有些页面显示不出内容。该应用在 pc 端和手机端都可以正常…

【递归版】归并排序算法(1)

目录 MergeSort归并排序 整体思想 图解分析 代码实现 时间复杂度 递归&归并排序VS快速排序 MergeSort归并排序 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法&#xff08;Divide and Conquer&a…

Linux第65步_学习“Makefie”

学习“Makefie”&#xff0c;为后期学习linux驱动开发做铺垫。 1、在“/home/zgq/linux/atk-mp1”创建一个“Test_MakeFile”目录用于学习“Makefie”。 打开终端 输入“cd /home/zgq/linux/回车”&#xff0c;切换到“/home/zgq/linux/”目录 输入“mkdir Linux_Drivers回…

window: C++ 获取自己写的dll的地址

我自己用C写了一个插件,插件是dll形式的,我的插件式在dll的目录下有个config文件夹,里面是我用json写的插件配置文件,当插件运行的时候我需要读取到json配置文件,所有最重要的就是如何获取dll的路径. 大概就是这么个结构, 我自己封装了一个函数.只适用于window编程,因为里面用…

node 之 fs文件系统模块

1.什么是fs文件系统模块 fs模块是Node.js官方提供的、用来操作文件的模块。它提供了一系列的方法和属性&#xff0c;用来满足用户对文件的操作需求 fs.readFile(),用来读取制定文件中的内容 fs.writeFile(),用来向制定的文件中写入内容 如果要在JavaScript代码中&#xff0c;使…

论文是怎么一回事

最近找到女朋友了&#xff0c;她还挺关心我毕业和论文的事情&#xff0c;我开始着手弄论文了~ 说来惭愧&#xff0c;我一直以为读研就是做东西当作工作来完成&#xff0c;结果一直陷入如何实现的问题&#xff0c;结果要论文时不知道怎么弄创新点&#xff0c;这才转过头来弄论文…

Python实现歌曲下载程序, 打包exe应用程序

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 环境使用: Python 3.10 Pycharm 模块使用: import requests >>> pip install requests import parsel >>> pip install parsel import pr…

使用向量数据库pinecone构建应用06:日志系统异常检测 Anomaly Detection

Building Applications with Vector Databases 下面是这门课的学习笔记&#xff1a;https://www.deeplearning.ai/short-courses/building-applications-vector-databases/ Learn to create six exciting applications of vector databases and implement them using Pinecon…