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

如何用Python将带格式的HTML内容追加到现有PDF的内容末尾(不另起新页)

如何用Python将带格式的HTML内容追加到现有PDF的内容末尾(不另起新页)

嘿,这个需求确实有点讲究——既要保留HTML的格式(段落、表格、图片都不能丢),又得精准续在原PDF最后一页的内容后面,不能直接开新页。我来给你拆解一下实现步骤,用Python结合几个实用的库就能搞定!

核心思路

要实现这个需求,我们需要分三步走:

  1. 把带格式的HTML转换成PDF(这样才能保留所有样式);
  2. 精准计算原PDF最后一页的剩余可用空间;
  3. 把HTML转成的PDF内容,先尝试塞进原PDF的剩余空间,放不下的部分再生成新页追加。

需要安装的库

首先得装两个关键库:

  • PyMuPDF(fitz):用来处理PDF页面,精确计算空间和复制内容;
  • WeasyPrint:完美支持HTML转PDF,能保留各种样式、表格和图片。

执行下面的命令安装:

pip install pymupdf weasyprint

具体代码实现

我把代码拆成几个函数,方便你理解和复用:

1. HTML转PDF函数

先把你的HTML内容转换成临时PDF字节流,这样后续好处理:

from weasyprint import HTML
import fitz  # PyMuPDF
import io

def html_to_pdf(html_content):
    # 将HTML字符串转换成PDF字节流
    html = HTML(string=html_content)
    pdf_bytes = html.write_pdf()
    return io.BytesIO(pdf_bytes)

2. 计算原PDF最后一页剩余空间

这里用PyMuPDF来获取原PDF最后一页的已用内容高度,从而算出剩余空间:

def get_last_page_remaining_space(original_pdf_path):
    doc = fitz.open(original_pdf_path)
    last_page = doc[-1]
    
    # 获取页面的实际可打印区域高度
    mediabox = last_page.mediabox
    total_page_height = mediabox[3] - mediabox[1]
    
    # 找到页面上所有文字内容的最底部位置(如果有图片/表格,后续可以补充判断)
    all_text_rects = last_page.get_text("words")
    if not all_text_rects:
        # 如果页面是空的,剩余空间就是整个页面高度
        remaining_height = total_page_height
    else:
        # PyMuPDF的y轴是从下往上的,所以取最大的y坐标就是内容最底部
        max_content_bottom = max(rect[3] for rect in all_text_rects)
        remaining_height = total_page_height - max_content_bottom
    
    doc.close()
    return remaining_height, total_page_height, mediabox

3. 核心合并函数

这部分是重点,把HTML内容精准追加到原PDF末尾:

def append_html_to_pdf(original_pdf_path, html_content, output_pdf_path):
    # 第一步:把HTML转成临时PDF
    html_pdf_stream = html_to_pdf(html_content)
    html_doc = fitz.open("pdf", html_pdf_stream)
    
    # 第二步:获取原PDF最后一页的剩余空间
    remaining_height, total_page_height, mediabox = get_last_page_remaining_space(original_pdf_path)
    original_doc = fitz.open(original_pdf_path)
    last_original_page = original_doc[-1]
    
    # 处理HTML的第一页内容
    html_first_page = html_doc[0]
    # 计算HTML第一页的实际内容高度(不是页面高度)
    html_text_rects = html_first_page.get_text("words")
    if html_text_rects:
        html_content_top = min(rect[1] for rect in html_text_rects)
        html_content_bottom = max(rect[3] for rect in html_text_rects)
        html_content_height = html_content_bottom - html_content_top
    else:
        html_content_height = 0
    
    if html_content_height <= remaining_height:
        # 能放下!把HTML第一页的内容复制到原PDF最后一页
        # 计算偏移量:让HTML内容刚好接在原内容的下面
        offset_y = total_page_height - remaining_height
        # 复制HTML内容到原页面,只取实际内容部分,避免空区域
        content_rect = fitz.Rect(0, html_content_top, mediabox[2]-mediabox[0], html_content_bottom)
        last_original_page.show_pdf_page(last_original_page.rect, html_doc, 0, clip=content_rect, shift=fitz.Point(0, offset_y))
        
        # 剩下的HTML页面直接追加到原PDF后面
        for page_num in range(1, len(html_doc)):
            original_doc.insert_pdf(html_doc, from_page=page_num, to_page=page_num)
    else:
        # HTML第一页内容太长,剩余空间放不下,就直接把所有HTML页面追加到原PDF后面
        print("HTML第一页内容超出剩余空间,直接追加所有页面到原PDF末尾")
        original_doc.insert_pdf(html_doc)
    
    # 保存最终的PDF
    original_doc.save(output_pdf_path)
    # 关闭文档释放资源
    original_doc.close()
    html_doc.close()

使用示例

你可以这样调用函数,替换成你自己的HTML内容和PDF路径:

# 替换成你自己的HTML内容
my_html = """
<html>
<body>
    <p>这是追加的段落,带<b>加粗</b>和<i>斜体</i>样式~</p>
    <table border="1" cellpadding="5">
        <tr><th>姓名</th><th>年龄</th></tr>
        <tr><td>张三</td><td>25</td></tr>
        <tr><td>李四</td><td>30</td></tr>
    </table>
    <img src="https://picsum.photos/200/120" alt="示例图片">
</body>
</html>
"""

# 调用函数生成结果
append_html_to_pdf("你的原PDF路径.pdf", my_html, "最终输出PDF路径.pdf")

注意事项

  • 关于非文字元素:上面的代码只通过文字来计算内容高度,如果原PDF里有图片、表格等非文字元素,剩余空间计算可能会有点误差。如果需要更精准,可以结合last_page.get_drawings()和last_page.get_images()来补充判断内容的边界。
  • WeasyPrint依赖:在Linux系统上安装WeasyPrint时,可能需要额外装系统依赖(比如libpango-1.0-0、libcairo2等),Windows和Mac一般安装时会自动处理。
  • 复杂HTML拆分:如果HTML内容特别长,且必须拆分第一页塞进剩余空间,那需要更精细的处理(比如把HTML拆分成多个小块逐个转换插入),上面的代码是基础版本,能满足大部分常规场景。

备注:内容来源于stack exchange,提问作者Jitendra Tank

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 15:33:00