Python:通过解析将文本从 docx 提取到 txt word/document。xml

Python: extract text from docx to txt via parsing word/document.xml

我想将 docx 文件中的文本提取到简单的 txt 文件中。 我知道这个问题可能看起来很简单或微不足道(我希望如此)但我查看了数十个论坛主题,花了几个小时试图自己解决但没有找到解决方案...

我从Etienne's blog那里借用了下面的代码。

如果我需要没有格式的内容,它可以完美地工作。但... 由于我的文档包含简单的表格,我需要它们通过简单地使用制表符来保持它们的格式。 所以不是这个:

Name
Age
Wage
John
30
2000

这应该出现:

Name      Age     Wage
John      30      2000

为了不互相滑入,我更喜欢使用双标签来显示较长的行。 我稍微检查了 XML 结构,发现表中的新行由 tr 表示,列由 tc 表示。 所以我试图修改这千种方式但没有成功...... 虽然它并没有真正起作用,但我复制了接近解决方案的想法:

from lxml.html.defs import form_tags

try:
    from xml.etree.cElementTree import XML
except ImportError:
    from xml.etree.ElementTree import XML
import zipfile

WORD_NAMESPACE='{http://schemas.openxmlformats.org/wordprocessingml/2006/main}'
PARA = WORD_NAMESPACE + 'p'
TEXT = WORD_NAMESPACE + 't'
ROW = WORD_NAMESPACE + 'tr'
COL = WORD_NAMESPACE + 'tc'


def get_docx_text(path):
document = zipfile.ZipFile(path)    
xml_content = document.read('word/document.xml')
document.close()    
tree = XML(xml_content)    
paragraphs = []    

for item in tree.iter(ROW or COL or PARA):    
    texts = []
    print(item)    
    if item is ROW:    
        texts.append('\n')    
    elif item is COL:    
        texts.append('\t\t')    
    elif item is PARA:    
        for node in item.iter(TEXT):    
            if node.text:    
                texts.append(node.text)    
    if texts:    
        paragraphs.append(''.join(texts))    
return '\n\n'.join(paragraphs)

text_file = open("output.txt", "w")
text_file.write(get_docx_text('input.docx'))
text_file.close()

我不太确定语法应该是什么样子。输出什么也没有,经过几次试验,它产生了一些结果,但总比没有更糟糕。

我放print(item)只是为了检查。但是它不会只列出 ROW,而不是每个 ROW、COL 和 PARA 项目。因此,在 for 循环的条件下,程序似乎忽略了术语的 or 连接。如果找不到 ROW,它不会执行剩余的 2 个选项,而是立即跳到下一项。我也尝试给出了一个术语列表。

里面有 if/elif 块,我认为例如if item is ROW 应该检查 'item' 和 'ROW' 是否相同(实际上是相同的)。

上面的答案不会像你问的那样有效。这应该适用于仅包含表格的文档;使用 findall 进行一些额外的解析应该可以帮助您隔离 non-table 数据并使其适用于包含表格和其他文本的文档:

TABLE = WORD_NAMESPACE + 'tbl'  

for item in tree.iter():   # use this for loop instead
    #print(item.tag)
    if item.tag == TABLE:
        for row in item.iter(ROW):
            texts.append('\n')
            for col in row.iter(COL):
                texts.append('\t')
                for ent in col.iter(TEXT):
                    if ent.text:
                        texts.append(ent.text)
return ''.join(texts)
  1. X or Y or Z 求值为三个值中的第一个,该值被转换为 True。 Non-empty 字符串总是 True。因此,for item in tree.iter(ROW or COL or PARA) 的计算结果为 for item in tree.iter(ROW) — 这就是为什么您在循环中只获取行元素的原因。
  2. iter() ElementTree 对象的方法只能接受一个标签名称,所以你也许应该遍历整个树(如果文档不大,这不会有问题)。
  3. is 在这里不起作用。它是一个身份运算符,只有 returns True 如果比较的对象相同(即比较的变量指的是 same Python 对象)。在你的 if... elif... 中,你正在比较一个常量 str (ROW, COL, PARA) 和 Element 对象,它在每次迭代中重新创建,所以,很明显,这两个不是同一个对象,每个比较会 return False.
  4. 相反,您应该使用 if item.tag == ROW.

考虑到以上所有因素,您应该像这样重写循环部分:

for item in tree.iter():    
    texts = []
    print(item)    
    if item.tag == ROW:    
        texts.append('\n')    
    elif item.tag == COL:    
        texts.append('\t\t')    
    elif item.tag == PARA:    
        for node in item.iter(TEXT):    
            if node.text:    
                texts.append(node.text)    
    if texts:    
        paragraphs.append(''.join(texts))