如何用Puppeteer生成每页尺寸独立的PDF?
如何用Puppeteer高效将不同尺寸的
.page div转为对应尺寸的PDF页面 我需要实现网页转PDF的功能:网页包含多个不同尺寸的.page类div,要求生成的PDF每页尺寸完全匹配对应div的边界框大小。目前采用的循环渲染单个div为PDF再合并的方法虽可行,但效率极低,想寻求更优雅的解决方案。
示例HTML
<!DOCTYPE html> <html lang="en"> <body> <div class="contents"> <div class="page" style="height: 436.656px; width: 950px; padding: 24px; border: 2px solid orange"> PAGE 1 </div> <div class="page" style="height: 1450.344px; width: 1234px; padding: 24px; border: 2px solid green"> PAGE 2 </div> <div class="page" style="height: 750px; width: 750px; padding: 24px; border: 2px solid lightblue"> PAGE 3 </div> <div class="page" style="height: 3000px; width: 950px; padding: 24px; border: 2px solid red"> PAGE 4 (yes, this is a possible page dimension) </div> </div> </body> </html>
当前低效实现
var printPages = await page.$$('.page'), pageBox; // 逐个生成单页临时PDF for (var i = 0; i < printPages.length; i++) { pageBox = await printPages[i].boundingBox(); await page.pdf({ path: params.filePath + '_page' + i + '.pdf', width: pageBox.width + 'px', height: pageBox.height + 'px', margin:0, printBackground: true, pageRanges: '1', }); // 删除已处理的div await page.evaluate(() => { var doc = document.querySelector('.page'); doc.remove(); }); } // 合并所有临时PDF为一个文件
高效解决方案:利用CSS分页媒体实现单次PDF生成
核心思路是通过CSS为每个.page元素指定独立的页面尺寸,同时强制每个div单独分页,仅需调用一次page.pdf就能生成所有对应尺寸的页面,无需循环渲染和合并操作。
实现步骤
- 遍历所有
.page元素,获取每个元素的边界框尺寸 - 动态生成CSS的
@page规则,为每个页面设置对应宽高 - 为每个
.page元素添加page属性,关联到对应的@page规则 - 添加分页规则,确保每个
.page元素单独占一页
完整代码实现
// 获取所有.page元素 const printPages = await page.$$('.page'); const dynamicStyles = []; for (let i = 0; i < printPages.length; i++) { // 获取当前页面的边界框尺寸 const pageBox = await printPages[i].boundingBox(); // 生成唯一的页面标识 const pageId = `custom-page-${i}`; // 添加@page规则,指定当前页面的尺寸和边距 dynamicStyles.push(`@page ${pageId} { size: ${pageBox.width}px ${pageBox.height}px; margin: 0; }`); // 为当前.page元素绑定对应的@page规则 await printPages[i].evaluate((el, id) => { el.setAttribute('page', id); }, pageId); } // 添加分页控制样式:每个.page后强制分页,最后一页除外 dynamicStyles.push(` .page { page-break-after: always; } .page:last-child { page-break-after: avoid; } `); // 将动态生成的CSS注入页面 await page.addStyleTag({ content: dynamicStyles.join('\n') }); // 单次生成完整PDF await page.pdf({ path: params.filePath, printBackground: true, // 无需全局指定宽高,将使用每个@page的自定义设置 });
方案优势
- 仅需一次渲染和PDF生成操作,避免多次
page.pdf调用的性能开销 - 无需生成临时文件和后续合并步骤,减少磁盘IO操作
- 依赖浏览器原生分页渲染能力,逻辑更稳定可靠
内容的提问来源于stack exchange,提问作者DatGameh
相关产品推荐
相关产品推荐

