
本文介绍使用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("nn".join(content)) print(f"✅ 已保存: {filename}") # 使用示例 split_by_heading("output.html")
3. 进阶建议
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("nn".join(content)) print(f"✅ 已保存: {filename}") # 使用示例 split_by_heading("output.html")
3. 进阶建议
最终,你将获得一组命名清晰、内容完整的 .txt 文件,每份严格对应合同中的一个逻辑章节——无需人工复制粘贴,真正实现法律文档的结构化复用。