weasyprint 是纯 python 的轻量 pdf 渲染工具,适合静态 html;需处理字体路径、绝对样式链接、避免 unsupported css;puppeteer 依赖 chromium,适合动态内容,但需注意编码、渲染兼容性与字体嵌入问题。

用 weasyprint 直接渲染 HTML 到 PDF,不依赖浏览器
如果你的 HTML 是静态页面、含内联样式或简单 CSS(比如报表、邮件模板),weasyprint 是最轻量且可控的选择。它基于 Python,纯 Python 实现的 CSS 渲染引擎,不启动 Chromium 或 WebKit,生成的 PDF 更稳定、更易批量处理。
常见错误现象:WeasyPrint 报 Failed to load stylesheet,其实是相对路径没转成绝对路径;或者中文显示为方块,因为默认没加载中文字体。
- 安装后必须显式指定字体路径:
weasyprint input.html output.pdf --fonts /usr/share/fonts/truetype/wqy/wqy-zenhei.ttc - CSS 中避免用
@import url(...),改用<link rel="stylesheet">且 href 必须是绝对路径或 base64 内联 - 不支持
position: fixed用于页眉页脚以外的场景,打印时会错位 - 表格跨页断裂不可控,加
page-break-inside: avoid仅对块级容器有效,<tr> 上加无效 <h3>用 <code>puppeteer走 Chromium 渲染,适合动态/交互型 HTML如果 HTML 里有 JS 初始化图表(如 ECharts)、Vue/React 渲染后的内容,或需要截图式精确还原,
puppeteer是更可靠的选择。它本质是控制一个无头 Chrome,所以兼容性接近真实浏览器。使用场景:导出带 ECharts 的监控看板、含
localStorage数据的前端管理页、需登录态的内部报告页。立即学习“前端免费学习笔记(深入)”;
- 务必等 JS 执行完成再截取,不能只靠
page.waitForTimeout(2000),应监听关键 DOM 出现:await page.waitForSelector('#chart-container canvas') -
page.pdf()默认用 A4 尺寸,但网页宽度超 210mm 会导致横向压缩变形,加format: 'letter'或手动设width/height - Linux 服务器上运行常报
chrome not found,不是没装 Chrome,而是puppeteer下载的 Chromium 权限被 SELinux 拦截,建议用--no-sandbox启动,但仅限可信环境 - PDF 中的超链接默认失效,需加
printBackground: true和 CSS@media print { a::after { content: ' (' attr(href) ')'; } }才能保留可读性
遇到
UnicodeEncodeError或乱码?先确认 HTML 声明和编码一致很多“转 PDF 中文变问号”问题,根源不在工具,而在 HTML 文件本身编码混乱。浏览器能容错,
weasyprint和puppeteer却很严格。错误现象:
UnicodeEncodeError: 'latin-1' codec can't encode character '\u4f60';或 PDF 里中文全成空白/方框。- 检查 HTML 文件开头是否有
<meta charset="utf-8">,且文件实际保存为 UTF-8(无 BOM) - 用
file -i your.html确认编码,不是 “us-ascii” 或 “iso-8859-1” -
weasyprint读文件时若没指定 encoding,默认按系统 locale 解码,Linux 服务器常是en_US.UTF-8,但某些 Docker 镜像 locale 是C,导致 decode 失败 - 稳妥做法:用 Python 脚本读取 HTML 字符串,显式
.decode('utf-8')后传给HTML(string=...),绕过文件读取环节
生成 PDF 后字体发虚、线条锯齿?别怪工具,先查 CSS 渲染模式
PDF 导出后文字边缘模糊、SVG 图标出现灰边、细线断续——这类问题通常不是 DPI 设置低,而是 CSS 中触发了非标准渲染路径。
典型诱因:用了
transform: scale()、filter: drop-shadow()、或backface-visibility: hidden这类强制硬件加速的属性。-
weasyprint完全忽略transform和filter,遇到就静默降级,可能让布局塌陷,间接导致字体重排模糊 -
puppeteer虽支持,但 PDF 导出时 Chromium 会把 transform 后元素光栅化成位图,分辨率锁定在 96dpi,放大即糊 - 解决方案:导出前用 JS 移除这些样式:
document.querySelectorAll('*').forEach(el => el.style.transform = '') - SVG 图标务必用
<svg></svg>内联,不要<img src="icon.svg" alt="怎么将html文件转换为pdf_网页转文档格式方法【工具】" >,否则 puppeteer 无法嵌入矢量数据
- 务必等 JS 执行完成再截取,不能只靠











