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

Python:通过解析word/document.xml将文本从docx提取到txt,python,xml,parsing,xml-parsing,docx,Python,Xml,Parsing,Xml Parsing,Docx,我想将docx文件中的文本提取到简单的txt文件中。 我知道这个问题可能看起来很简单或者很琐碎(我希望是这样),但我已经浏览了几十个论坛主题,花了几个小时试图自己解决,却找不到解决方案 我从中借用了以下代码 如果我需要没有格式的内容,它就可以完美地工作。但是 由于我的文档包含简单的表,我需要它们保持格式,只需使用制表器。 因此,与此相反: 应显示以下内容: 为了避免滑入对方,我更喜欢长线条的双标签。 我稍微检查了一下XML结构,发现表中的新行由tr表示,列由tc表示。 所以我尝试了一千种方法来修

我想将docx文件中的文本提取到简单的txt文件中。 我知道这个问题可能看起来很简单或者很琐碎(我希望是这样),但我已经浏览了几十个论坛主题,花了几个小时试图自己解决,却找不到解决方案

我从中借用了以下代码

如果我需要没有格式的内容,它就可以完美地工作。但是 由于我的文档包含简单的表,我需要它们保持格式,只需使用制表器。 因此,与此相反:

应显示以下内容:

为了避免滑入对方,我更喜欢长线条的双标签。 我稍微检查了一下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()
我不太确定语法应该是什么样子。输出没有给出任何结果,经过几次试验,结果是有些东西,但比什么都没有更糟

我把
打印(项目)
只是为了检查。但它不会列出每一行、COL和PARA项,而是只列出me行。因此,在for循环的条件下,程序似乎在考虑或连接术语。如果找不到行,它将不执行剩余的2个选项,而是立即跳到下一项。我也试着给出一个术语列表


在它里面,if/elif块我认为,例如,
if item是ROW
应该检查“item”和“ROW”是否相同(它们实际上是相同的)。

上面的答案不会像你问的那样有效。这适用于仅包含表的文档;使用
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)

上面的答案不会像你问的那样有效。这适用于仅包含表的文档;使用
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)
  • X或Y或Z
    计算为三个值中的第一个,该值被转换为
    True
    。非空字符串总是
    True
    。因此,
    对于树中的项。iter(行、列或段落)
    的计算结果为
    对于树中的项。iter(行)
    -这就是为什么在循环中只获得行元素
  • iter()
    ElementTree的
    method
    对象只能接受一个标记名,因此您可能只需迭代整个树(如果文档不大,则不会有问题)
  • 在这里不起作用。它是一个标识运算符,仅当比较的对象相同时才返回
    True
    (即比较的变量指的是相同的Python对象)。在您的
    中,如果。。。elif…
    您正在比较常量str(行、列、段)和
    元素
    对象,这两个对象在每次迭代中都会重新创建,因此,很明显,这两个对象不是同一个对象,每次比较都将返回
    False
  • 相反,您应该使用类似于
    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))    
    
  • X或Y或Z
    计算为三个值中的第一个,该值被转换为
    True
    。非空字符串总是
    True
    。因此,
    对于树中的项。iter(行、列或段落)
    的计算结果为
    对于树中的项。iter(行)
    -这就是为什么在循环中只获得行元素
  • iter()
    ElementTree的
    method
    对象只能接受一个标记名,因此您可能只需迭代整个树(如果文档不大,则不会有问题)
  • 在这里不起作用。它是一个标识运算符,仅当比较的对象相同时才返回
    True
    (即比较的变量指的是相同的Python对象)。在您的
    中,如果。。。elif…
    您正在比较常量str(行、列、段)和
    元素
    对象,这两个对象在每次迭代中都会重新创建,因此,很明显,这两个对象不是同一个对象,每次比较都将返回
    False
  • 相反,您应该使用类似于
    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))    
    

    你提到的第一点是如此微不足道,以至于我不敢相信我没有考虑它。。。嗯,在你回答之前大约半个小时,我找到了一些代码,我从中找出了其余的。毕竟,我想你已经解决了我的问题。非常感谢你!你提到的第一点是如此微不足道,以至于我不敢相信我没有考虑它。。。嗯,在你回答之前大约半个小时,我找到了一些代码,我从中找出了其余的。毕竟,我想你已经解决了我的问题。非常感谢你!