百木园-与人分享,
就是让自己快乐。

Python批量导出word文档中的图片、嵌入式文件

学生试卷中的题目有要提交截图的,也有要提交文件的,为了方便学生考试,允许单独交或者嵌入Word中提交,那么事后如何整理学生的答案?单独提交的比较方便,直接扫描文件名匹配名字后放入指定文件夹即可。但是嵌入到Word中的图片和文件怎么提取出来呢?

现有如下需求:提取出一个Word文档中所有的图片(png、jpg)和嵌入的文件(任意格式)放入到指定的文件夹。

解决

docx是一个压缩包,解压缩后图片一般都放在文档名.docx\\word\\media\\目录下:

 

 

而嵌入式文件一般都放在文档名.docx\\word\\embeddings\\目录下:

 

 

经过询问度娘,发现提取图片比较简单,直接使用docx库中的Document.part.rels{k:v.target_ref}找到文件的相对路径,用Document.part.rels{k:v.target_part.blob}读出文件内容。简单判断一下路径和文件后缀是不是我们需要的media下的png文件和embeddings下的bin文件,是的话写入到新文件中即可:

提取图片

安装python-docx库

pip install python-docx

提取

import os

from docx import Document  # pip install python-docx

is_debug = True

if __name__ == \'__main__\':
    # 需要导出的Word文档路径
    # Python学习交流群 279199867
    target_file = r\'paper\\HBase试题.docx\'
    # 导出文件所在目录
    output_dir = r\'paper\\output\'

    # 加载Word文档
    doc = Document(target_file)
    # 遍历Word包中的所有文件
    dict_rel = doc.part.rels
    # r_id:文件身份码,rel:文件对象 
    for r_id, rel in dict_rel.items():
        if not ( # 如果文件不是在media或者embeddings中的,直接跳过
                str(rel.target_ref).startswith(\'media\')
                or str(rel.target_ref).startswith(\'embeddings\')
        ):
            continue
        
        # 如果文件不是我们想要的后缀,也直接跳过
        file_suffix = str(rel.target_ref).split(\'.\')[-1:][0]
        if file_suffix.lower() not in [\'png\', \'jpg\', \'bin\']:
            continue

        # 如果输出目录不存在,创建
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
        
        # 构建导出文件的名字和路径
        file_name = r_id + \'_\' + str(rel.target_ref).replace(\'/\', \'_\')
        file_path = os.path.join(output_dir,file_name)
        
        # 将二进制数据写入到新位置的文件中
        with open(file_path, \"wb\") as f:
            f.write(rel.target_part.blob)
        
        # 打印结果
        if is_debug:
            print(\'导出文件成功:\', file_name)

 

 

运行结果:

 

 

可以看到,图片都能正常导出,但是学生嵌入的JAVA文件并没有导出,或者说导出的是bin文件,没有完全导出。

提取嵌入式文件

再次询问度娘发现,这种其实也是zip压缩包,但是不能直接提取出,它有个更专业的名字,叫ole文件,我们之前的doc、xls、ppt等没有带x的上古文档文件都是这种格式。那如何提取出文件呢?度娘告诉我有个叫oletools的项目可以,于是下载下来浅浅地分析了下,发现确实可以!

oletools项目地址:https://github.com/decalage2/oletools

或者gitee上别人转存的地址:https://gitee.com/yunqimg/oletools

我是用的gitee上的版本,因为github打不开 QwQ

经相关文档介绍,项目下的oletools-master\\oletools\\oleobj.py就可以提取这种bin后缀的ole文件,简单试一下,在oleobj.py所在目录下打开命令行,把刚刚提取出的rId12_embeddings_oleObject1.bin文件复制到oleobj.py所在目录,执行如下命令:

注意: 在此之前我执行了一下安装oletools的命令,如果不安装可能会出错:pip install oletools,或者说oleobj.py依赖olefile:pip install olefile,在安装oletools时顺便安装了olefile。

python oleobj.py rId12_embeddings_oleObject1.bin

成功导出

Microsoft Windows [版本 10.0.22000.708]
(c) Microsoft Corporation。保留所有权利。

D:\\Minuy\\Downloads\\oletools-master\\oletools-master\\oletools>python oleobj.py rId12_embeddings_oleObject1.bin
oleobj 0.56 - http://decalage.info/oletools
THIS IS WORK IN PROGRESS - Check updates regularly!
Please report any issue at https://github.com/decalage2/oletools/issues

-------------------------------------------------------------------------------
File: \'rId12_embeddings_oleObject1.bin\'
extract file embedded in OLE object from stream \'\\x01Ole10Native\':
Parsing OLE Package
Filename = \"Boos.java\"
Source path = \"D:\\111\\´ó20´óÊý¾Ý Àî¾üÁé\\Boos.java\"
Temp path = \"C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\Boos.java\"
saving to file rId12_embeddings_oleObject1.bin_Boos.java

D:\\Minuy\\Downloads\\oletools-master\\oletools-master\\oletools>

 

导出的文件也能正常访问:

 

 

 

于是把oletools目录复制到工程项目下,稍微修改一下oleobj.py能让我的代码调用它,在oleobj.py中添加如下代码:

def export_main(ole_files, output_dir, log_leve=DEFAULT_LOG_LEVEL):
    ensure_stdout_handles_unicode()

    logging.basicConfig(level=LOG_LEVELS[log_leve], stream=sys.stdout,
                        format=\'%(levelname)-8s %(message)s\')
    # 启用日志模块
    log.setLevel(logging.NOTSET)

    any_err_stream = False
    any_err_dumping = False
    any_did_dump = False

    for container, filename, data \\
            in xglob.iter_files(ole_files,
                                recursive=False,
                                zip_password=None,
                                zip_fname=\'*\'):

        if container and filename.endswith(\'/\'):
            continue
        
        # 输出文件夹
        err_stream, err_dumping, did_dump = \\
            process_file(filename, data, output_dir)

        any_err_stream |= err_stream
        any_err_dumping |= err_dumping
        any_did_dump |= did_dump

    return_val = RETURN_NO_DUMP
    if any_did_dump:
        return_val += RETURN_DID_DUMP
    if any_err_stream:
        return_val += RETURN_ERR_STREAM
    if any_err_dumping:
        return_val += RETURN_ERR_DUMP
    return return_val


def export_ole_file(ole_files, output_dir, debug=False):
    debug_leve = \'critical\'
    if debug:
        debug_leve = \'info\'
        
    # 导出
    result = export_main(
        ole_files,
        output_dir,
        debug_leve
    )

    if result and debug:
        print(\'导出ole文件出错\', ole_files)

 

在提取文件的代码后面加上如下调用:

if str(rel.target_ref).startswith(\'embeddings\'):
  # 解压嵌入式文件
  export_ole_file([file_path], output_dir)

再次运行

 

 

 

成功导出嵌入到Word中的文件!

成功解决问题~


来源:https://www.cnblogs.com/hahaa/p/16388592.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » Python批量导出word文档中的图片、嵌入式文件

相关推荐

  • 暂无文章