基于Python開(kāi)發(fā)批量提取Excel圖片的小工具
目前有一個(gè)需求,就是批量讀取當(dāng)前目錄下所有文件夾里的Excel文件,去獲取出Excel文件中的圖片,并根據(jù)圖片對(duì)應(yīng)的行去獲取某列的值作為命名方式進(jìn)行命名,并統(tǒng)一保存在一個(gè)新的文件夾里面。
自己花了幾個(gè)小時(shí)寫(xiě)了一個(gè)小工具出來(lái),利用的是openpyxl這個(gè)庫(kù),其他庫(kù)用了提取效果不太好,這個(gè)提取效果挺不錯(cuò)的。以下代碼要根據(jù)實(shí)際需求,將“貨品編碼”改成你對(duì)應(yīng)需要的值。如果你不需要命名規(guī)則,則直接去掉都行。
第一個(gè)版本,針對(duì)于不規(guī)則分布圖片的Excel,進(jìn)行每個(gè)單元格進(jìn)行遍歷,比較費(fèi)時(shí):
import os from openpyxl import load_workbook from openpyxl.drawing.image import Image from openpyxl_image_loader import SheetImageLoader from openpyxl.utils.cell import get_column_letter from PIL import Image # 創(chuàng)建文件夾 def create_folder(): if not os.path.exists('images'): os.makedirs('images') print("成功創(chuàng)建/更新文件夾!") # 獲取當(dāng)前目錄下的文件夾 def get_folders(directory): folders = [] for entry in os.scandir(directory): if entry.is_dir(): folders.append(entry.name) print("成功獲取當(dāng)前目錄的文件夾!") return folders # 提取圖片 def extract_images(): # 創(chuàng)建存放文件夾 create_folder() # 獲取當(dāng)前目錄下的文件夾 folders = get_folders('.') i = 1 num = 1 # 遍歷當(dāng)前目錄下的文件夾 for folder in folders: print(f"正在遍歷第{i}個(gè)文件夾{folder}......") # 進(jìn)行提取圖片 num = extract_images_from_excel(folder, num) i += 1 # 進(jìn)行提取圖片 def extract_images_from_excel(folder, num): # 遍歷當(dāng)前文件夾內(nèi)的所有文件 for entry in os.scandir('.\\'+folder): # 如果當(dāng)前對(duì)象是文件且后綴是xlsx if entry.is_file() and entry.name.endswith('.xlsx'): print(f'{folder}下的Excel文件路徑為:{entry.path}') # 打開(kāi)當(dāng)前文件 wb = load_workbook(entry.path) # 獲取當(dāng)前xlsx的所有Sheet表 worksheets = wb.worksheets # 遍歷xlsx中每一個(gè)Sheet for ws in worksheets: # 獲取當(dāng)前列名為貨品編碼的列序號(hào) code_index = '' for column in ws.iter_cols(): if column[0].value == "貨品編碼": code_index = column[0].column # 創(chuàng)建圖片加載對(duì)象 image_loader = SheetImageLoader(ws) # 每一行進(jìn)行遍歷,獲取行序號(hào)和該行數(shù)據(jù) for row_index, row in enumerate(ws.rows, start=1): # 每一列進(jìn)行遍歷 for column_index in range(1, len(row) + 1): # 獲取列序號(hào) column_letter = get_column_letter(column_index) # 如果當(dāng)前單元格是圖片 if image_loader.image_in(f'{column_letter}{row_index}'): # 獲取圖片 image = image_loader.get(f'{column_letter}{row_index}') # 獲取圖片格式 image_type = image.format # 獲取當(dāng)前行的貨品編碼列的值 code = ws.cell(row=(row_index), column=code_index).internal_value # 保存圖片(保存命名為 序號(hào)_貨品編碼) print(f'正在提取單元格{column_letter}{row_index + 1}的圖片......') image.save(f"./images/[code]_{num}.{image_type}") # 序號(hào)遞增 num += 1 # 關(guān)閉文件對(duì)象 wb.close() return num if __name__ == '__main__': print("此版本是針對(duì)于圖片分布不規(guī)則的情況,提取圖片速度尚且較慢") print("開(kāi)始提取......") # 提取圖片 extract_images() print("提取完成!")
第二個(gè)版本,針對(duì)于某一列統(tǒng)一分布圖片的Excel,只會(huì)進(jìn)行有圖片那一列的遍歷,比較快速:
import os from openpyxl import load_workbook from openpyxl.drawing.image import Image from openpyxl_image_loader import SheetImageLoader from openpyxl.utils.cell import get_column_letter from PIL import Image # 創(chuàng)建文件夾 def create_folder(): if not os.path.exists('images'): os.makedirs('images') print("成功創(chuàng)建/更新文件夾!") # 獲取當(dāng)前目錄下的文件夾 def get_folders(directory): folders = [] for entry in os.scandir(directory): if entry.is_dir(): folders.append(entry.name) print("成功獲取當(dāng)前目錄的文件夾!") return folders # 提取圖片 def extract_images(): # 創(chuàng)建存放文件夾 create_folder() # 獲取當(dāng)前目錄下的文件夾 folders = get_folders('.') i = 1 num = 1 # 遍歷當(dāng)前目錄下的文件夾 for folder in folders: print(f"正在遍歷第{i}個(gè)文件夾{folder}......") # 進(jìn)行提取圖片 num = extract_images_from_excel(folder, num) i += 1 # 進(jìn)行提取圖片 def extract_images_from_excel(folder, num): # 遍歷當(dāng)前文件夾內(nèi)的所有文件 for entry in os.scandir('.\\'+folder): # 如果當(dāng)前對(duì)象是文件且后綴是xlsx或者xls if entry.is_file() and (entry.name.endswith('.xlsx') or entry.name.endswith('.xls')): print(f'{folder}下的Excel文件路徑為:{entry.path}') # 打開(kāi)當(dāng)前文件 wb = load_workbook(entry.path) # 獲取當(dāng)前xlsx的所有Sheet表 worksheets = wb.worksheets # 遍歷xlsx中每一個(gè)Sheet for ws in worksheets: # 獲取當(dāng)前列名為貨品編碼的列序號(hào) code_index = '' for column in ws.iter_cols(): if column[0].value == "貨品編碼": code_index = column[0].column # 創(chuàng)建圖片加載對(duì)象 image_loader = SheetImageLoader(ws) # 記錄第一次遍歷的標(biāo)志 img_sign_index = '' # 每一行進(jìn)行遍歷,獲取行序號(hào)和該行數(shù)據(jù) for row_index, row in enumerate(ws.rows, start=1): # 只有第一次才會(huì)進(jìn)行每列遍歷,去找到圖片所在的列 if img_sign_index == '': # 每一列進(jìn)行遍歷 for column_index in range(1, len(row) + 1): # 獲取列序號(hào) column_letter = get_column_letter(column_index) if image_loader.image_in(f'{column_letter}{row_index}'): # 獲取對(duì)應(yīng)圖片的列序號(hào) img_sign_index = column_letter break # 如果不為空,則證明有圖片,反之直接跳過(guò) if img_sign_index != '': # 后面遍歷直接去找圖片所在的列 image = image_loader.get(f'{img_sign_index}{row_index}') # 獲取圖片格式 image_type = image.format # 獲取當(dāng)前行的貨品編碼列的值 code = ws.cell(row=(row_index), column=code_index).internal_value # 保存圖片(保存命名為 序號(hào)_貨品編碼) print(f'正在提取單元格{img_sign_index}{row_index + 1}的圖片......') image.save(f"./images/{num}_[code].{image_type}") # 序號(hào)遞增 num += 1 # 關(guān)閉文件對(duì)象 wb.close() return num if __name__ == '__main__': print("此版本是針對(duì)于圖片集中分布在一列的情況,能更快提取圖片出來(lái)") print("開(kāi)始提取......") # 提取圖片 extract_images() print("提取完成!")
第三個(gè)版本更新
此版本不是遍歷單元格,是直接找圖片,再鎖定圖片的中心行位置去找相應(yīng)的貨品編碼,效率更高,而且不會(huì)因?yàn)閳D片位于單元格邊緣存在識(shí)別不到的問(wèn)題。
import os from openpyxl import load_workbook import os from openpyxl_image_loader import SheetImageLoader from openpyxl.utils.cell import get_column_letter # 創(chuàng)建文件夾 def create_folder(): if not os.path.exists('images'): os.makedirs('images') print("成功創(chuàng)建/更新文件夾!") # 獲取當(dāng)前目錄下的文件夾 def get_folders(directory): folders = [] for entry in os.scandir(directory): if entry.is_dir(): folders.append(entry.name) print("成功獲取當(dāng)前目錄的文件夾!") return folders # 提取圖片 def extract_images(): # 創(chuàng)建存放文件夾 create_folder() # 獲取當(dāng)前目錄下的文件夾 folders = get_folders('.') i = 1 num = 1 # 遍歷當(dāng)前目錄下的文件夾 for folder in folders: print(f"正在遍歷第{i}個(gè)文件夾{folder}......") # 進(jìn)行提取圖片 num = extract_images_from_excel(folder, num) i += 1 # 進(jìn)行提取圖片 def extract_images_from_excel(folder, num): # 遍歷當(dāng)前文件夾內(nèi)的所有文件 for entry in os.scandir('.\\'+folder): # 如果當(dāng)前對(duì)象是文件且后綴是xlsx或者xls if entry.is_file() and entry.name.endswith('.xlsx'): print(f'{folder}下的Excel文件路徑為:{entry.path}') # 打開(kāi)當(dāng)前文件 wb = load_workbook(entry.path) # 遍歷每一個(gè)Sheet for sheet_name in wb.sheetnames: sheet = wb[sheet_name] image_loader = SheetImageLoader(sheet) # 獲取當(dāng)前列名為貨品編碼的列序號(hào) code_index = '' for column in sheet.iter_cols(): if column[0].value == "貨品編碼": code_index = column[0].column # 遍歷Sheet中的所有圖片 for image in sheet._images: # 獲取圖片中心行數(shù),判斷貨品編碼是哪一個(gè) row_index = (int(((image.anchor._from.row + 1) + (image.anchor.to.row + 1)) / 2)) # 獲取當(dāng)前行的貨品編碼列的值(取中間值) code = sheet.cell(row=row_index, column=code_index).value # 獲取圖片格式 img_format = image.format # 重新將圖片獲取出來(lái)(因?yàn)楂@取下標(biāo)這個(gè)image沒(méi)有存儲(chǔ)方法),直接通過(guò)定位左上角坐標(biāo)將圖片取出來(lái) img = image_loader.get(f'{get_column_letter(image.anchor._from.col + 1)}{image.anchor._from.row + 1}') # 保存圖片 print(f'正在提取貨品編碼為[code]的圖片{image}......') img.save(f'./images/{num}_[code].{img_format}') # 序號(hào)遞增 num += 1 # 關(guān)閉文件對(duì)象 wb.close() return num # v1.0:此版本是針對(duì)于圖片分布不規(guī)則的情況,提取圖片速度尚且較慢 # v1.1:此版本是針對(duì)于圖片集中分布在一列的情況,能更快提取圖片出來(lái)。 # v1.2:此版本解決圖片位于Excel邊界時(shí)存在的問(wèn)題,只要圖片中心行在這一行,就可以匹配相應(yīng)的國(guó)家編碼,同時(shí)不用去遍歷,直接獲取圖片。 if __name__ == '__main__': print("開(kāi)始提取......") # 提取圖片 extract_images() print("提取完成!")
第四個(gè)版本:增加了圖片的壓縮,不需要壓縮的可以直接不調(diào)用壓縮犯法即可,增加了交互,聽(tīng)取了評(píng)論區(qū)大佬的意見(jiàn),現(xiàn)在可以提取同一單元格多張圖片。
import math from openpyxl import load_workbook import os from PIL import Image # 命名規(guī)則 good_code = "" # 命名字典 name_dict = {} # 圖片數(shù)量 img_num = 0 # 記錄哪些文件夾已經(jīng)被提取過(guò)了 folder_name_dict = {} # 是否輸出提取文本 is_text = True # 創(chuàng)建文件夾 def create_folder(): if not os.path.exists('images'): os.makedirs('images') print("成功創(chuàng)建/更新images文件夾!") # 提取圖片 def extract_images(stop): if stop: return global img_num global good_code folder = input("請(qǐng)輸入需要提取的文件夾名稱(chēng)(不輸入則遍歷當(dāng)前目錄下未提取過(guò)的所有文件夾):") good_code = input("請(qǐng)輸入命名規(guī)則對(duì)應(yīng)表格中的名字(不輸入則默認(rèn)為貨品編碼):") if good_code == "": good_code = "貨品編碼" if folder != '': # 查找指定文件夾 extract_images_from_excel(folder) else: folders = [] for entry in os.scandir('.'): if entry.is_dir(): folders.append(entry.name) i = 1 # 記錄可提取的文件夾的數(shù)量 number = 0 # 遍歷當(dāng)前目錄下的文件夾 for folder in folders: if folder in folder_name_dict: continue print(f"正在遍歷第{i}個(gè)文件夾{folder}......") # 進(jìn)行提取圖片 extract_images_from_excel(folder) number += 1 i += 1 if number == 0: print("沒(méi)有可供提取的文件夾了!") return is_success() img_num = 0 status = input("\n是否繼續(xù)提?。ㄝ斎隮表示是,輸入其他則退出):") if status == "Y" or status == "y": extract_images(False) else: extract_images(True) def is_success(): if img_num == 0: if is_text: print(f'沒(méi)有提取到圖片!') else: print(f'成功提取{img_num}張圖片!') print("圖片提取完成,請(qǐng)到images文件夾中查看!") # 進(jìn)行提取圖片 def extract_images_from_excel(folder): global img_num global is_text is_have_excel = False path = os.path.join('.', folder) if not os.path.exists(path): print(f'{folder}文件夾未找到!') return # 判斷文件夾是否已經(jīng)被提取過(guò)了 if folder not in folder_name_dict: is_text = True else: print(f'{folder}文件夾已經(jīng)被提取過(guò)了!') is_text = False return try: # 遍歷當(dāng)前文件夾內(nèi)的所有文件 for entry in os.scandir(path): # 如果當(dāng)前對(duì)象是文件且后綴是xlsx或者xls if entry.is_file() and entry.name.endswith('.xlsx'): is_have_excel = True print(f'{folder}下的Excel文件路徑為:{entry.path}') # 打開(kāi)當(dāng)前文件 wb = load_workbook(entry.path) # 遍歷每一個(gè)Sheet for sheet_name in wb.sheetnames: sheet = wb[sheet_name] # 獲取當(dāng)前列名為貨品編碼的列序號(hào) code_index = "" for column in sheet.iter_cols(): if column[0].value == good_code: code_index = column[0].column break if code_index == "": print(f'列名{good_code}在{entry.path}的文件中不存在!') break else: folder_name_dict[folder] = True # 遍歷Sheet中的所有圖片 for image in sheet._images: # 獲取圖片中心行數(shù),判斷貨品編碼是哪一個(gè) row_index = (int(((image.anchor._from.row + 1) + (image.anchor.to.row + 1)) / 2)) # 獲取當(dāng)前行的貨品編碼列的值(取中間值) code = "" if code_index != "": code = str(sheet.cell(row=row_index, column=code_index).value) # 獲取圖片格式 img_format = image.format # 這個(gè)if else只是命名規(guī)則,不重要 if code not in name_dict: name_dict[code] = 1 else: name_dict[code] = name_dict[code] + 1 save_path = f"./images/[code]-{name_dict[code]}.{img_format}" # 保存 file = open(save_path, "wb") file.write(image.ref.getvalue()) file.close() # 壓縮圖片 compress_and_save_image(save_path) img_num += 1 break # 關(guān)閉文件對(duì)象 wb.close() except FileNotFoundError: # 處理文件未找到異常 print(f'{folder}文件夾未找到!') extract_images(good_code) except Exception as e: # 處理其他異常 print("提取圖片異常:", e) if not is_have_excel: print(f'{folder}文件夾內(nèi)未找到Excel文件!') folder_name_dict[folder] = True # 壓縮圖片 def compress_and_save_image(image_path): # 打開(kāi)原始圖片 original_image = Image.open(image_path) # 檢查文件大小,并根據(jù)需要進(jìn)行進(jìn)一步壓縮,壓縮到1M if os.path.getsize(image_path) > 1024 * 1024: size = os.path.getsize(image_path) # 壓縮到1mb需要壓縮的比例(百分比) quality = math.floor(((1024 * 1024) / size) * 100) original_image.save(image_path, optimize=True, quality=quality) original_image.close() # v1.0:此版本是針對(duì)于圖片分布不規(guī)則的情況,提取圖片速度尚且較慢 # v1.1:此版本是針對(duì)于圖片集中分布在一列的情況,能更快提取圖片出來(lái)。 # v1.2:此版本解決圖片位于Excel邊界時(shí)存在的問(wèn)題,只要圖片中心行在這一行,就可以匹配相應(yīng)的國(guó)家編碼,同時(shí)不用去遍歷,直接獲取圖片。 # v1.3:此版本是讓用戶(hù)自己輸入指定的文件夾,增加異常交互。 # v1.4:此版本增加了對(duì)1MB以上圖片的壓縮,解決了多圖片在同一單元格的問(wèn)題。 if __name__ == '__main__': print("開(kāi)始提取......") # 創(chuàng)建存放文件夾 create_folder() # 提取圖片 extract_images(False) # 最后加入輸入語(yǔ)句,以阻塞程序的執(zhí)行 input("按下任意鍵以關(guān)閉程序")
以上就是基于Python開(kāi)發(fā)批量提取Excel圖片的小工具的詳細(xì)內(nèi)容,更多關(guān)于Python提取Excel圖片的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
pandas數(shù)據(jù)聚合與分組運(yùn)算的實(shí)現(xiàn)
本文主要介紹了pandas數(shù)據(jù)聚合與分組運(yùn)算的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01基于python不同開(kāi)根號(hào)的速度對(duì)比分析
這篇文章主要介紹了基于python不同開(kāi)根號(hào)的速度對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03Transpose 數(shù)組行列轉(zhuǎn)置的限制方式
今天小編就為大家分享一篇Transpose 數(shù)組行列轉(zhuǎn)置的限制方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02基于Python做一個(gè)簡(jiǎn)單的動(dòng)圖生成器
現(xiàn)在的年輕人都開(kāi)始每天保溫杯里泡枸杞,這怎么能行呢?于是懷揣著愉悅心情的想法,我開(kāi)始制作GIF動(dòng)圖生成器,這個(gè)小工具制作的目的是為了將多張圖片組合后生成一張動(dòng)態(tài)的GIF圖片,感興趣的可以嘗試一下2023-01-01Django中實(shí)現(xiàn)點(diǎn)擊圖片鏈接強(qiáng)制直接下載的方法
這篇文章主要介紹了Django中實(shí)現(xiàn)點(diǎn)擊圖片鏈接強(qiáng)制直接下載的方法,涉及Python操作圖片的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-05-05Python 操作 PostgreSQL 數(shù)據(jù)庫(kù)示例【連接、增刪改查等】
這篇文章主要介紹了Python 操作 PostgreSQL 數(shù)據(jù)庫(kù)的方法,結(jié)合實(shí)例形式分析了Python 連接PostgreSQL及增刪改查等相關(guān)操作技巧,需要的朋友可以參考下2020-04-04