基于Python开发批量提取Excel图片的小工具

2025-03-20 01:50

本文主要是介绍基于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图片的小工具的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153838

相关文章

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

利用Python打造一个Excel记账模板

《利用Python打造一个Excel记账模板》这篇文章主要为大家详细介绍了如何使用Python打造一个超实用的Excel记账模板,可以帮助大家高效管理财务,迈向财富自由之路,感兴趣的小伙伴快跟随小编一... 目录设置预算百分比超支标红预警记账模板功能介绍基础记账预算管理可视化分析摸鱼时间理财法碎片时间利用财

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

python处理带有时区的日期和时间数据

《python处理带有时区的日期和时间数据》这篇文章主要为大家详细介绍了如何在Python中使用pytz库处理时区信息,包括获取当前UTC时间,转换为特定时区等,有需要的小伙伴可以参考一下... 目录时区基本信息python datetime使用timezonepandas处理时区数据知识延展时区基本信息

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

Java中的工具类命名方法

《Java中的工具类命名方法》:本文主要介绍Java中的工具类究竟如何命名,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java中的工具类究竟如何命名?先来几个例子几种命名方式的比较到底如何命名 ?总结Java中的工具类究竟如何命名?先来几个例子JD

利用python实现对excel文件进行加密

《利用python实现对excel文件进行加密》由于文件内容的私密性,需要对Excel文件进行加密,保护文件以免给第三方看到,本文将以Python语言为例,和大家讲讲如何对Excel文件进行加密,感兴... 目录前言方法一:使用pywin32库(仅限Windows)方法二:使用msoffcrypto-too

SpringBoot整合mybatisPlus实现批量插入并获取ID详解

《SpringBoot整合mybatisPlus实现批量插入并获取ID详解》这篇文章主要为大家详细介绍了SpringBoot如何整合mybatisPlus实现批量插入并获取ID,文中的示例代码讲解详细... 目录【1】saveBATch(一万条数据总耗时:2478ms)【2】集合方式foreach(一万条数