python解析word文档,提取文档中所有的图片并保存,并将原图位置用占位符替换。
问题描述
利用python-dox库解析word文档,并提取里面的所有图片时发现会出现一摸一样的图片只解析一次,导致图片丢失,数量不对的情况。
解决方法
通过例如 lxml 或直接解析 Word 的结构解决 例如,读取每个图片引用的具体关系
- 解析 Word 文档的内容:我们需要读取 document.xml 来找到所有的 <w:drawing> 元素。
- 解析关系文件:在 word/_rels/document.xml.rels 文件中,每张图片都有一个关系定义,你需要读取这个文件来找到图像的实际存储路径。
- 提取和保存图像:最后,从 Word 的 ZIP包里把真正的图像提取出来保存到本地。
代码
import os
from datetime import datetime
from docx import Document
from docx.oxml.ns import qn
import zipfile
import os
from zipfile import ZipFile
from lxml import etreedef extract_images_and_replace(docx_path, output_docx_path, images_dir):# 打开 docx 文件作为 Zipbase_filename=os.path.splitext(os.path.basename(docx_path))[0]with ZipFile(docx_path, 'r') as docx:# 读取 word/document.xml 文件document_xml = docx.read('word/document.xml')root = etree.XML(document_xml)# 读取 word/_rels/document.xml.rels 文件rels_xml = docx.read('word/_rels/document.xml.rels')rels_root = etree.XML(rels_xml)# 查找所有的 <w:drawing> 元素drawing_elements = root.findall('.//{http://schemas.openxmlformats.org/wordprocessingml/2006/main}drawing')# 创建输出目录os.makedirs(images_dir, exist_ok=True)# 查找并保存所有图片image_id=0placelist=[]for i, drawing in enumerate(drawing_elements):# 获取 <a:blip> 的 r:embed 属性blip_element = drawing.find('.//{http://schemas.openxmlformats.org/drawingml/2006/main}blip')if blip_element is not None:embed_attr = blip_element.get('{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed')if embed_attr:# 查找图像在 rels 中的路径relationship = rels_root.find(f".//{{http://schemas.openxmlformats.org/package/2006/relationships}}Relationship[@Id='{embed_attr}']")if relationship is not None:timestamp = datetime.now().timestamp()target = relationship.get('Target')image_path = os.path.join('word', target)placeholder = f"{base_filename}_{timestamp}<unused{image_id}>"placelist.append(placeholder)# 提取并保存图像with docx.open(image_path) as image_file:image_data = image_file.read()image_ext = os.path.splitext(image_path)[1]# 保存图片到指定目录image_filename = os.path.join(images_dir, f"{placeholder}.png")with open(image_filename, 'wb') as out_file:out_file.write(image_data)print(f'Image saved: {image_filename}')image_id+=1print(len(placelist))# 替换文档中对应的图片为占位符i=0# 遍历所有段落及图片doc = Document(docx_path)for paragraph in doc.paragraphs:for run in paragraph.runs:# try:if 'graphicData' in run._element.xml: # 搜索图片标记# 删除图片并插入占位符文字inline = run._element.xpath('.//a:graphic')[0]inline.getparent().remove(inline)run.text = placelist[i]i+=1# except:# break# 保存修改后的 Word 文档doc.save(output_docx_path)print(f"提取了 {image_id} 张图片并用占位符替换。")print(f"图片保存在:{images_dir}")print(f"修改后的 Word 文件保存在:{output_docx_path}")# 示例调用
docx_path = "/data/xxxxx/ZHX财务管理系统.docx" # 输入的 Word 文档
output_docx_path = "/data/xxxxx/ZHX财务管理系统--.docx" # 替换图片后保存的 Word 文档
images_dir = "/data/xxxxx/样例图集/" # 提取图片保存的目录
extract_images_and_replace(docx_path, output_docx_path, images_dir)