最近工作涉及到解析docx,看了许多方法,用C++,java,python都有,最后发现实用性包括简易性还是得python,根本跑不了。然后又看了许多python解析docx的库,最终选择使用python-docx。当然,其实很多教程也是关于如何使用python-docx进行word文档解析的,但是如果我们使用python-docx的基本功能,如:
段落打印:
from docx import Document
from docx.shared import Inches
document = Document('demo.docx') #打开文件
for paragraph in document.paragraphs:
print(paragraph.text) #打印各段落内容文本
或是表格提取:
import docx
from docx import Document #导入库
path = 'demo.docx' #文件路径
document = Document(path) #读入文件
tables = document.tables #获取文件中的表格集
for table in tables[:]:
for i, row in enumerate(table.rows[:]): # 读每行
row_content = []
for cell in row.cells[:]: # 读一行中的所有单元格
c = cell.text
row_content.append(c)
print (row_content) #以列表形式导出每一行数据
利用这种方式进行读取,我们只能读取每部分的最基本的文字信息,对于一些特殊字符无法进行读取及解析。
如:之类的符号,无法通过这种方式解析出来,但是又很需要,这时候就需要我们换一个思路,使用OPENXML进行word的解析。
其实想了解openxml,只要将docx文件后缀改为zip然后解压缩就会发现,整个文件其实分成了很多xml文件,分别存储了文档的内容,格式,打开document.xml就会看到我们的正文内容了。
其中document.xml也遵循了xml的数据结构,包含标签,属性啥的。所以我们要做的就是将表示特殊符号的标签找到,将它恢复到原文中的对应位置。
所以这里选择python-docx的原因就是,他可以在读取docx的同时恢复他的openxml结构,我们可以直接利用xml的方式进行标签搜索。
首先我们先了解一下openxml的格式,参考https://blog.csdn.net/liuqixuan1994/article/details/104486600/:
整体结构:body、styles、setting等
格式Properties结点:<w:pPr>
与<w:rPr>
字体<w:rFonts>
字号<w:sz>
、<w:szCs>
看的见的文字Text:<w:t>
其中我们需要分析特殊字符在xml文件中的表示方法,我碰到的大概三种,一种是
基于这个原因,我们可以在xml中直接搜索对应的标签去寻找特殊字符。
首先我们读取文档,并以XML的方式打开,找到w:r标签,基本段落单元:
from docx import Document
from lxml import etree
doc = Document('demo.docx')
body_xml_str = doc._body._element.xml # 获取body中的xml
body_xml = etree.fromstring(body_xml_str) # 转换成lxml结点
print(etree.tounicode(body_xml)) # 打印查看
for p in doc.paragraphs:
p_xml_str = p._p.xml # 按段落获取xml
p_xml = etree.fromstring(p_xml_str) # 转换成lxml结点
print(etree.tounicode(p_xml)) # 打印查看
xml_dom = parseString(etree.tounicode(p_xml))
stus = xml_dom.getElementsByTagName('w:r')
for si in stus:
print(si)
提取段落中的特殊字符:
sym_id = si.getElementsByTagName('w:sym')
for sym_i in sym_id:
if((sym_i.attributes._attrs['w:font'].nodeValue=='Wingdings2')and(sym_i.attributes._attrs['w:char'].nodeValue=='0052')):
print('特殊字符',end='')
sym_box = si.getElementsByTagName('w:instrText')
for box_i in sym_box:
if((box_i.childNodes[0].data == 'FORMCHECKBOX'):
print('特殊字符',end='')
sym_box = si.getElementsByTagName('w:checked')
for box_i in sym_box:
print('特殊字符',end='')
这样就可以将特殊字符找到了,当然具体场景还得具体去找对应的表示方式进行具体匹配。