报错是这么冒出来的。python-docx 1.1 读合同表格,合并单元格的行列索引错位,第三列的金额读成了第二列的日期,同一份文档在 Word 里看是对的。
中间走过弯路,把「表格里还有嵌套表格,层级没区分」当成主因,改完现象没变。
真正麻烦的地方在于,几个原因的现象几乎一样。合并单元格用 gridSpan 和 vMerge 表示,row.cells 会重复返回同一个单元格。另一种情况是按 cells 下标取值,列数被合并打乱。
不容易想到的是,文档用了不规范的合并写法,解析器只能猜。
第一件事是打印每行的 gridSpan 分布
python -c "from docx import Document;d=Document('contract.docx');print([[c.grid_span for c in r.cells] for r in d.tables[0].rows[:3]])"
接着按 tc 的真实位置重建列索引
python -c "from docx import Document;d=Document('contract.docx');print(len(d.tables[0].rows[0].cells))"
随后换 docx2python 对比取到的矩阵
python -c "from docx2python import docx2python;print(docx2python('contract.docx').text[:200])"
剩下的就是对金额列做一次正则校验兜底
python -c "import re;print(re.findall(r'\d+\.\d{2}',open('row.txt').read()))"
别只看报错消失,验证要多做一步。重建索引后金额与日期各归各位,抽 30 份合同与人工核对一致,嵌套表格也能单独取到。
合并单元格在 python-docx 里是逻辑视图不是网格视图,按下标取列一定会错位,得自己按 gridSpan 铺平。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。
