
本文介绍使用pdftohtml工具将法律合同类pdf精准转换为带语义标签(如h1–h6、p)的html,再借助beautiful soup解析标题与正文并分段导出为独立文本文件的完整流程。
在处理结构清晰但无交互能力的PDF文档(如标准法律合同)时,直接提取“标题+对应内容”是常见需求。由于PDF本质是布局导向而非语义导向,无法直接读取逻辑章节,因此需借助语义重建策略:先将PDF转换为结构化HTML(保留标题层级与段落关系),再通过DOM解析实现精准切分。
✅ 推荐方案:pdftohtml + Python(Beautiful Soup)
pdftohtml 是成熟稳定的开源工具(基于Poppler),能将PDF中识别出的视觉层级(如字体大小、加粗、缩进等启发式特征)映射为HTML语义标签(如
、、
),特别适合格式规整的合同类文档。
1. 安装与基础转换
macOS 用户可通过 Homebrew 安装:
brew install pdftohtml
Windows/Linux 用户可从 pdftohtml 官网 下载二进制包,或使用 poppler-utils 中的 pdftohtml(Ubuntu/Debian):
立即学习“前端免费学习笔记(深入)”;
sudo apt-get install poppler-utils
执行转换(启用结构化输出,保留标题语义):
pdftohtml -c -s -i input_contract.pdf output.html
- -c:启用CSS样式(提升结构可读性)
- -s:生成单文件HTML(非分页碎片)
- -i:忽略图像(合同文本为主时可提速并减少干扰)
⚠️ 注意:pdftohtml 的标题识别依赖PDF内嵌字体信息与排版线索。若原PDF为扫描件(图片型),需先用OCR工具(如 pdf2image + pytesseract)转为可搜索PDF,再进行转换。
2. 解析HTML并按章节拆分
安装依赖:
pip install beautifulsoup4
Python 脚本示例(自动识别
– 标题,并将后续非标题内容归入该节,直到下一标题出现):from bs4 import BeautifulSoup
import re
def split_by_heading(html_path, output_dir="sections"):
import os
os.makedirs(output_dir, exist_ok=True)
with open(html_path, "r", encoding="utf-8") as f:
soup = BeautifulSoup(f, "html.parser")
# 移除脚注、页眉页脚等干扰区域(根据实际HTML结构调整)
for elem in soup(["script", "style", "footer", "header", "nav"]):
elem.decompose()
headings = soup.find_all(re.compile(r"^h[1-6]$"))
for i, h in enumerate(headings):
title = h.get_text(strip=True)
if not title:
continue
# 生成安全的文件名(去除非法字符)
safe_title = re.sub(r'[<>:"/\\|?*]', "_", title)[:50]
filename = f"{output_dir}/Section_{i+1}_{safe_title}.txt"
# 收集该标题后所有连续段落(p)、列表(ul/ol)、甚至嵌套div
content = [title]
sibling = h.next_sibling
while sibling and not sibling.name or not re.match(r"^h[1-6]$", sibling.name):
if sibling.name in ["p", "ul", "ol", "div"] and sibling.get_text(strip=True):
content.append(sibling.get_text(strip=True))
sibling = sibling.next_sibling
with open(filename, "w", encoding="utf-8") as f:
f.write("\n\n".join(content))
print(f"✅ 已保存: {filename}")
# 使用示例
split_by_heading("output.html")3. 进阶建议
-
验证HTML质量:打开生成的 output.html,检查
是否真实对应合同中的“第X条”“甲方义务”等标题;若错位,可微调 pdftohtml 参数(如 -zoom 1.5 提升识别精度)或预处理PDF(Acrobat “增强扫描”)。
-
替代工具对比:pdfplumber(Python库)提供更细粒度的文本定位,适合自定义规则;pymupdf(fitz)速度快,支持直接提取带坐标的文本块,但需自行聚类标题。
-
批量与自动化:可封装为CLI工具,支持通配符输入(如 *.pdf)及JSON元数据导出(含章节编号、页码范围)。
from bs4 import BeautifulSoup
import re
def split_by_heading(html_path, output_dir="sections"):
import os
os.makedirs(output_dir, exist_ok=True)
with open(html_path, "r", encoding="utf-8") as f:
soup = BeautifulSoup(f, "html.parser")
# 移除脚注、页眉页脚等干扰区域(根据实际HTML结构调整)
for elem in soup(["script", "style", "footer", "header", "nav"]):
elem.decompose()
headings = soup.find_all(re.compile(r"^h[1-6]$"))
for i, h in enumerate(headings):
title = h.get_text(strip=True)
if not title:
continue
# 生成安全的文件名(去除非法字符)
safe_title = re.sub(r'[<>:"/\\|?*]', "_", title)[:50]
filename = f"{output_dir}/Section_{i+1}_{safe_title}.txt"
# 收集该标题后所有连续段落(p)、列表(ul/ol)、甚至嵌套div
content = [title]
sibling = h.next_sibling
while sibling and not sibling.name or not re.match(r"^h[1-6]$", sibling.name):
if sibling.name in ["p", "ul", "ol", "div"] and sibling.get_text(strip=True):
content.append(sibling.get_text(strip=True))
sibling = sibling.next_sibling
with open(filename, "w", encoding="utf-8") as f:
f.write("\n\n".join(content))
print(f"✅ 已保存: {filename}")
# 使用示例
split_by_heading("output.html")3. 进阶建议
-
验证HTML质量:打开生成的 output.html,检查
是否真实对应合同中的“第X条”“甲方义务”等标题;若错位,可微调 pdftohtml 参数(如 -zoom 1.5 提升识别精度)或预处理PDF(Acrobat “增强扫描”)。
- 替代工具对比:pdfplumber(Python库)提供更细粒度的文本定位,适合自定义规则;pymupdf(fitz)速度快,支持直接提取带坐标的文本块,但需自行聚类标题。
- 批量与自动化:可封装为CLI工具,支持通配符输入(如 *.pdf)及JSON元数据导出(含章节编号、页码范围)。
最终,你将获得一组命名清晰、内容完整的 .txt 文件,每份严格对应合同中的一个逻辑章节——无需人工复制粘贴,真正实现法律文档的结构化复用。











