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
相关文章:
Puppeteer 使用实战:如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客(二)
文章目录 上一篇效果演示Puppeteer 修改浏览器的默认下载位置控制并发数错误重试并发控制 错误重试源码 上一篇 Puppeteer 使用实战:如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客(一) 效果演示 上一篇实现了一些基本功能,…...
[ 2024春节 Flink打卡 ] -- 优化(draft)
2024,游子未归乡。工作需要,flink coding。觉知此事要躬行,未休,特记 资源配置调优内存设置 TaskManager内存模型 https://nightlies.apache.org/flink/flink-docs-release-1.18/docs/deployment/config/ TaskManager 内存模型…...
电脑进水无法开机怎么办 电脑进水开不了机的解决方法
意外总是会不定时打破你的计划,电脑这类电器最怕遇到的除了火还有水,设备进水会导致数据丢失,那么我们遇到电脑进水怎么办?进水之后不正确处理也会引起很多不必要的麻烦. 解决办法 第一步:关机 如果您的电脑是在开…...
【Flutter】底部导航BottomNavigationBar的使用
常用基本属性 属性名含义是否必须items底部导航栏的子项List是currentIndex当前显示索引否onTap底部导航栏的点击事件, Function(int)否type底部导航栏类型,定义 [BottomNavigationBar] 的布局和行为否selectedItemColor选中项图标和label的颜色否unsel…...
Vue封装全局公共方法
有的时候,我们需要在多个组件里调用一个公共方法,这样我们就能将这个方法封装成全局的公共方法。 我们先在src下的assets里新建一个js文件夹,然后建一个common.js的文件,如下图所示: 然后在common.js里写我们的公共方法,比如这里我们写了一个testLink的方法,然后在main…...
雪花算法生成分布式主键ID
直接上代码,复制即可使用 public class SnowflakeIdGenerator {private static final long START_TIMESTAMP 1624000000000L; // 设置起始时间戳,2021-06-18 00:00:00private static final long DATA_CENTER_ID_BITS 5L;private static final long WO…...
第三百五十九回
文章目录 1. 概念介绍2. 使用方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 013pickers2.gif 我们在上一章回中介绍了"如何实现Numberpicker"相关的内容,本章回中将介绍wheelChoose组件.闲话休提,让我们一起Talk Flutter吧。 1. 概念…...
vue3 用xlsx 解决 excel 低版本office无法打开问题
需求背景解决思路解决效果将json导出为excel将table导为excel导出样式 需求背景 原使用 vue3-json-excel ,导致在笔记本office环境下,出现兼容性问题 <vue3-json-excel class"export-btn" :fetch"excelGetList" :fields"js…...
Java后端底座从无到有的搭建(随笔)
文章目录 开发模式的演变草创时期1.0时期(基座时期)1.1时期(低代码时期)2.0时期(无代码时期) 前言:本文是笔者在初创公司,一年多来Java后端服务底座搭建过程的总结,如有不…...
Rust介绍与开发环境搭建
Rust 是一种系统编程语言,它专注于内存安全、并发和性能。它是由 Mozilla 开发的,并得到了许多社区的广泛支持。Rust 的设计理念是“安全 by default”,这意味着你不需要特殊的工具或技巧来编写安全的代码。 Rust 的主要特点: 内…...
本地TCP通讯(C++)
概要 利用TCP技术,实现本地ROS1和ROS2的通讯。 服务端代码 头文件 #include <ros/ros.h> #include "std_msgs/String.h" #include "std_msgs/Bool.h" #include <iostream> #include <cstring> #include <unistd.h>…...
docker 安装jenkins
使用 Docker 安装 Jenkins 是一种快速、方便的方法,可以避免本地环境的复杂依赖。以下是通过 Docker 安装 Jenkins 的基本步骤: 安装 Docker: 如果你的系统尚未安装 Docker,请先安装 Docker。对于 Ubuntu 系统,可以通过…...
电脑黑屏什么都不显示怎么办 电脑开机黑屏不显示任何东西的4种解决办法
相信有很多网友都有经历电脑开机黑屏不显示任何东西,找了很多方法都没处理好,其实关于这个的问题,首先还是要了解清楚开机黑屏的原因,才能够对症下药,下面大家可以跟小编一起来看看怎么解决吧 电脑开机黑屏不显示任何…...
MT8781核心板_MTK8781安卓核心板规格参数
MT8781安卓核心板以其强大的性能和高效的能耐备受瞩目。其八核CPU架构包括(2x Cortex-A76 2.2GHz 6x Cortex-A55 2.0GHz),以及高性能的Arm Mali G57级GPU。同时,配备高达2,133MHz的LPDDR4X内存和快速的UFS 2.2级存储,大大加速了数据访问速…...
HTML知识点
HTML 【一】HTML简介 【1】什么是HTML HTML是一种用于创建网页结构和内容的超文本标记语言,它是构建网页的基础。为了让浏览器正确渲染页面,我们必须遵循HTML的语法规则。浏览器在解析网页时会将HTML代码转换为可视化的页面,所以我们在浏览…...
聊聊分库分表
文章导读 背景介绍 随着互联网技术的发展,数据量呈爆炸性增长。大数据量的业务场景中,数据库成为系统性能瓶颈的一个主要因素。当单个数据库包含了太多数据或过高的访问量时,会出现查询缓慢、响应时间长等问题,严重影响用户体验。…...
小米标准模组+MCU 快速上手开发(二)——之模组串口调试
小米标准模组MCU 开发笔记之固件调试 背景技术名词简介● 小米IoT开发者平台● 小米IoT 模组● 固件● OTA● CRC32 固件双串口调试● MHCWB6S-IB 模组资料下载● MHCWB6S-IB 模组管脚图● 上电调试 背景 小米标准模组MCU的开发过程中,由于部分官方资料较为古早&am…...
Ubuntu22.04和Windows10双系统安装
概要 本篇演示Ubuntu22.04和Windows10双系统的安装。先安装Ubuntu22.04,再安装Windows10。 一、说明 1、电脑 笔者的电脑品牌是acer(宏碁/宏基) 电脑开机按F2进入BIOS 电脑开机按F12进入Boot Manager 2、U盘启动盘 需要用到两个U盘启动盘 (1&a…...
重新安装VSCode后,按住Ctrl(or Command) 点击鼠标左键不跳转问题
重新安装VSCode后,按住Ctrl(or Command) 点击鼠标左键不跳转问题 原因:重新安装一般是因为相应编程语言的插件被删除了或还没有下载。 本次是由于Python相关的插件被删除了,因此导致Python无法跳转。 解决办法 在vs…...
QPaint绘制自定义仪表盘组件01
网上抄别人的,只是放这里自己看一下,看完就删掉 ui Dashboard.pro QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomm…...
二代壳脱壳新思路:Hook CreateFromRawDexFile捕获原始DEX
1. 为什么“二代壳”让传统脱壳方法集体失效?——从Dex加载链路说起你有没有试过用经典的dumpdex脚本在Android 10设备上跑,结果dump出来的dex文件一打开就是满屏java.lang.ClassNotFoundException?或者用dex2oat反编译出的odex,反…...
收藏! Harness 让你轻松驾驭大模型,小白也能写出高效代码
本文探讨了 AI 编程 Agent 的核心要素,强调 Harness(工具、流程和反馈系统)的重要性远超单纯依赖模型。通过实例说明,优化编辑格式等 Harness 设计可显著提升 Agent 成功率。文章提出,为 AI 准备更好的工作台ÿ…...
B站视频下载终极指南:如何一键获取无水印高清视频
B站视频下载终极指南:如何一键获取无水印高清视频 【免费下载链接】BiliDownload B站视频下载工具 项目地址: https://gitcode.com/gh_mirrors/bil/BiliDownload 你是否曾为下载B站视频而烦恼?想要保存喜欢的视频却找不到合适的工具?B…...
Diablo Edit2完全指南:掌握暗黑破坏神2存档编辑的艺术
Diablo Edit2完全指南:掌握暗黑破坏神2存档编辑的艺术 【免费下载链接】diablo_edit Diablo II Character editor. 项目地址: https://gitcode.com/gh_mirrors/di/diablo_edit 你是否曾经在暗黑破坏神2中因为技能点分配失误而懊恼?是否因为刷不到…...
如何将Scrapeless MCP服务器集成到ZeroClaw中:逐步指南
关键要点: 一个TOML块将云浏览器连接到本地Rust代理。 ZeroClaw是一个单一二进制AI代理运行时,它与LLM提供者通信,监听30多个频道,并通过工具进行操作。只需在~/.zeroclaw/config.toml中添加四行[mcp]块即可添加Scrapeless MCP服…...
3个真实场景解密:如何用btcrecover找回遗忘的比特币钱包密码
3个真实场景解密:如何用btcrecover找回遗忘的比特币钱包密码 【免费下载链接】btcrecover An open source Bitcoin wallet password and seed recovery tool designed for the case where you already know most of your password/seed, but need assistance in try…...
5分钟免费解决NVIDIA显卡显示器色彩过饱和的终极方案
5分钟免费解决NVIDIA显卡显示器色彩过饱和的终极方案 【免费下载链接】novideo_srgb Calibrate monitors to sRGB or other color spaces on NVIDIA GPUs, based on EDID data or ICC profiles 项目地址: https://gitcode.com/gh_mirrors/no/novideo_srgb 你是否曾经发现…...
从Delaunay到高质量网格:手把手拆解TetGen算法核心与C++实现避坑指南
从Delaunay到高质量网格:手把手拆解TetGen算法核心与C实现避坑指南 在计算几何与科学计算领域,生成高质量四面体网格是有限元分析、流体仿真和游戏物理引擎等应用的基础。TetGen作为开源网格生成工具的代表,其算法设计与实现细节直接影响着最…...
Linux mkdir、rmdir 命令详解——目录的创建与删除(新手零踩坑)
前言在Linux操作中,目录是文件的“容器”,想要管理文件,首先要学会创建和删除目录。mkdir(创建目录)和rmdir(删除目录)是最基础的目录操作命令,用法简单但有细节,尤其是r…...
OpenAI 模型攻克离散几何 80 年难题:Erdős 单位距离猜想被 AI 证明
OpenAI 模型攻克离散几何 80 年难题:Erdős 单位距离猜想被 AI 证明 一场改写数学史的AI突破 2026年5月20日,OpenAI 宣布其内部通用推理模型成功证明了一个困扰数学界近80年的开放问题——Erdős 单位距离问题(Unit Distance Problem&#…...
