You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何提取.docx文件中出现2次及以上的重复图片?

这个需求确实有点 tricky,毕竟默认的工具都是帮你自动去重,而你要的反而是留下那些出现至少两次的图片。我刚好有个可行的方案,用 Python 结合 python-docxzipfile 就能实现,下面一步步给你讲清楚:

核心思路

DOCX 文件本质是个压缩包,里面的图片都存在 word/media/ 目录下,每个图片会通过一个唯一的关系 ID(rId)和文档内容关联。我们需要:

  1. 遍历文档内容,统计每个 rId 对应的图片被引用的次数
  2. 筛选出引用次数 ≥2 的 rId,然后从压缩包中提取对应的图片文件

具体实现代码

首先安装依赖库:

pip install python-docx

然后运行下面的脚本:

import docx
import zipfile
import os
import shutil
import xml.etree.ElementTree as ET

def extract_duplicate_images(docx_path, output_folder):
    # 创建输出文件夹(不存在则自动创建)
    os.makedirs(output_folder, exist_ok=True)
    
    # 第一步:统计每个图片的引用次数
    doc = docx.Document(docx_path)
    image_reference_counts = {}
    
    # 遍历所有段落中的图片
    for paragraph in doc.paragraphs:
        for run in paragraph.runs:
            # 通过 XPath 定位图片元素
            pic_elements = run._element.xpath('.//pic:pic')
            if pic_elements:
                # 获取图片对应的关系 ID(rId)
                r_id = run._element.xpath('.//a:blip/@r:embed')[0]
                # 更新计数
                image_reference_counts[r_id] = image_reference_counts.get(r_id, 0) + 1
    
    # 筛选出引用次数≥2的图片rId
    duplicate_image_rids = [rid for rid, count in image_reference_counts.items() if count >= 2]
    if not duplicate_image_rids:
        print("文档中没有找到重复出现的图片")
        return
    
    # 第二步:从DOCX压缩包中提取目标图片
    with zipfile.ZipFile(docx_path, 'r') as zip_ref:
        # 读取关系映射文件,关联rId和实际图片路径
        rels_content = zip_ref.read('word/_rels/document.xml.rels').decode('utf-8')
        ns = {'r': 'http://schemas.openxmlformats.org/package/2006/relationships'}
        root = ET.fromstring(rels_content)
        
        rid_to_media_path = {}
        for rel in root.findall('r:Relationship', ns):
            rel_id = rel.get('Id')
            target_path = rel.get('Target')
            if target_path.startswith('media/'):
                rid_to_media_path[rel_id] = f'word/{target_path}'
        
        # 复制符合条件的图片到输出文件夹
        for rid in duplicate_image_rids:
            media_path = rid_to_media_path.get(rid)
            if media_path and media_path in zip_ref.namelist():
                filename = os.path.basename(media_path)
                # 提取并保存图片
                with zip_ref.open(media_path) as source_file, open(os.path.join(output_folder, filename), 'wb') as dest_file:
                    shutil.copyfileobj(source_file, dest_file)
                print(f"已提取重复图片:{filename}")

# 调用函数,替换成你的文件路径和输出文件夹
extract_duplicate_images(
    r"C:\Users\name\Documents\document_with_image.docx",
    r"C:\Users\name\Documents\duplicate_images"
)

代码说明

  1. 统计引用次数:通过 python-docx 遍历文档的段落和运行块,用 XPath 定位图片元素,获取对应的 rId 并计数
  2. 关联rId与图片路径:DOCX 的 word/_rels/document.xml.rels 文件存储了 rId 和实际媒体文件的映射关系,我们解析这个文件来找到每个 rId 对应的图片位置
  3. 提取目标图片:从压缩包中读取符合条件的图片文件,复制到指定输出文件夹

补充说明

如果你的文档里有图片在文本框、表格单元格等特殊容器中,上面的代码可能无法完全覆盖,这时候可以额外遍历文档中的形状元素(doc.inline_shapesdoc.shapes)来补充统计,不过大部分常规场景下,上面的代码已经够用了。

内容的提问来源于stack exchange,提问作者sush

火山引擎 最新活动