# govdoc-md-cleaner 政务文档(招标 / 投标 / 采购 / 合同)**PDF→Markdown 产物**的规则化清洗工具。 上游解析管线(MinerU / OCR)把 PDF 转成 Markdown 后,会带入大量非正文噪音: 逐页重复的页眉页脚、页码行、目录点线、死链图片引用、压成单行的 HTML 表格、 行尾硬换行双空格,以及 OCR 重复崩坏段。本工具用一套 **YAML 声明、按序应用、 逐条统计** 的规则把它们清掉,输出可直接进入比对 / RAG / 审核管线的干净 Markdown。 ## 数据来源 清洗目标为 `/home/lihaoze/gov_test_data`(律所上传的真实政务文件的筛选子集, 详见其 `compare/readme.md`),未来会持续接入更多批次的 Markdown 文件。 **本项目只包含清洗代码与规则,不包含任何业务数据**——测试数据不入库。 ## 清洗规则(rules/default.yaml) | 顺序 | 规则 | 处理对象 | 示例 | |---|---|---|---| | 10 | `strip_page_lines` | 页码行 | `第 3 页 共 53 页`、`第4页共4页`、`Page 3 of 10`、`- 4 -` | | 20 | `strip_repeated_short_lines` | 页眉页脚 + OCR 崩坏 | 全篇重复 ≥3 次的短行;连续刷屏 ≥5 次(实测"审计程序"×1359) | | 30 | `strip_toc_dots` | 目录点线 | `第一章 投标邀请函 ………… 2` → 保留标题,删点线页码 | | 40 | `drop_images` | 死链图片 | `![](images/xxx.jpg)`、base64 内嵌图 | | 50 | `normalize_tables` | HTML 表格 | `
…` 单行压缩 → Markdown 管道表格 | | 60 | `strip_stray_html` | 散落标签 | `
` | | 70 | `rstrip_lines` | 行尾空白 | MinerU 每行行尾的双空格硬换行 | | 80 | `collapse_blank_lines` | 空行折叠 | 连续空行 → 1 行;裁掉文首文末 | ### 防误伤设计(来自真实数据踩坑) - **protect 正则**:`投标人:(公章)`、`法定代表人签名:`、`日期: 年 月 日`、 `致:xxx`、声明函结尾句——标书里逐章重复,**是正文模板不是页眉**,默认保护。 - **内容形态豁免**:编号条款 `(1)…`、`1、…`、`一、…`、列表/表格行、 `乙方:xxx` 字段行——平行结构天然重复,引擎侧直接不参与页眉判定。 - **burst 检测**:同一短行连续刷屏 ≥5 次(间隔 ≤2 行)判为 OCR 重复崩坏, 直接删除(003-10 案例出现"审计程序"连续 1359 行)。 ## 安装 ```bash pip install -e . # 或直接 python -m cleaner.cli(仅需 PyYAML) ``` ## 使用 ```bash # 单文件:清洗 + 打印统计 md-clean single input.md -o output.md --diff # 批量:递归清洗目录下所有 .md,输出到平行目录 + JSON 报告 md-clean batch /path/to/uploads -o /path/to/uploads_cleaned \ --pattern "*.md" --report report.json # 用自定义规则集(复制 default.yaml 改参数即可) md-clean batch uploads/ --rules rules/strict.yaml ``` `--diff` 输出 unified diff,`report.json` 记录每个文件每条规则的命中数, 清洗过程完全可审计、可回滚(重跑即得原结果的对照)。 ## 项目结构 ``` govdoc-md-cleaner/ ├── cleaner/ │ ├── cleaner.py # 引擎:按序应用规则,输出 CleanResult(text, stats) │ ├── rules.py # 规则实现 + REGISTRY + YAML 加载 │ └── cli.py # single / batch 两个子命令 ├── rules/ │ └── default.yaml # 默认规则集(顺序、开关、参数、protect 列表) ├── tests/ │ └── test_rules.py # 每条规则的最小样例 + 防误伤回归 └── docs/ └── RULES.md # 规则编写指南(新增规则的方法) ``` ## 新增一条规则 1. `cleaner/rules.py`:实现 `_your_rule(text, params, stats) -> text`,注册进 `REGISTRY`; 2. `rules/default.yaml`:追加 `- name: your_rule / order: / params:`; 3. `tests/test_rules.py`:加一个真实数据浓缩出的最小样例。 原则:**规则只删噪音不删正文**;拿不准的形态默认保留,靠 protect/exempt 收紧。 ## 测试 ```bash python -m unittest discover tests -v ``` ## License MIT