You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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就能生成所有对应尺寸的页面,无需循环渲染和合并操作。

实现步骤

  1. 遍历所有.page元素,获取每个元素的边界框尺寸
  2. 动态生成CSS的@page规则,为每个页面设置对应宽高
  3. 为每个.page元素添加page属性,关联到对应的@page规则
  4. 添加分页规则,确保每个.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 19:20:36