简体中文 | English
确定性、非 LLM 的中文标准文件 PDF → Markdown 转换工具。
转换器不绑定任何单一标准体系:GB 国家标准、QB/SB 行业标准,以及其他中文标准与 法规类文件,走的都是同一套通用的 PDF、版面与 OCR 处理流程。
日常单个文件转换使用 standard_to_markdown.py;需要质量报告、页码选择或 OCR
控制时使用进阶转换器 pdf_to_markdown_auto.py。
- 转换流程中不使用 LLM。
- 优先采用通用的 PDF/OCR/版面方法,而不是针对特定文档的配置档。
- 不为了让测试通过而加入食品专用、特定标准专用或样本专用的词典。
- 宁可把 OCR 的不确定性暴露在报告里,也不静默地把它变成看似合理的错误文本。
本项目以 Python 3.10 作为最低支持版本,类型注解使用了 X | None、list[...]
等较新的写法。已在 Python 3.10.5 与 3.13.7 上完整跑通测试。
python3 --version # 需要 >= 3.10文字层完好的 PDF 不依赖 OCR,但只要出现扫描件、字体映射损坏等情况,转换器就会
回退到 Tesseract。它是命令行程序,必须单独安装,并且必须包含简体中文与
英文语言包(chi_sim 与 eng)。
安装方式:
# macOS (Homebrew)
brew install tesseract tesseract-lang
# Debian / Ubuntu
sudo apt-get update
sudo apt-get install -y tesseract-ocr tesseract-ocr-chi-sim
# Windows:下载 UB Mannheim 版安装包
# https://github.com/UB-Mannheim/tesseract/wiki
# 安装时在 "Additional language data" 中勾选 Chinese (Simplified)安装后确认语言包齐全——这一步很容易被忽略,缺 chi_sim 会导致中文 OCR 直接失败:
tesseract --version
tesseract --list-langs | grep -E '^(chi_sim|eng)$'
# 期望输出两行:chi_sim 与 eng全部依赖声明在 requirements.txt:
| 包 | 用途 | 是否必需 |
|---|---|---|
PyMuPDF |
提供 fitz,负责文字层提取、坐标与表格发现 |
必需 |
pytesseract |
Tesseract 的 Python 封装 | 必需 |
Pillow |
OCR 图像预处理与调试叠加图工具 | 必需 |
opencv-python |
OCR 图像预处理:纠偏、去噪、自适应二值化、表格线检测 | 可选,建议安装 |
numpy |
同上,与 OpenCV 配合 | 可选,建议安装 |
pytest |
运行 tests/ 下的回归测试 |
仅开发需要 |
关于可选依赖:转换器在运行时检查 cv2 与 numpy 是否存在,缺失时会跳过上述
预处理变体。因此没有它们 OCR 仍能运行,只是少了几层兜底,在扫描质量较差的文件上
识别效果可能变差,tools/eval_ocr_samples.py 的质量门也可能因此不达标。
requirements.txt 使用版本下限而非精确锁版本,因为转换器只依赖 PyMuPDF、
pytesseract、Pillow 的稳定 API。实际验证环境为:全新虚拟环境安装后得到
PyMuPDF 1.28.2 / pytesseract 0.3.13 / Pillow 12.3.0 / opencv-python 5.0.0.93 /
numpy 2.2.6,tests/ 全部 77 项通过。
git clone https://github.com/Sirfetch-d/std2md.git
cd std2md
# 1. 创建虚拟环境
python3 -m venv .venv
# 2. 激活虚拟环境
source .venv/bin/activate
# 3. 升级 pip(可选,但建议)
python -m pip install --upgrade pip
# 4. 安装依赖
pip install -r requirements.txtgit clone https://github.com/Sirfetch-d/std2md.git
cd std2md
python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements.txt激活成功后,命令行提示符前会出现 (.venv)。之后所有命令都在该虚拟环境中执行,
退出用 deactivate。
pip install -r requirements-dev.txtgit config core.hooksPath .githooks该钩子会拒绝提交源 PDF、.docx 中间产物、生成的 auto-md/ 输出、本地环境文件,
并在安装了 gitleaks 时扫描暂存内容里的凭据。扫描器用 brew install gitleaks
安装;未安装时只保留路径守卫。确需提交的样例文件仍可用 git add -f 加入,单次
提交也可用 git commit --no-verify 绕过,但两者都应在提交信息里说明原因。
需要注意这是兜底而非保证:gitleaks 匹配已知的凭据形态并做熵检测,形状特殊
或低熵的密钥仍可能漏过。推送前请自行过一遍暂存内容。
本仓库不包含任何标准 PDF,Standards/、Laws/、auto-md/、local/ 均被
git 忽略。请自行合法获取源文件并放入 Standards/:
mkdir -p Standards
cp /path/to/"GB 7718-2025 食品安全国家标准 预包装食品标签通则.pdf" Standards/本文档的示例都使用
Standards/、auto-md/这类相对路径,请先cd到仓库根目录再执行。 也可以用绝对路径从其它目录调用脚本,例如python /path/to/std2md/standard_to_markdown.py "/abs/path/file.pdf"。
把一个标准 PDF 转成同目录同名的 .md:
python standard_to_markdown.py "Standards/GB 7718-2025 食品安全国家标准 预包装食品标签通则.pdf"输出:
Standards/GB 7718-2025 ....pdf -> Standards/GB 7718-2025 ....md (text)
括号里是该文件实际走的路径,text 表示文字层,ocr 表示 OCR 回退。
带质量报告、自动识别文字层/OCR,并跳过前置页:
python pdf_to_markdown_auto.py --standard --report -o auto-md/standards \
"Standards/GB 7718-2025 食品安全国家标准 预包装食品标签通则.pdf"完整转换(不跳过任何页):
python pdf_to_markdown_auto.py --full --report -o auto-md "Standards/example.pdf"只调试指定页:
python pdf_to_markdown_auto.py --standard --report --pages 4,6 -o auto-md/ocr "Standards/example.pdf"实验性的慢速 OCR 重试模式(在困难扫描件上多试几种预处理):
python pdf_to_markdown_auto.py --standard --report --ocr-deep-retry -o auto-md/ocr "Standards/example.pdf"常用参数:
| 参数 | 说明 |
|---|---|
--standard |
标准正文模式:跳过第一个「1 范围」页之前的前置页(封面、目次、前言等) |
--full |
全文模式:包含 PDF 的每一页 |
--report |
在每份输出旁写出 .report.md 质量报告 |
--pages |
调试模式:只转换指定页,1 起算,如 3 或 3,5-7 |
-o / --out-dir |
指定输出目录 |
--ocr-cache-dir |
指定持久化 OCR 缓存目录 |
--no-ocr-cache |
关闭持久化 OCR 缓存 |
--ocr-deep-retry |
对困难扫描页尝试更慢的 OCR 预处理变体 |
--standard 与 --full 互斥,不指定时默认为 --standard。
需要区分的是:文字层与 OCR 之间的选择才是自动的——转换器先用
text_layer_is_trustworthy 判断该 PDF 的文字层是否可信,可信则走文字层解析,
不可信才回退到 OCR。输出的括号里会标明实际走了哪条路(text 或 ocr)。
小型 OCR 样本集,附带质量门,指标回退时会以非零状态退出:
python tools/eval_ocr_samples.py文字层生产基线集,会重跑所有受信任文字层 PDF 的 --standard 与 --full 两种
模式,包含 GB 2760 这类大表格压力样本:
python tools/eval_text_samples.py需要探索性诊断时可以加 --no-fail 只看汇总而不让命令失败。
注意:这两个脚本依赖本仓库不包含的本地语料。
它们各自内置了一份固定的样本清单,清单里的 PDF 全部位于
Standards/,而本仓库 按设计不提交任何 PDF。脚本遇到缺失文件时直接抛出FileNotFoundError退出, 不会跳过该样本。因此刚 clone 下来的仓库直接运行这两个命令会失败,这是预期行为, 不是环境装错了。
tools/eval_ocr_samples.py需要:GB T 31121-2014、QB T 2076-2021、GB T 29602-2013tools/eval_text_samples.py需要清单内 10 份 GB/GB T 文件,含GB 2760-2024(约 5244 行表格的压力样本)要用它们做质量门,请自行准备清单中对应的 PDF 放入
Standards/。如果只想转换自己的 文件,完全可以忽略这两个脚本,直接用「方式一」或「方式二」。
python tools/render_ocr_coordinate_overlay.py auto-md/ocr-eval/example.report.json \
--pdf "Standards/example.pdf" -o auto-md/debug-overlays/example输出 PNG 页面叠加图、index.html 与 overlay_summary.json 到指定目录。这类生成物
请一律放在 auto-md/ 下。
使用 --report 时,每次转换会写出两个报告文件:
.report.md— 人类可读的质量报告.report.json— 结构化的机器可读指标,供eval_ocr_samples.py等工具消费
JSON 结构由 tools/quality_metrics.py 中的 QualityMetrics 定义。
OCR 缓存默认写在 auto-md/.ocr-cache/。首次处理扫描件时 OCR 较慢,之后同一页会
命中缓存。缓存键包含转换器版本,因此升级后预期会重新识别。
低置信度坐标记录同时包含源坐标与归一化坐标:
bbox_raw— PDF 页面坐标,用于溯源调试bbox_norm— 归一化到固定0..10000逻辑画布的坐标,使不同页面、不同 PDF 之间的位置可直接比较was_clamped— 归一化坐标越出画布并被夹到边界时为 trueclamped_coordinate_count— 被夹取的诊断记录总数
夹取与归一化坐标只是诊断信号,用于指导人工复核、可视化与质量遥测,不得用来 静默修正 OCR 文本。
文字层报告还包含 text_fracture_issues,用于标记未解决的换行断裂,例如悬空的条款
引用(按4.)、标准号引用(GB5009.)或不完整的条款引用(按4.3.的要求)。
生产环境的文字层基线应保持该值为 0。
文字层报告包含以下字段:
logical_tables— 安全跨页合并后的 Markdown 表格块数table_continuations_detected— 检测到的续接组(含已合并与明确未解决)table_continuations_merged— 在 Markdown 序列化前合并的兼容邻页表格组table_continuations_unresolved— 结构上合理但因表头不匹配而保留待人工复核的续接repeated_table_headers_removed— 合并片段中被移除的等价重复表头行
合并后的表格会附带一段 HTML 溯源注释,列出其来源页。续接判定综合使用了表格标识、 页边几何、列数与归一化表头。携带行号或条目元信息的表题会作为独立子表边界保留。
在文字层模式下(见 AGENTS.md 的回归检查):
- GB 28050:210 行 Markdown 表格,0 个表宽问题,0 个单元格审计问题
- GB 7718:13 行 Markdown 表格,0 个表宽问题,0 个单元格审计问题
tools/— 评测器、共享辅助模块与诊断工具tests/— 确定性回归测试standard_to_markdown.py— 简单入口,在源文件旁写出同名.mdpdf_to_markdown_auto.py— 进阶转换器,支持报告、页码选择与 OCR 控制Standards/— 本地中文标准 PDF 语料,默认被 git 忽略(不提交 PDF)Laws/— 可选的本地法规类 PDF 语料,同样默认忽略auto-md/— 生成的 Markdown、报告、OCR 缓存与调试图,永不提交local/baselines/— 两份手工整理的 Markdown 质量基线,仅本地保留local/manual-intermediates/— 人工比对过程中产生的 DOCX 与草稿副本local/duplicate-pdfs/— 不属于规范语料、但需保留的重复源 PDF
改完代码后先做语法校验:
python -m py_compile standard_to_markdown.py pdf_to_markdown_auto.py跑单元测试:
python -m pytest tests/ -q改动 OCR 相关逻辑时,先用指定页做定向检查,再跑整份文件:
python pdf_to_markdown_auto.py --standard --report --pages 4,6 -o auto-md/ocr \
"Standards/GB T 31121-2014 果蔬汁类及其饮料(含第1号修改单)-现行有效.pdf"判断 OCR 改动时,必须同时看 .report.md 的指标和 .auto.md 的实际内容。
审计计数变低但文本变成"看似合理却是错的",这种情况不算改进。
TesseractNotFoundError: tesseract is not installed
Tesseract 未安装,或不在 PATH 中。按上文安装后用 tesseract --version 确认。
若装在非标准路径,可通过设置 pytesseract.pytesseract.tesseract_cmd 指定。
OCR 报 Failed loading language 'chi_sim'
缺简体中文语言包。tesseract --list-langs 里必须有 chi_sim。macOS 装
tesseract-lang,Debian/Ubuntu 装 tesseract-ocr-chi-sim。
ModuleNotFoundError: No module named 'tools'
出现在把 pdf_to_markdown_auto.py 单独复制到仓库外运行的时候。该脚本依赖同仓库的
tools/ 包,请连同整个仓库一起使用,不要只拷贝单个脚本文件。
运行 tools/eval_ocr_samples.py 或 tools/eval_text_samples.py 报 FileNotFoundError
预期行为,不是环境问题:这两个脚本使用内置的固定样本清单,而本仓库不提交 PDF。
详见上方「方式三」的说明。只想转换自己的文件时可以忽略它们。
OCR 效果差 / 评测质量门不达标
先确认 opencv-python 与 numpy 已安装(pip show opencv-python numpy),
缺了它们会跳过纠偏、去噪等预处理变体。仍不理想时可加 --ocr-deep-retry
做慢速重试。
扫描件处理很慢
属正常现象:OCR 逐页识别,首次运行还需生成缓存。后续同页会命中
auto-md/.ocr-cache/。调试时优先用 --pages 只跑关键页。
运行时出现 The 'fitz' API is deprecated ... Use 'import pymupdf' instead
这是 PyMuPDF 1.28 及以上版本打印的弃用提示,不影响当前功能,可以忽略。转换器
目前使用 import fitz 这一旧名称以兼容较老的 PyMuPDF。待确认所有受支持版本都
提供 pymupdf 模块名后,会统一切换。
- 只跟踪转换器代码与轻量级项目文档。
- 生成的 Markdown 报告、OCR 缓存、调试裁图、本地基线、本地环境文件与人工中间 产物一律不入库。
- 标准 PDF 默认作为本地测试语料;确需加入时应当是有意为之。
- 手工整理的基线与其它本地草稿放在各自的
local/子目录下。
本仓库只包含工具,不附带任何标准文件。
仓库中不提交 PDF 源文件、不提交转换出的 Markdown,也不提交手工整理的基线。
Standards/、Laws/、auto-md/、local/ 均被 git 忽略,只存在于本地工作副本。
- GB 国家标准、QB/SB 行业标准及同类法规文本的版权归各自发布机构所有。在中国大陆, GB 标准由中国标准出版社出版。请合法获取源文件,并遵守其附带的使用条款。
- 请勿提交、上传或再分发转换出的标准正文。转换产物仅供本地个人研究与互操作用途; 是否可以再发布其中任何部分,应由权利人判断,而不是由本工具决定。
- 本项目与中国国家标准化管理委员会(SAC)、国家卫生健康委员会(NHC)或其他任何 标准机构均无隶属、认可或关联关系。
- OCR 与版面重建都是启发式的。输出可能包含错误,低置信度计数少也不等于内容正确。 凡是要依赖的内容,请与权威来源文件核对。
本项目基于 MIT 许可证 发布。
MIT 许可证仅覆盖本仓库的源代码,不覆盖任何标准文件,也不覆盖由标准文件转换 得到的文本。