文档信息提取2--python - docx 数据结构
1)一般文档结构
整篇文档是一个Document,将正文分成若干个段落Paragraph(以回车算,一个回车一个段落,表格不算),每个段落Paragraph再划分为若干个run对象。每个run对象内的文本样式都是一致的,也就是说,在从docx文件生成文档对象时,python-docx会根据样式的变化来将文本切分为一个个的Run对象。
https://www.jianshu.com/p/7d2fcf976914

基于以上的理解,在测试的时候发现了一个问题。在一个word文档中编辑一段文字,比如“Hello world”,然后将“hello”的后两个字母去掉“lo”,再将这两个字母加上,最终的结果还是“Hello world”,格式完全没有变过。按照上面的的理解,这段文字应该是一个Paragraph,一个run。
from docx import Document
document1 = Document('C:/Users/huawei/Desktop/1.docx')
document2 = Document('C:/Users/huawei/Desktop/2.docx')
for paragraph in document1.paragraphs:
for run in paragraph.runs:
print(run.text)
for paragraph in document2.paragraphs:
for run in paragraph.runs:
print(run.text)
输出结果:
Hello world
Hel
lo
world
1.docx是改前的,2.docx是改后的。可见改后文档变成了3个run对象。去
Proxy object wrapping <w:r> element. Several of the properties on Run take a tri-state value, |True|, |False|, or |None|. |True| and |False| correspond to on and off respectively. |None| indicates the property is not specified directly on the run and its effective value is taken from the style hierarchy.
看到这也没太看明白, <w:r> element 这个又是哪来的。只好再去看一下源码,看具体一个word文档读取进来是如何构建的run对象。发现实际读取文件调用ZipFile.py;读取进来之后是实际一堆的xml文件。疑问1,为什么最终使用ZipFile.py,读取的不是word而是zip压缩文件。疑问2,直接读取进来为什么是一堆的xml文件。



找了一下具体的Hello world 是在 /word/document.xml下面,在这个文件里面文档的分块结构已经构建好了。源码看到这感觉更困惑了。百度查找/word/document.xml相关信息,看看有没有姜document.xml文件时怎么被创建的。
直接给结论,Office 2007之前的版本使用的是二进制格式定义(未公开标准),Office 2007之后文档格式使用 OOXML 国际标准定义,OOXML 的全称是 Office Open XML File Formats 或被称为 OpenXML 格式,这是一个基于 zip+xml 定义的文档格式。说人话就是Office 2007之后后缀为pptx、docx、xlsx的文件实际上是一个ZI包,包中为一堆的xml文件。
直接用WinRAR打开word文档,如下图所示。



首先按照
还有最开始的疑问,文字编辑后即使格式一样为什么还会产生多个run。将之前的两个word文档以WinRAR方式打开对比一下。发现在settings.xml和document.xml里确实不太一样。

在settings.xml文件中多了一个rsid,文档修改保存一次会产生一个新的ID。

在document.xml文件中一个w:r变成了3个w:r,且给修改的run分配了一个新的ID,也就是settings.xml文件中新增的rsid。所以python在读取的时候就是3个run对象。
在追问一下,微软为什么这么设计。目前没找到答案初步猜想一下,这种设计类似于记录修改日志,对与改前和改后的文件对比是比较方便的(也是在2007之后版本推出了文件对比功能,当然2003版本之前也是可以对比的只是这种设计会更方便);除了文档对比之外,文件在线多人编辑也会变得更简单,格式也有单独的xml文件记录;还有ZIP格式也会比原来的文档小得多。
浙公网安备 33010602011771号