學生試卷中的題目有要提交截圖的,也有要提交檔案的,為了方便學生考試,允許單獨交或者嵌入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′óêy?Y à??üáé\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.uj5u.com/houduan/492476.html
標籤:其他
上一篇:Lambda入門--一篇就夠了
下一篇:java內部類的簡介說明
