
Puppeteer PDF 生成完全指南Page.pdf 页面打印的用法、参数与底层原理【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer本指南围绕 Puppeteer 的 PDF 生成能力展开从docs/guides/pdf-generation.md给出的最小示例出发系统讲解page.pdf()的调用方式、全部打印参数、默认行为以及该 API 在仓库源码中的完整实现链路。读完本文你将能够用 Puppeteer 将任意网页稳定地导出为高可定制纸张、边距、页眉页脚、背景、可访问性等的 PDF 文件并能在排查问题时准确理解每一步背后的机制。相关源码全部位于仓库内核心实现见 api/Page.ts、cdp/Page.ts 与 bidi/Page.ts参数定义见 PDFOptions.ts。一、PDF 生成快速上手把网页打印成 PDF官方指南给出的最小示例即可运行const browser await puppeteer.launch(); const page await browser.newPage(); await page.goto(https://news.ycombinator.com, { waitUntil: networkidle2, }); // Saves the PDF to hn.pdf. await page.pdf({ path: hn.pdf, }); await browser.close();这段代码只有四步puppeteer.launch()启动浏览器browser.newPage()打开新页面page.goto(url, { waitUntil: networkidle2 })加载目标页面并等待网络空闲一般建议对新闻、内容聚合这类动态页面使用networkidle2避免截图/打印时机过早导致内容不完整page.pdf({ path: hn.pdf })把当前页面打印成 PDF 并写入磁盘。仓库中的 examples/pdf.js 给出了与之等价的可运行脚本区别只在于显式传入了format: letterimport puppeteer from puppeteer; const browser await puppeteer.launch(); const page await browser.newPage(); await page.goto(https://news.ycombinator.com, { waitUntil: networkidle2, }); await page.pdf({ path: hn.pdf, format: letter, }); await browser.close();path 与返回值PDF 去了哪里page.pdf()的声明见 api/Page.ts返回类型为PromiseUint8Arrayabstract pdf(options?: PDFOptions): PromiseUint8Array;关于path的语义PDFOptions.ts 中有明确说明path表示保存文件的路径如果该路径是相对路径则以进程的当前工作目录current working directory为基准进行解析默认值为undefined即不写盘此时 PDF 字节会作为返回值整体返回方便你把字节流转存到数据库、对象存储或直接作为 HTTP 响应下发。即便传入了path方法仍会返回完整的Uint8Array可进一步转为 Node.jsBuffer使用。二、三个容易忽略的默认行为指南末尾专门强调了一句By default, the Page.pdf() waits for fonts to be loaded.默认情况下Page.pdf()会等待字体加载完成。对应到源码这其实牵出三处默认行为理解它们能避免大量PDF 样式不对的困惑。1. 默认等待字体加载waitForFonts: true在 PDFOptions.ts 中waitForFonts的默认值是true。其语义是打印前等待document.fonts.ready决议从而确保 webfont 已加载、文本按最终字形渲染。对应到 ChromeCDP实现 cdp/Page.ts是在主 frame 的隔离世界isolatedRealm中执行document.fonts.ready并与timeout做竞速if (waitForFonts) { await firstValueFrom( from( this.mainFrame() .isolatedRealm() .evaluate(() { return document.fonts.ready; }), ).pipe(raceWith(timeout(ms))), ); }因此两点提醒页面位于后台标签时字体加载可能被延迟。参数注释建议必要时先用page.bringToFront()把页面激活再打印。若页面字体加载异常缓慢可以设置waitForFonts: false跳过等待超时行为仍受下面的timeout约束。2. 使用 print 媒体类型 打印配色渲染page.pdf()的文档注释见 api/Page.ts明确指出PDF 按printCSS 媒体类型生成若希望按screen样式输出需在调用前使用page.emulateMediaType(screen)默认情况下page.pdf()生成的是经过打印配色调整的颜色如需强制精确还原颜色可通过 CSS 的-webkit-print-color-adjust及标准print-color-adjust属性控制。3. 默认不打印背景图形printBackground: falseprintBackground默认值为false即页面背景色、背景图默认不会进入 PDF。若你的页面依赖背景深色卡片、高亮、图表底色等记得显式开启await page.pdf({ path: out.pdf, printBackground: true });三、PDFOptions 参数全览page.pdf()的全部可配置项集中在 PDFOptions.ts。结合 parsePDFOptions 中的默认值整理如下参数类型默认值作用pathstringundefined不写盘PDF 保存路径相对路径基于进程 CWD 解析scalenumber1页面渲染缩放取值范围0.1 ~ 2displayHeaderFooterbooleanfalse是否打印页眉页脚headerTemplate/footerTemplatestring页眉/页脚 HTML 模板printBackgroundbooleanfalse是否打印背景图形landscapebooleanfalse是否横向打印pageRangesstring全部页面页码范围如1-5, 8, 11-13formatPaperFormatletter纸张规格设置后优先于width/heightwidth/heightstring \| number由 format 决定纸张宽高支持带单位字符串或纯数字preferCSSPageSizebooleanfalse优先使用页面中 CSSpage声明的尺寸marginPDFMargin四边均为 0上下左右边距omitBackgroundbooleanfalse隐藏默认白色背景产出透明背景 PDFtaggedbooleantrue实验性生成带标签的无障碍PDFoutlinebooleanfalse实验性生成文档大纲timeoutnumber30000超时毫秒数传0表示不超时默认值可经page.setDefaultTimeout修改waitForFontsbooleantrue打印前等待document.fonts.ready页面布局与纸张尺寸scale渲染缩放系数必须位于0.1与2之间默认1。format预设纸张规格是使用频率最高的参数。合法的PaperFormat取值支持大小写组合见 PDFOptions.ts包括letter、legal、tabloid、ledger与a0~a6。仓库在 paperFormats 常量表中固化了各规格的精确尺寸英寸/厘米常见规格如下规格英寸 (in)厘米 (cm)Letter8.5 × 1121.59 × 27.94Legal8.5 × 1421.59 × 35.56Tabloid11 × 1727.94 × 43.18A48.2677 × 11.692921 × 29.7A311.6929 × 16.535429.7 × 42A55.8268 × 8.267714.8 × 21width/height自定义纸张尺寸可传带单位的字符串如210mm、8.5in、100px或纯数字。注意数字被当作像素处理详见下文单位解析一节。format与width/height的优先级设置format后它优先于width和height。preferCSSPageSize默认false。当为true时页面 CSS 中page { size: ... }声明的尺寸优先于width/height/format为false时内容会被缩放以适应指定纸张。landscape横向输出默认纵向。页眉页脚模板displayHeaderFooter开启displayHeaderFooter后通过headerTemplate/footerTemplate提供 HTML 模板。模板必须是合法 HTML并使用以下固定 class 注入动态值说明见 PDFOptions.tsclass注入内容date格式化的打印日期title文档标题url文档地址pageNumber当前页码totalPages文档总页数示例await page.pdf({ path: report.pdf, displayHeaderFooter: true, headerTemplate: div stylewidth:100%;font-size:10px;padding:0 20px;color:#555; span classtitle/span span stylefloat:right;span classdate/span/span /div, footerTemplate: div stylewidth:100%;font-size:10px;padding:0 20px;color:#555;text-align:center; Page span classpageNumber/span / span classtotalPages/span /div, });实践提示页眉页脚由浏览器打印引擎独立渲染样式需以内联 CSS形式写进模板同时建议为margin预留空间否则模板内容可能与正文重叠。背景、透明度与范围printBackground: true让背景色/背景图进入 PDFomitBackground: true则相反隐藏白色底、生成带透明区域的 PDF如把页面内容叠加到其他底图上的场景。其实现会临时把页面背景置为透明见 cdp/Page.ts 的setTransparentBackgroundColor打印结束后复位pageRanges: 1-5, 8, 11-13只打印指定页空字符串表示全部页面。可访问性与大纲实验性tagged默认true生成带语义标签的无障碍PDF便于读屏软件与辅助技术解析outline默认false生成文档大纲书签目录。解析源码里还有一个值得注意的细节见 util.ts一旦启用outlinetagged会被强制置为true因为大纲依赖标签结构注释引用了 Chromium issue 840455 的约束。四、尺寸与单位的解析规则源码级width/height/margin为什么既能传字符串又能传数字答案在 convertPrintParameterToInches 与单位表 unitToPixelsexport const unitToPixels { px: 1, in: 96, cm: 37.8, mm: 3.78, };解析规则为传数字直接视为像素值与 PhantomJSpaperSize行为对齐最终再换算为长度单位传字符串末尾两位若命中px/in/cm/mm则按对应倍率换算未命中已知单位时整个字符串按像素尝试解析解析失败会抛出断言错误如Failed to parse parameter value: ...。默认长度单位为英寸in未指定format、width、height时回退为宽8.5、高11即 Letter见 util.ts。边距四个方向的默认值为0。有意思的是FirefoxWebDriver BiDi路径在解析时使用了cm作为长度单位见 bidi/Page.ts因为 BiDi 的browsingContext.print命令以厘米承载纸张与边距尺寸。五、page.pdf() 的底层实现链路抽象层在基础类 api/Page.ts 中定义了两个抽象方法abstract createPDFStream(options?: PDFOptions): PromiseReadableStreamUint8Array; abstract pdf(options?: PDFOptions): PromiseUint8Array;即先有PDF 字节流再由pdf()完成落盘/聚合——不同浏览器协议只实现createPDFStream即可复用统一的上层逻辑。ChromeCDP路径CDP 实现中pdf()见 cdp/Page.ts先调用createPDFStream()再用 getReadableAsTypedArray 一边累积分片、一边若指定path写入文件最后返回合并后的Uint8Array。createPDFStream()的核心步骤为通过parsePDFOptions展开全部默认值与尺寸若omitBackground先将页面背景置为透明若waitForFonts等待document.fonts.ready向 CDP 发送Page.printToPDF并采用transferMode: ReturnAsStream以流式返回大文档同时把 Puppeteer 参数逐一映射为协议字段paperWidth、paperHeight、marginTop等见 cdp/Page.ts通过 getReadableFromProtocolStream 用IO.read循环拉取协议流分片产出ReadableStream。整条链路说明 Puppeteer 对超大 PDF 也采用流式处理不会一次性把整个文档塞进内存。FirefoxWebDriver BiDi路径仓库已支持通过 WebDriver BiDi 驱动 Firefox其pdf()实现见 bidi/Page.ts同样先等待document.fonts.ready随后调用browsingContext.print把 Puppeteer 参数映射为background、orientation、page宽高、pageRanges、scale、shrinkToFit即!preferCSSPageSize等 BiDi 字段最后经stringToTypedArray还原字节。需要说明的是两种浏览器协议支持的参数子集并不完全一致跨浏览器使用时建议先做一次参数可用性验证。更多背景可参考 webdriver-bidi 指南。超时机制两个实现的打印与字体等待都会与timeout(ms)竞速见 util.ts。默认超时为 30 秒可通过PDFOptions.timeout覆盖传0表示禁用超时timeout未显式给出时会回退到page.setDefaultTimeout设置的默认值。六、生产场景示例场景 1A4 边距 页眉页脚 背景输出报表const browser await puppeteer.launch(); const page await browser.newPage(); await page.goto(https://example.com/report, { waitUntil: networkidle0 }); await page.pdf({ path: ./out/report.pdf, format: A4, printBackground: true, margin: { top: 20mm, bottom: 20mm, left: 15mm, right: 15mm }, displayHeaderFooter: true, headerTemplate: div stylefont-size:9px;padding:0 15mm;color:#666;span classtitle/span/div, footerTemplate: div stylefont-size:9px;padding:0 15mm;color:#666;text-align:center;Page span classpageNumber/span of span classtotalPages/span/div, timeout: 60_000, }); await browser.close();场景 2不落盘直接拿到字节用于上传/下发const browser await puppeteer.launch(); const page await browser.newPage(); await page.setContent(h1Hello PDF/h1, { waitUntil: networkidle0 }); const bytes await page.pdf({ format: A4 }); // 不传 path const buffer Buffer.from(bytes); // Uint8Array - Buffer // 例如await uploadToS3(buffer) / res.send(buffer) await browser.close();page.setContent搭配page.pdf是HTML 模板转 PDF发票、合同、证书类场景的常见组合。场景 3只打印某些页 / 横向 / 缩放await page.pdf({ path: slides.pdf, landscape: true, // 幻灯片宽屏版式 pageRanges: 1-5, 8, // 跳过某几页 scale: 0.8, // 内容缩小到 80% format: letter, });场景 4按 screen 媒体类型输出如果你的页面样式区分了print与screen而你想按屏显样式打印await page.emulateMediaType(screen); await page.pdf({ path: screen-style.pdf, printBackground: true });场景 5透明背景 PDFawait page.pdf({ path: transparent.pdf, omitBackground: true });七、常见问题与注意事项小结路径基准path为相对路径时基于进程 CWD 解析PDFOptions.ts建议使用绝对路径或在代码中显式path.resolve()避免运行目录不同导致文件落错位置。字体等待是默认行为waitForFonts默认true后台标签页的字体加载可能超时必要时bringToFront()或设waitForFonts: false。背景不打印需要背景色/图时显式设置printBackground: true。颜色有调整默认输出打印配色需要精确还原页面颜色时结合 CSSprint-color-adjust/-webkit-print-color-adjust处理。尺寸优先级format优先于width/heightpreferCSSPageSize: true时 CSSpage尺寸又优先于前两者不指定时默认 Letter。纯数字按像素解释width: 200是 200 像素而非 200 毫米带单位请写字符串200mm。outline会自动开启tagged若介意这一点注意二者是实验性能力。超时控制默认 30s可用timeout: 0关闭或用page.setDefaultTimeout统一调整全局默认值。返回值page.pdf()总是返回Uint8Array需要磁盘文件则传path。浏览器差异ChromeCDP与 FirefoxWebDriver BiDi各自映射的参数子集不同跨浏览器前应做功能验证。参考入口本主题官方指南docs/guides/pdf-generation.mdAPI 文档Page.pdfpuppeteer.page.pdf.md、createPDFStreampuppeteer.page.createpdfstream.md、PDFOptions 完整类型puppeteer.pdfoptions.md可运行示例examples/pdf.js源码抽象定义 api/Page.ts、CDP 实现 cdp/Page.ts、BiDi/Firefox 实现 bidi/Page.ts、参数类型与纸张尺寸表 PDFOptions.ts、参数解析与单位换算 common/util.ts【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考