本文主要是介绍基于Python开发批量提取Excel图片的小工具,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《基于Python开发批量提取Excel图片的小工具》这篇文章主要为大家详细介绍了如何使用Python中的openpyxl库开发一个小工具,可以实现批量提取Excel图片,有需要的小伙伴可以参考一下...
目前有一个需求,就是批量读取当前目录下所有文件夹里的Excel文件,去获取出Excel文件中的图片,并根据图片对应的行去获取某列的值作为命名方式进行命名,并统一保存在一个新的文件夹里面。
自己花了几个小时写了一个小工具出来,利用的是openpyxl这个库,其他库用了提取效果不太好,这个提取效果挺不错的。以下代码要根据实际需求,将“货品编码”改成你对应需要的值。如果你不需要命名规则,则直接去掉都行。
第一个版本,针对于不规则分布图片的Excel,进行每个单元格进行遍历,比较费时:
import os from openpyxl import load_workbook from openpyxl.drawing.image import Image from openpyxl_image_loader impophprt SheetImageLoader from openpyxl.utils.cell import get_column_letter from PIL import Image # 创建文件夹 def create_folder(): if not os.path.exists('images'): os.makedirs('images') print("成功创建/更新文件夹!") # 获取当前目录下的文件夹 def get_folders(directory): folders = [] for entry in os.scandir(directory): if entry.is_dir(): folders.append(entry.name) print("成功获取当前目录的文件夹!") return folders # 提取图片 def extract_images(): # 创建存放文件夹 create_folder() # 获取当前www.chinasem.cn目录下的文件夹 folders = get_folders('.') i = 1 num = 1 # 遍历当前目录下的文件夹 for folder in folders: print(f"正在遍历第{i}个文件夹{folder}......") # 进行提取图片 num = extract_images_from_excel(folder, num) i += 1 # 进行提取图片 def extract_images_from_excel(folder, num): # 遍历当前文件夹内的所有文件 for entry in os.scandir('.\\'+folder): # 如果当前对象是文件且后缀是xlsx if entry.is_file() and entry.name.endswith('.xlsx'): print(f'{folder}下的Excel文件路径为:{entry.path}') # 打开当前文件 wb = load_workbook(entry.path) # 获取当前xlsx的所有Sheet表 worksheets = wb.worksheets # 遍历xlsx中每一个Sheet for ws in worksheets: # 获取当前列名为货品编码的列序号 code_index = '' for column in ws.iter_cols(): if column[0].value == "货品编码": code_index = column[0].column # 创建图片加载对象 image_loader = SheetImageLoader(ws) # 每一行进行遍历,获取行序号和该行数据 for row_index, row in enumerate(ws.rows, start=1): # 每一列进行遍历 for column_index in range(1, len(row) + 1): # 获取列序号 column_letter = get_column_letter(column_index) # 如果当前单元格是图片 if image_loader.image_in(f'{column_letter}{row_index}'): # 获取图片 image = image_loader.get(f'{column_letter}{row_index}') # 获取图片格式 image_type = image.format # 获取当前行的货品编码列的值 code = ws.cell(row=(row_index), column=code_index).internal_value # 保存图片(保存命名为 序号_货品编码) print(f'正在提取单元格{column_letter}{row_index + 1}的图片......') image.save(f"./images/[code]_{num}.{image_type}") # 序号递增 num += 1 # 关闭文件对象 wb.close() return num if __name__ == '__main__': print("此版本是针对于图片分布不规则的情况,提取图片速度尚且较慢") print("开始提取......") # 提取图片 extract_images() print("提取完成!")
第二个版本,针对于某一列统一分布图片的Excel,只会进行有图片那一列的遍历,比较快速:
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 # 创建文件夹 def create_folder(): if not os.path.exists('images'): os.makedirs('images') print("成功创建/更新文件夹!") # 获取当前目录下的文件夹 def get_folders(directory): folders = [] for entry in os.scandir(directory): if entry.is_dir(): folders.append(entry.name) print("成功获取当前目录的文件夹!") return folders # 提取图片 def extract_images(): # 创建存放文件夹 create_folder() # 获取当前目录下的文件夹 folders = get_folders('.') i = 1 num = 1 # 遍历当前目录下的文件夹 for folder in folders: print(f"正在遍历第{i}个文件夹{folder}......") # 进行提取图片 num = extract_images_from_excel(folder, num) i += 1 # 进行提取图片 def extract_images_from_excel(folder, num): # 遍历当前文件夹内的所有文件 for entry in os.scandir('.\\'+folder): # 如果当前对象是文件且后缀是xlsx或者xls if entry.is_file() and (entry.name.endswith('.xlsx') or entry.name.endswith('.xls')): print(f'{folder}下的Excel文件路径为:{entry.path}') # 打开当前文件 wb = load_workbook(entry.path) # 获取当前xlsx的所有Sheet表 worksheets = wb.worksheets # 遍历xlsx中每一个Sheet for ws in worksheets: # 获取当前列名为货品编码的列序号 code_index = '' for column in ws.iter_cols(): if column[0].value == "货品编码": code_index = column[0].column # 创建图片加载对象 image_loader = SheetImageLoader(ws) # 记录第一次遍历的标志 img_sign_index = '' # 每一行进行遍历,获取行序号和该行数据 for row_index, row in enumerate(ws.rows, start=1): # 只有第一次才会进行每列遍历,去找到图片所在的列 if img_sign_index == '': # 每一列进行遍历 for column_index in range(1, len(row) + 1): # 获取列序号 column_letter = get_column_letter(column_index) if image_loader.image_in(f'{column_letter}{row_index}'): # 获取对应图片的列序号 img_sign_index = column_letter break # 如果不为空,则证明有图片,反之直接跳过 if img_sign_index != '': # 后面遍历直接去找图片所在的列 image = image_loader.get(f'{img_sign_index}{row_index}') # 获取图片格式 image_type = image.format # 获取当前行的货品编码列的值 code = ws.cell(row=(row_index), column=code_index).internal_value # 保存图片(保存命名为 序号_货品编码) print(f'正在提取单元格{img_sign_index}{row_index + 1}的图片......') image.save(f"./images/{num}_[code].{image_type}") # 序号递增 num += 1 # 关闭文件对象 wb.close() return num if __name__ == '__main__': print("此版本是针对于图片集中分布在一列的情况,能更快提取图片出来") print("开始提取......") # 提取图片 extract_images() print("提取完成!")
第三个版本更新
此版本不是遍历单元格,是直接找图片,再锁定图片的中心行位置去找相应的货品编码,效率更高,而且不会因为图片位于单元格边缘存在识别不到的问题。
import os from openpyxl import load_workbook import os from openpyxl_image_loader import SheetImageLoader from openpyxl.utils.cell import get_column_letter # 创建文件夹 def create_folder(): if not os.path.exists('images'): os.makedirs('images') print("成功创建/更新文件夹!") # 获取当前目录下的文件夹 def get_folders(directory): folders = [] for entry in os.scandir(directory): if entry.is_dir(): folders.append(entry.name) print("成功获取当前目录的文件夹!") return folders # 提取图片 def extract_images(): # 创建存放文件夹 create_folder() # 获取当前目录下的文件夹 folders = get_folders('.') i = 1 num = 1 # 遍历当前目录下的文件夹 for folder in folders: print(f"正在遍历第{i}个文件夹{folder}......") # 进行提取图片 num = extract_images_from_excel(folder, num) i += 1 # 进行提取图片 def extract_images_from_excel(folder, num): # 遍历当前文件夹内的所有文件 for entry in os.scandir('.\\'+folder): javascript # 如果当前对象是文件且后缀是xlsx或者xls if entry.is_file() and entry.name.endswith('.xlsx'): print(f'{folder}下的Excel文件路径为:{entry.path}') # 打开当前文件 wb = load_workbook(entry.path) # 遍历每一个Sheet for sheet_name in wb.sheetnames: sheet = wb[sheet_name] image_loader = SheetImageLoader(sheet) # 获取当前列名为货品编码的列序号 code_index = '' for column in sheet.iter_cols(): if column[0].value == "货品编码": code_index = column[0].column # 遍历Sheet中的所有图片 for image in sheet._images: # 获取图片中心行数,判断货品编码是哪一个 row_index = (int(((image.anchor._from.row + 1) + (image.anchor.to.row + 1)) / 2)) # 获取当前行的货品编码列的值(取中间值) code = sheet.cell(row=row_index, column=code_index).value # 获取图片格式 img_format = image.format # 重新将图片获取出来(因为获取下标这个image没有存储方法),直接通过定位左上角坐标将图片取出来 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}') # 序号递增 num += 1 # 关闭文件对象 wb.close() return num # v1.0:此版本是针对于图片分布不规则的情况,提取图片速度尚且较慢 # v1.1:此版本是针对于图片集中分布在一列的情况,能更快提取图片出来。 # v1.2:此版本解决图片位于Excel边界时存在的问题,只要图片中心行在这一行,就可以匹配相应的国家编码,同时不用去遍历,直接获取图片。 if __name__ == '__main__': print("开始提取......") # 提取图片 extract_images() print("提取完成!")
第四个版本:增加了图片的压缩,不需要压缩的可以直接不调用压缩犯法即可,增加了交互,听取了评论区大佬的意见,现在可以提取同一单元格多张图片。
import math from openpyxl import load_workbook import os from PIL import Image # 命名规则 good_code = "" # 命名字典 name_dict = {} # 图片数量 img_num = 0 # 记录哪些文件夹已经被提取过了 folder_name_dict = {} # 是否输出提取文本 is_text = True # 创建文件夹 def create_folder(): if not os.path.exists('images'): os.makedirs('images') print("成功创建/更新images文件夹!") # 提取图片 def extract_images(stop): if stop: return global img_num global good_code folder = input("请输入需要提取的文件夹名称(不输入则遍历当前目录下未提取过的所有文件夹):") good_code = input("请输入命名规则对应表格中的名字(不输入则默认为货品编码):") 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 # 记录可提取的文件夹的数量 number = 0 # 遍历当前目录下的文件夹 for folder in folders: if folder in folder_name_dict: continue print(f"正在遍历第{i}个文件夹{folder}......") # 进行提取图片 extract_images_from_excel(folder) number += 1 i += 1 if number == 0: print("没有可供提取的文件夹了!") return is_success() img_num = 0 status = input("\n是否继续提取(输入Y表示是,输入其他则退出):") 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'没有提取到图片!') else: print(f'成功提取{img_num}张图片!') print("图片提取完成,请到images文件夹中查看!") # 进行提取图片 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 # 判断文件夹是否已经被提取过了 if folder not in folder_name_dict: is_text = True else: print(f'{folder}文件夹已经被提取过了!') is_text = False return try: # 遍历当前文件夹内的所有文件 for entry in os.scandir(path): # 如果当前对象是文件且后缀是xlsx或者xls if entry.is_file() and entry.name.endswith('.xlsx'): is_have_excel = True print(f'{folder}下的Excel文件路径为:{entry.path}') # 打开当前文件 wb = load_workbook(entry.path) # 遍历每一个Sheet for sheet_name in wb.sheetnames: sheet = wb[sheet_name] # 获取当前列名为货品编码的列序号 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: # 获取图片中心行数,判断货品编码是哪一个 row_index = (int(((image.anchor._from.row + 1) + (image.anchor.to.row + 1)) / 2)) # 获取当前行的货品编码列的值(取中间值) code = "" if code_index != "": code = str(sheet.cell(row=row_index, column=code_index).value) # 获取图片格式 img_format = image.format # 这个if else只是命名规则,不重要 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}" China编程 # 保存 file = open(save_path, "wb") file.write(image.ref.getvalue()) file.close() # 压缩图片 compress_and_save_image(save_path) img_num += 1 break # 关闭文件对象 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}文件夹内未找到Excel文件!') folder_name_dict[folder] = True # 压缩图片 def compress_and_save_image(image_path): # 打开原始图片 original_image = Image.open(image_path) # 检查文件大小,并根据需要进行进一步压缩,压缩到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:此版本是针对于图片分布不规则的情况,提取图片速度尚且较慢 # v1.1:此版本是针对于图片集中分布在一列的情况,能更快提取图片出来。 # v1.2:此版本解决图片位于Excel边界时存在的问题,只要图片中心行在这一行,就可以匹配相应的国家编码,同时不用去遍历,直接获取图片。 # v1.3:此版本是让用户自己输入指定的文件夹,增加异常交互。 # v1.4:此版本增加了对1MB以上图片的压缩,解决了多图片在同一单元格的问题。 if __name__ == '__main__': print("开始提取......") # 创建存放文件夹 create_folder() # 提取图片 extract_images(False) # 最后加入输入语句,以阻塞程序的执行 input("按下任意键以关闭程序")
以上就是php基于python开发批量提取Excel图片的小工具的详细内容,更多关于Python提取Excel图片的资料请关注编程China编程(www.chinasem.cn)其它相关文章!
这篇关于基于Python开发批量提取Excel图片的小工具的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!