直接提取图片的方法有很多,但是要同时获取题注信息就比较复杂。本文提取题注基本思路:遍历全部段落,选取图片特征信息,计数并获取下方段号,提取其文本作为题注信息。段落是自然形成的,并无id属性,所以需要遍历获取。
使用python-docx提取文档中的元素,需要熟悉文档内部的文件结构。
一、docx文档内部结构
我们常用的Office Word格式分为doc和docx两种格式,doc是Word 97-2003版本使用的格式,Word2007及其之后的版本,默认格式是docx。
doc使用的是office 97-03的存储规范:OLE。它是一种对象链接和嵌入的技术,该技术可以包含文本,图形,电子表格甚至其他二进制数据。
docx使用OpenXML(OOXML)协议,它是微软在Office 2007中提出的一种新的文档格式,Office 2007及其以后的Word、Excel、PowerPoint默认均采用OpenXML格式。
我们后面讨论的都只针对docx格式的文件,doc文件的解析有另外一套规范。doc文件可以转换为docx。所以就不再讨论doc文件如何解析。
将文件格式docx改为rar,用解压软件打开:
大致文件结构如下:
document.xml文件包含了大部分与文档内容有关的信息,因此可以重点研究它。
二、分析document.xml中图片信息
将demo.dcox,改名为demo.rar解压找到word目录下的document.xml并用浏览器打开。文档中已知有三张插图,搜索image关键字,发现有三个搜索结果。
对比查看document.xml和paragraph子对象_element的xml属性值发现,标签包裹的内容基本一致,w:p标记应是段落标记。
三、有效的代码
import docx
import os, re
word_path="demo.docx"
result_path=os.getcwd()
doc = docx.Document(word_path)
images=[]
pCount=0
for pin doc.paragraphs:
pCount +=1
if "imagedata" in p._element.xml:
#注意!不同的计算机,又有不一样的情况了:原来是检索“imagedata”,现在在这个电脑检索就不对了。
#试了一下,并非word和金山的原因。
rID= re.findall("v:imagedata r:id=\"(.*?)\"", p._element.xml)[0]
p.part.rels[rID].target_ref
pNam=doc.paragraphs[pCount].text
part=doc.part.related_parts[rID]
#paragraph中的part.rels[rID]应当也可以使用
images.append([pNam,part])#此处应注意方法别少了(),有的错误并没有被爆出,是因为[]干扰了()的语法识别。
#把下一段的内容作为题注传入images
for imagein images:
with open(word_path+image[0]+image[1].filename,'wb')as fp :
fp.write(image[1].blob)
四、出现的问题
最初在一台计算机上观察xml属性上有"v:imagedata r:id="
通过代码rID= re.findall("v:imagedata r:id=\"(.*?)\"", p._element.xml)[0]即可提取图片的地址。
但是在另一台计算机上进行提取操作时,却发现其xml属性并不包含此关键信息。似乎document.xml内的结构出现一些区别。此时要查找<pic:pic>仅能找到其中两张图片,另一张swf格式图片不能被找到。
五、存在的问题,待解决后再更新。
两个计算机使用word版本区别:前者使用Office专业增强版2016,版本:2311;后者使用Office Mondo 2016,版本:2310。对同一个文件保存后再修改原文件结构没变化,表明这与word的版本无关。
前者无“pic:pic”,而“imagedata”与内嵌图片所在段落位置对应。
后者"imagedata"与内嵌图片无关,且大量存在“pic:pic”。