python-docx结合lxml读取word文档段落格式、字体格式等信息
最近还是在研究docx文档,搞了几天终于有点心得了。不得不说,虽然python-docx库没那么强大能直接获取样式继承的字体信息之类的,但是通过使用python-docx,获取段落的xml信息会简单很多,结合lxml进一步获取信息也会方便很多。
首先还是,记一下关于样式继承。
一个样式可以从另一个样式继承属性,有点类似于层叠样式表 (CSS) 的工作方式。base_style使用属性指定继承 。通过将一种风格建立在另一种风格上,可以形成任意深度的继承层次结构。没有基本样式的样式会从文档默认值继承属性。
许多字体属性是三态的,这意味着它们可以采用值 True、False和None。True表示该属性是“on”,False表示它是“off”。从概念上讲,None价值意味着“继承”。
样式继承依然不是那么好理解。
这次写详细一点点叭
document.xml/style.xml
当我们把文档后缀的.docx修改成.zip,解压就会看到一些文件。 其中word文件夹下document.xml是存放文本的主要文件,文档的样式信息则在style.xml中。
信息获取
如果,文档中的某个段落应用了样式,则该段落的字体格式等一些信息需要从style.xml中获取。
此时使用python-docx获取字体格式信息之类的,大概率返回的结果是None。也有可能返回的是英文字体信息。
import docx
file_name = 'temp.docx'
doc = docx.Document(file_name)
paragraphs = doc.paragraphs
print('段落0字体:',paragraphs[0].style.font.name)
print('段落3字体:',paragraphs[3].style.font.name)
段落0字体: None
段落3字体: Times New Roman
那么问题来了,返回为None时或者想要获取到中文字体该怎么办呢?接下来要说说我不是很懂以及我也很苦恼的xml了。
首先让我们打印一下段落的xml看看它是个啥。
print(paragraphs[0]._p.xml)
<w:p xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpsCustomData="http://www.wps.cn/officeDocument/2013/wpsCustomData">
<w:pPr>
<w:pStyle w:val="6"/>
<w:ind w:firstLine="723"/>
<w:rPr>
<w:b w:val="0"/>
<w:bCs w:val="0"/>
<w:sz w:val="36"/>
<w:szCs w:val="36"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:b w:val="0"/>
<w:bCs w:val="0"/>
<w:sz w:val="36"/>
<w:szCs w:val="36"/>
</w:rPr>
<w:t>这里是应用了标题样式的一个标题(黑体 小二号居中)</w:t>
</w:r>
</w:p>
字体信息在<w:rFonts>
中的,可以看到这里面是没有显示详细的字体信息的。注意到前面有<w:pStyle w:val="6">
,说明这里用到了id为“6”的style。所以打印一下这个段落的样式的xml看看。
print(paragraphs[0].style.element.xml)
<w:style xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main" xmlns:wpsCustomData="http://www.wps.cn/officeDocument/2013/wpsCustomData" w:type="paragraph" w:styleId="6">
<w:name w:val="Title"/>
<w:basedOn w:val="1"/>
<w:next w:val="1"/>
<w:link w:val="13"/>
<w:qFormat/>
<w:uiPriority w:val="10"/>
<w:pPr>
<w:spacing w:before="240" w:after="60"/>
<w:jc w:val="center"/>
<w:outlineLvl w:val="0"/>
</w:pPr>
<w:rPr>
<w:rFonts w:eastAsia="黑体" w:asciiTheme="majorHAnsi" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi"/>
<w:b/>
<w:bCs/>
<w:sz w:val="36"/>
<w:szCs w:val="32"/>
</w:rPr>
</w:style>
可以看到在style中是有字体信息的。
获取字体信息方法1
转换成lxml后进行信息提取
from lxml import etree
from xml.dom.minidom import parseString
p_style_xmlstr = paragraphs[0].style.element.xml
p_style_xml = etree.fromstring(p_style_xmlstr) # 转换成lxml结点
p_style_dom = parseString(etree.tounicode(p_style_xml))
# 获取段落字体信息
# 字体名称
style_w_rfonts = p_style_dom.getElementsByTagName('w:rFonts')
font_name_zh = w_rfonts[0].getAttribute('w:eastAsia')
font_name = w_rfonts[0].getAttribute('w:ascii')
获取字体信息方法2
使用xpath进行信息提取
link_id = paragraphs[0].style.element.xpath('string(.//w:pStyle/@w:val)')
font_name_zh = doc.styles.element.xpath(f'string(.//w:style[@w:styleId={link_id}]//w:rFonts/@w:eastAsia)')
font_name = doc.styles.element.xpath(f'string(.//w:style[@w:styleId={link_id}]//w:rFonts/@w:ascii)')