【问题标题】:Python: extract text from docx to txt via parsing word/document.xmlPython:通过解析 word/document.xml 将文本从 docx 提取到 txt
【发布时间】:2016-01-14 08:22:52
【问题描述】:

我想将 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、COL 和 PARA 项目,它只会列出我的 ROW。因此,在 for 循环的情况下,程序似乎忽略了术语的或连接。如果它找不到 ROW,它不会执行剩下的 2 个选项,而是立即跳到下一个项目。我也尝试过提供术语列表。

我认为在其中的 if/elif 块,例如if item is ROW 应该检查 'item' 和 'ROW' 是否相同(它们实际上是相同的)。

【问题讨论】:

    标签: python xml parsing xml-parsing docx


    【解决方案1】:
    1. X or Y or Z 计算为三个值中的第一个,该值被强制转换为 True。非空字符串始终为True。因此,for item in tree.iter(ROW or COL or PARA) 的计算结果为 for item in tree.iter(ROW) — 这就是为什么您只能在循环中获取行元素的原因。
    2. ElementTree 对象的 iter() 方法只能接受一个标签名称,因此您或许应该遍历整个树(如果文档不大,则不会有问题)。
    3. is 不会在这里工作。它是一个恒等运算符,仅当比较的对象相同时才返回True(即比较的变量指的是 same Python 对象)。在您的 if... elif... 中,您正在比较一个常量 str (ROW, COL, PARA) 和 Element 对象,该对象在每次迭代中重新创建,因此,显然,这两个对象不是同一个对象,每次比较都会返回 @ 987654332@.
    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))    
    

    【讨论】:

    • 你提到的第一点是如此微不足道,我不敢相信我没有考虑过......好吧,在你回答之前大约半小时,我找到了一些代码,我从中找出了其余部分.毕竟,我认为你已经解决了我的问题。非常感谢!
    【解决方案2】:

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

    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-26
      • 2020-04-10
      • 1970-01-01
      • 2014-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多