利⽤python-docx批量处理Word⽂件—图⽚
图⽚是Word的⼀种特殊内容,这篇⽂章主要内容是如何利⽤python-docx批量提取Word中的图⽚,以及如何在Word国插⼊图⽚。
1.提取Word中的图⽚并保护成指定格式
docx好像并没有直接获取图⽚的⽅法,⽹上的资料也很少,有⽤的资料我就到这⼀篇:
说实话,这篇⽂章我看的不是太懂,⽽且这个⽅法只能获得内联的图⽚,什么是内联的图⽚呢,我也不知道,我只知道我们在word中直接插⼊的图⽚不属于这种,也就是这种⽅法并不能获得word中直接插⼊的图⽚,我⽤add_picture()插⼊⼀张图⽚,⽤该⽅法可以获得。受这篇⽂章的启发,我看了⼀下python-docx的源码,虽然没有看懂,但也得到⼀个⽤有的信息:python-docx会将wrod⽂件转换成Proxy Type(不敢翻译)格式进⾏处理。Proxy Type格式是什么样的呢,其实质是xml,不同的类型会被转成不同的Proxy Type,以Document 为例,可以⽤document._l查看被转换后的内容:
这就是word内容转换成Proxy Type后的形式(⼤部分信息被我折叠了),我对xml研究不多,可以看出所有标签都是<w:x>的形式,整个⽂档包含在<w:document></w:document>标签中,每段以<w:p>开始,</w:p>结束 ,图⽚在docx中也是段落,因此我们过以通过遍历整
个xml到包含图⽚的段落,要通过遍历到图⽚,图⽚所在的段落必须有其特殊之处,不然我们也⽆判断。下⾯是⼀幅图处的Proxy Type的内容:
<p w="/wordprocessingml/2006/main"wpc="schemas.microsoft/office/word/2010/wordprocess ingCanvas"mc="/markup-compatibility/2006"o="urn:schemas-microsoft-com:office:office"r="s /officeDocument/2006/relationships"m="/officeDocument/2006/math"v="urn:s chemas-microsoft-com:vml"wp14="schemas.microsoft/office/word/2010/wordprocessingDrawing"wp="schemas./drawingml/2006/wordprocessingDrawing"w10="urn:schemas-microsoft-com:office:word"w14="schemas.microsoft/office/wo rd/2010/wordml"w15="schemas.microsoft/office/word/2012/wordml"wpg="schemas.microsoft/office/word/2010/wordproc essingGroup"wpi="schemas.microsoft/office/word/2010/wordprocessingInk"wne="schemas.microsoft/office/word/2006/ wordml"wps="schemas.microsoft/office/word/2010/wordprocessingShape"rsidR="00B20677"rsidRDefault="00D47C7B"rsidP="00 ED22C2">
<pPr>
<rPr>
<rFonts ascii="宋体"eastAsia="宋体"hAnsi="宋体"/>
<lang eastAsia="zh-CN"/>
</rPr>
</pPr>
<r>
<rPr>
<rFonts ascii="宋体"eastAsia="宋体"hAnsi="宋体"/>
<lang eastAsia="zh-CN"/>
</rPr>
<pict>
<shapetype id="_x0000_t75"coordsize="21600,21600"spt="75"preferrelative="t"path="m@4@5l@4@11@9@11@9@5xe"filled="f"stroked="f" >
<stroke join/>
<formulas>
< f eqn="if lineDrawn pixelLineWidth 0"/>
< f eqn="sum @0 1 0"/>
< f eqn="sum 0 0 @1"/>
< f eqn="prod @2 1 2"/>
< f eqn="prod @3 21600 pixelWidth"/>
< f eqn="prod @3 21600 pixelHeight"/>
< f eqn="sum @0 0 1"/>
< f eqn="prod @6 1 2"/>
< f eqn="prod @7 21600 pixelWidth"/>
< f eqn="sum @8 21600 0"/>
< f eqn="prod @7 21600 pixelHeight"/>
< f eqn="sum @10 21600 0"/>
</formulas>
<path extrusionok="f"gradientshapeok="t"connecttype="rect"/>
<lock ext="edit"aspectratio="t"/>
</shapetype>
<shape id="_x0000_i1025"type="#_x0000_t75" >
<imagedata id="rId8"title="syh"/>
</shape>
</pict>
</r>
</p>
可以看到图⽚信息包含在<w:pict></w:pict>标签中,因此我们可以通过该标签写信图⽚段落。
document有⼀个part属性,part有⼀个related_parts属性,其定义如下:
@property
def related_parts(self):
"""
Dictionary mapping related parts by rId, so child objects can resolve
explicit relationships present in the part XML, e.g. sldIdLst to a
specific |Slide| instance.
"""
ls.related_parts
再看lated_partsr的定义:
@property
def related_parts(self):
"""
dict mapping rIds to target parts for all the internal relationships
in the collection.
"""
return self._target_parts_by_rId
<shape id="_x0000_i1025"type="#_x0000_t75" >
<imagedata id="rId8"title="syh"/>
</shape>
可以看到,这个图⽚对应rId是rId8,运⾏
lated_parts['rId9']
发现前没有报错,将其存储成图⽚后,惊喜出现了——这就是该图⽚的内容。
整理上⾯的思路,获得图⽚的过程分3步:
1. 获得各段的Proxy Type对象,它是⼀个xml;
2. 遍历该xml,如果pict键存在,该段是图⽚,继续遍历获得rId;
3. 利⽤related_parts获得图⽚内容。
下⾯详述该过程:
1.1 获得各段对应的Proxy Type xml数据
proxy=[]
for p in doc.paragraphs:
proxy.append(p._l)
1.2 遍历xml,到图⽚所在的段落并获得rid
cElementTree as ET
rIds=[]
for p in proxy:
#⼀段⼀个根树
root=ET.fromstring(p)
#获得<w:r>树,所有的<w:pict>树均是<w:r>树的⼦树
pictr_str="{/wordprocessingml/2006/main}r"
pictrs=root.findall(pictr_str)
image_str="*/{urn:schemas-microsoft-com:vml}shape/{urn:schemas-microsoft-com:vml}imagedata"
for pictr in pictrs:
#获得所有<v:imagedata>标签
pict=pictr.findall(image_str)
if len(pict)>0:
rIds.append(pict[0].attrib['{/officeDocument/2006/relationships}id'])
ps:这部分代码需要对照xml才能看懂。
1.3 获得image数据
imgs=[]
for rid in rIds:
imgs.append(lated_parts[rid])
1.4 保存图⽚到本地
i=1
python处理xml文件for img in imgs:
f=open("img%d.jpg"% i,'wb')
f.write(im
g.blob)
f.close()
i+=1
2.给word插⼊图⽚
插⼊图⽚就⽐较简单了:
doc.add_picture('img_path',width=Cm(16),height=Cm(12))
后记:从word中读出图⽚在点复杂,这个代码肯定不能满⾜所有word⽂件,也可能存在很多问题,但是根据这个思路,任何word⽂件的图⽚都可被到,毕竟在官⽅API中并没有提到图⽚如何导出,我只是抛砖引⽟,如果⼤家有更好的⽅法欢迎交流。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论