
用 weasyprint 直接转 HTML 到 PDF,最稳的 Python 方案
不是所有 HTML 都能无损转 PDF,weasyprint 是目前对 CSS 支持最完整、不依赖系统浏览器引擎的纯 Python 方案。它把 HTML 当成“可打印文档”来渲染,适合生成报表、合同、静态页面归档。
常见错误现象:WeasyPrint encountered an error while rendering —— 多半是用了 position: fixed、transform 或 Web 字体未正确加载;或者 HTML 里有 JS 动态插入的内容(它不执行 JS)。
- 安装:运行
pip install weasyprint,注意它依赖cairo和pango,macOS 用brew install cairo pango libffi,Ubuntu 用apt install libcairo2-dev libpango1.0-dev - 基础用法:
HTML("page.html").write_pdf("out.pdf"),路径必须是本地文件或完整 URL(不支持file://协议前缀) - 中文显示问题?加
@font-face规则并确保字体文件路径可读,或直接在write_pdf()里传stylesheets=[CSS("zh.css")]指定含字体声明的 CSS
pdfkit 走的是 wkhtmltopdf 路子,快但兼容性差
它本质是调外部命令 wkhtmltopdf,所以速度快、支持 JS 渲染(加 --enable-javascript),但对现代 CSS(比如 Grid、Flex 嵌套)支持弱,不同系统生成效果可能不一致。
典型翻车点:QPainter::begin(): Returned false 错误,基本等于 wkhtmltopdf 没装好,或用了 headless 模式但没配 Xvfb(Linux);Windows 上路径含空格常导致命令执行失败。
立即学习“前端免费学习笔记(深入)”;
- 安装:先去 官网下二进制,再
pip install pdfkit - 调用时显式指定路径:
config = pdfkit.configuration(wkhtmltopdf="/usr/local/bin/wkhtmltopdf") - 关键参数:
options={"encoding": "UTF-8", "quiet": ""},quiet空字符串才能屏蔽 stderr 干扰
浏览器 DevTools 的 “另存为 PDF” 不可靠
Chrome / Edge 的打印 → “另存为 PDF” 看似方便,但它受当前 viewport、缩放、开发者工具是否开启影响,同一页面多次保存可能页边距、分页点都不同。更麻烦的是:无法自动化、不能嵌入到 CI/CD 流程中。
如果你只是临时导一份,没问题;但只要涉及批量、定时、或需要和 Python 后端联动(比如用户提交表单后自动生成 PDF),这条路就走不通。
- 隐藏元素会被打印出来?检查
@media print里有没有漏掉display: none - 背景图不显示?默认 Chrome 关闭了 “背景图形”,必须勾选才能输出
- 页眉页脚固定内容?得靠
@page规则 +running(),但 Chrome 实现不全,别指望running(header)真能跨页生效
为什么不用 playwright 或 puppeteer?
它们能完美还原浏览器渲染结果,JS、动画、Canvas 全支持,但代价是重:要下载 Chromium、内存占用高、启动慢。对简单静态 HTML 来说,属于“杀鸡用牛刀”,而且容易因超时、网络请求卡住(哪怕你只读本地文件)。
真正需要它的场景只有两个:HTML 里大量依赖 JS 渲染(比如 React/Vue 生成的报表),或必须和线上页面完全一致(比如截图比对)。
- 若真要用,别用
page.goto("file:///..."),改用page.setContent(html_str),避免跨域限制 - 务必加
wait_until="networkidle",否则 PDF 可能截到空白页 - 生成 PDF 前手动调一次
page.emulate_media("screen"),否则某些 CSS @media print 规则会干扰布局











