当前位置: 首页 > ai >正文

3 分钟学会使用 Puppeteer 将 HTML 转 PDF

方案一、wkhtmltopdf + python

  • https://wkhtmltopdf.org/

不推荐,实测效果不佳,2020已停止维护。

在这里插入图片描述

sudo apt-get install xfonts-75dpi
sudo dpkg -i wkhtmltox_0.12.6.1-2.jammy_amd64.deb 

在这里插入图片描述

在这里插入图片描述

# 使用示例
wkhtmltopdf http://google.com google.pdf

在这里插入图片描述

在这里插入图片描述

方案二、Puppeteer

推荐方案,效果最佳,高度还原浏览器打印效果

pnpm install puppeteer-core# which google-chrome
/usr/bin/google-chrome
const puppeteer = require('puppeteer-core');
const fs = require('fs');
const path = require('path');// 自动检测 Chrome 安装路径(支持 Linux/Windows)
const CHROME_PATHS = ['/usr/bin/google-chrome',      // Debian/Ubuntu 默认路径'/opt/google/chrome/chrome',   // 二进制实际位置'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
];(async () => {try {// 自动查找可用浏览器路径const executablePath = CHROME_PATHS.find(p => fs.existsSync(p));if (!executablePath) throw new Error('未找到 Chrome 浏览器');const browser = await puppeteer.launch({headless: 'new',          // 启用新一代无头模式executablePath,args: ['--no-sandbox','--disable-setuid-sandbox','--disable-dev-shm-usage','--font-render-hinting=medium' // 提升中文字体渲染质量]});const page = await browser.newPage();// 加载内容(支持本地文件或远程URL)const htmlPath = path.resolve(__dirname, '/home/sam/下载/blender_python_reference_4_4/aud.html');await page.goto(`file://${htmlPath}`, {waitUntil: 'networkidle2',timeout: 30000});// 组合方案:CSS隐藏 + JS移除await page.addStyleTag({content: '.skip-to-content { display: none !important; }'});await page.evaluate(() => {const skipLink = document.querySelector('a.skip-to-content');if (skipLink) skipLink.remove();});// PDF生成配置await page.pdf({path: 'report.pdf',format: 'A4',printBackground: true,displayHeaderFooter: false,margin: {top: '25mm',right: '15mm',bottom: '25mm',left: '15mm'}});console.log('PDF 导出完成');await browser.close();} catch (error) {console.error('运行失败:', error.message);process.exit(1);}
})();

浏览器导出效果:

在这里插入图片描述

在这里插入图片描述

Puppeteer 导出效果:

在这里插入图片描述

在这里插入图片描述

补充:多线程处理导出

pnpm add tinypool
// main.mjs
import Tinypool from 'tinypool';
import fs from 'fs/promises'
import path from 'path'// 创建一个 Tinypool 实例
const pool = new Tinypool({filename: new URL('./worker.mjs', import.meta.url).href, // 指定工作线程文件minThreads: 10, // 设置最小线程数maxThreads: 20, // 设置最大线程数
});// 遍历目录
const folderPath = '/home/sam/MyWorkSpace/SOLIDWORKS/html/sldworksapi';
// const folderPath = '/home/sam/MyWorkSpace/SOLIDWORKS/html/swcommands';
// const folderPath = '/home/sam/MyWorkSpace/SOLIDWORKS/html/swconst';async function getAllFilesAsync(dirPath) {let filesList = [];async function traverse(currentPath) {const files = await fs.readdir(currentPath);for (const file of files) {const fullPath = path.join(currentPath, file);const stats = await fs.stat(fullPath);if (stats.isDirectory()) {await traverse(fullPath); // 递归处理子目录} else if (stats.isFile()) {filesList.push(fullPath); // 收集文件路径}}}await traverse(dirPath);return filesList;
}async function run() {// 遍历文件夹const filesList = await getAllFilesAsync(folderPath);// 使用 Promise.all 并行处理任务const promises = filesList.map(file => pool.run({ htmlPath: file, folderPath: folderPath }));// 等待所有任务完成await Promise.all(promises);// 销毁线程池await pool.destroy();
}await run();
// worker.mjs
import puppeteer from 'puppeteer-core'
import fs1 from 'fs'
import path from 'path'
import { fileURLToPath } from 'url';const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);// 自动检测 Chrome 安装路径(支持 Linux/Windows)
const CHROME_PATHS = ['/usr/bin/google-chrome',      // Debian/Ubuntu 默认路径'/opt/google/chrome/chrome',   // 二进制实际位置'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
];async function html2pdf(file, folderPath, executablePath) {let flag1 = 0;let flag2 = 0;// 判断文件类型if (file.slice(-4) != '.htm') {flag1 = 1;}if (file.slice(-5) != '.html') {flag2 = 1}if (flag2 + flag1 == 2) {console.log('--> DOC IS NOT A TYPE OF HTML. SKIP');return;}// 判断是否已导出const outputPath = '/home/sam/MyWorkSpace/PDF/SW/sldworksapi' + file.replace(folderPath, '').replace('.htm', '').replace('.html', '') + '.pdf';// const outputPath = '/home/sam/MyWorkSpace/PDF/SW/swcommands' + file.replace(folderPath, '').replace('.htm', '') .replace('.html', '') + '.pdf';// const outputPath = '/home/sam/MyWorkSpace/PDF/SW/swconst' + file.replace(folderPath, '').replace('.htm', '') .replace('.html', '') + '.pdf';if (fs1.existsSync(outputPath)) {console.log('-> Exists. SKIP');return;}// 加载浏览器实例const browser = await puppeteer.launch({headless: 'new',          // 启用新一代无头模式executablePath,args: ['--no-sandbox','--disable-setuid-sandbox','--disable-dev-shm-usage','--font-render-hinting=medium' // 提升中文字体渲染质量]});const page = await browser.newPage();// 加载内容(支持本地文件或远程URL)const htmlPath = path.resolve(__dirname, file);await page.goto(`file://${htmlPath}`, {waitUntil: 'networkidle2',timeout: 30000});// PDF生成配置await page.pdf({path: outputPath,format: 'A4',printBackground: false,displayHeaderFooter: false,landscape: true,// 横向打印margin: {top: '25mm',right: '15mm',bottom: '25mm',left: '15mm'}});console.log('PDF导出完成');await browser.close();}export default async ({ htmlPath,folderPath }) => {// 自动查找可用浏览器路径const executablePath = CHROME_PATHS.find(p => fs1.existsSync(p));if (!executablePath) throw new Error('未找到 Chrome 浏览器');// 遍历目录// const folderPath = '/home/sam/MyWorkSpace/SOLIDWORKS/html/sldworksapi';// const folderPath = '/home/sam/MyWorkSpace/SOLIDWORKS/html/swcommands';// const folderPath = '/home/sam/MyWorkSpace/SOLIDWORKS/html/swconst';await html2pdf(htmlPath, folderPath, executablePath);
};

横向打印 PDF,效果不错,直接转了一万多个文档。

在这里插入图片描述

在这里插入图片描述

http://www.xdnf.cn/news/9709.html

相关文章:

  • Axure设计案例——科技感渐变线性图
  • 不可变集合类型转换异常
  • Astra学习之-如何修改Header-logo和favicon图标
  • Linux | Shell脚本的基础知识
  • 基于ubuntu安装hadoop
  • .NET8入门:14.ASP.NET Core MVC进阶——Model
  • 前端高频面试题1:HTML/CSS/浏览器/计算机网络
  • 安装 Node.js 和配置 cnpm 镜像源
  • Java异常处理的全面指南
  • 基于通义千问的儿童陪伴学习和成长的智能应用架构。
  • Spring AI 之对话记忆(Chat Memory)
  • [网页五子棋][匹配模块]处理开始匹配/停止匹配请求(匹配算法,匹配器的实现)
  • python h5py 读取mat文件的<HDF5 object reference> 问题
  • StarRocks x Iceberg:云原生湖仓分析技术揭秘与最佳实践
  • 【大模型】Bert变种
  • Kubernetes资源申请沾满但是实际的资源占用并不多,是怎么回事?
  • 微深节能 码头装卸船机定位与控制系统 格雷母线
  • WPF 按钮悬停动画效果实现
  • 【五模型时间序列预测对比】Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN
  • 《AI大模型的开源与性能优化:DeepSeek R1的启示》
  • 互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景
  • 深入理解C#中的LINQ:数据查询的终极利器
  • 2013-2021年各省电子商务数据
  • 认识多系统萎缩:一种隐匿进展的神经退行性问题
  • spring IOC控制反转
  • 【春秋云镜】CVE-2022-26965 靶场writeup
  • 第一章 项目总览
  • 线性代数入门:轻松理解二阶与三阶行列式的定义与理解
  • Java消息队列与安全实战:谢飞机的烧饼摊故事
  • AI编程报错 API流式传输失败解决方案