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)
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)
— 这就是为什么您在循环中只获取行元素的原因。
iter()
ElementTree
对象的方法只能接受一个标签名称,所以你也许应该遍历整个树(如果文档不大,这不会有问题)。
is
在这里不起作用。它是一个身份运算符,只有 returns True
如果比较的对象相同(即比较的变量指的是 same Python 对象)。在你的 if... elif...
中,你正在比较一个常量 str (ROW, COL, PARA) 和 Element
对象,它在每次迭代中重新创建,所以,很明显,这两个不是同一个对象,每个比较会 return 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))
我想将 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)
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)
— 这就是为什么您在循环中只获取行元素的原因。iter()
ElementTree
对象的方法只能接受一个标签名称,所以你也许应该遍历整个树(如果文档不大,这不会有问题)。is
在这里不起作用。它是一个身份运算符,只有 returnsTrue
如果比较的对象相同(即比较的变量指的是 same Python 对象)。在你的if... elif...
中,你正在比较一个常量 str (ROW, COL, PARA) 和Element
对象,它在每次迭代中重新创建,所以,很明显,这两个不是同一个对象,每个比较会 returnFalse
.- 相反,您应该使用
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))