工作上常用到给表格中插入图片, 特别是比较多的时候, 很麻烦, 于是尝试用python解决这个问题.

以下是我自己尝试出来经常在用的, 这里做个记录备份.

** 自动插入的图片的名称中需含有表格中某列的值, 作为关健字, 以便进行自动匹配

比如: 图片名为: AABBCC.jpg, 则exce表格某行中某单元格中的值为AAB则可以匹配

0、表格列号的转化

因为Excel表格的列是A,B,....Z,AA,AB,...., 不是很方便, 比如: A是第1列, Z是第26列, AA是27列等, 为了方便这个做成函数, 比如, 第4列, 刚输出 D

def gcl(number):  #get a excel header's letter
    # 此函数用于通过一个数字来获取 excel 表头列的字母代码
    # 比如:第1列返回 A,第27列返回AA。以此类推
    import string
    # a = b * c + d  =>  b = a / c
    # a 为被除数,b 为除数,c 为商,d 为余数

    letter = list(string.ascii_uppercase)  # 26个大写英文字母
    num = range(1, 27, 1)
    dic = dict(zip(num, letter))  #生成字典

    if int(number) > 26:
        b = int(number) // 26  #取商
        d = int(number) % 26  #取余
        col_letter = dic[b] + dic[d]
    else:
        col_letter = dic[number]

    return col_letter

1、第一次做的插入图片

第一次做的这个逻辑不好, 很慢, 用了一次就放弃了. 留个念.

'Awork/00-sanho pictrue library/00-文件插入图片专用新图片/' 因为我的图片都统一放在这里, 所以在函数中默认了这个位置, 实际使用是正常给 pic_file 赋值就可以了

def add_pic_to_excel0(f_file,file_book,sht_name,col_pic_name,col_pic_insert,row_start):
    # 这个是第一个版本的,可运行,但是执行的速度很慢2022-9-2
    # 向excle 添加图片
    # f_file 表格地址
    # file_book 工作薄名称
    # sht_name 工作表名称
    # col_pic_name 插入的图片名称列,数字或字母
    # col_pic_insert 图片插入列,数字或字母
    # row_start 插入图片的起始行
    import openpyxl

    f_file_book = f_file + file_book
    f_file_book_r  = f_file + '图片版' + file_book
    
    wb=openpyxl.load_workbook(f_file_book)
    ws=wb[sht_name]
    
    # 最大行
    row_max = ws.max_row +1
    
    col_pic_name_m = str(col_pic_name)
    col_pic_insert_m = str(col_pic_insert)
    
    # 以下对 col_pic_name 插入的图片名称列,数字或字母,最终使col_pic_name_r为字母
    # .isalpha()是内置的一个字符串方法,用于检查给定的字符串是否只包含字母。
    if col_pic_name_m.isalpha():
        col_pic_name_r = col_pic_name
    elif col_pic_name_m.isdigit():
        # 如果是数字,调用函数转为字母
        col_pic_name_r = gcl(col_pic_name)
    
    # 以下对 col_pic_insert 插入的图片名称列,数字或字母,最终使col_pic_name_r为字母
    if col_pic_insert_m.isalpha():
        col_pic_insert_r = col_pic_insert
    elif col_pic_insert_m.isdigit():
        # 如果是数字,调用函数转为字母
        col_pic_insert_r = gcl(col_pic_insert)
    # 设置列宽
    ws.column_dimensions[col_pic_insert_r].width = 15
        
    for i in range(row_start,row_max):
        # 设置行高
        ws.row_dimensions[i].height=80
        
        # 图片名称
        pic_name = ws[col_pic_name_r + str(i)].value
        
        # 调用函数获取图片路径
        a = os_file_dir()
        # 将图片路径转为字典
        dict_name = dict(zip(a[1],a[0]))

        i_count = 0
        for j in dict_name.keys():
            if str(pic_name) in j:
                pic_dir = dict_name[j]
                cell = col_pic_insert_r + str(i)
                
                # 获取图片地址
                img=openpyxl.drawing.image.Image(pic_dir)

                # 设置图片的宽度
                img.width  = 114
                img.height = 101

                # 在单元格中添加img图像
                ws.add_image(img,cell)
                
                # 图片插入后将工作薄并保存
                wb.save(f_file_book_r)  
                # 加一个输出,查看程序运行情况
                print(str(pic_name) + '插入成功')
                
                i_count += 1
        
        if i_count == 0:
            # 将插入的结果打印出来
            print(str(pic_name) + ' 奇怪了,居然真的没有插入成功')
            continue
            
    wb.close()

2、第2次做的插入图片

优化后的这个很快, 几秒钟搞定

def add_pic_to_excel(f_file,file_book,sht_name_li,col_pic_name,col_pic_insert,row_start,pic_file='Awork/00-sanho pictrue library/00-文件插入图片专用新图片/'):
    # 向excle 添加图片,这个快
    # f_file 表格地址
    # file_book 工作薄名称
    # sht_name 工作表名称
    # col_pic_name 插入的图片名称列,数字或字母
    # col_pic_insert 图片插入列,数字或字母
    # row_start 插入图片的起始行
    import openpyxl

    f_file_book = f_file + file_book
    f_file_book_r  = f_file + '图片版' + file_book
    
    # 初始化几个参数    
    col_pic_name_m = str(col_pic_name)
    col_pic_insert_m = str(col_pic_insert)
    
    # 以下对 col_pic_name 插入的图片名称列,数字或字母,最终使col_pic_name_r为字母
    if col_pic_name_m.isalpha():
        col_pic_name_r = col_pic_name
    elif col_pic_name_m.isdigit():
        # 如果是数字,调用函数转为字母
        col_pic_name_r = gcl(col_pic_name)
    
    # 以下对 col_pic_insert 插入的图片名称列,数字或字母,最终使col_pic_insert_r为字母
    if col_pic_insert_m.isalpha():
        col_pic_insert_r = col_pic_insert
    elif col_pic_insert_m.isdigit():
        # 如果是数字,调用函数转为字母
        col_pic_insert_r = gcl(col_pic_insert)
    
    wb=openpyxl.load_workbook(f_file_book)
    
    # 循环工作表列表
    for sht_name in sht_name_li:
        # 将图片路径转为字典
        dict_name = build_pic_dir_dict(f_file,file_book,sht_name,col_pic_name,col_pic_insert,row_start,pic_file)
        ws=wb[sht_name]
        print('_'*5 + '现在给 ' + sht_name + ' 插入图片' + '_'*5)
        
        # 最大行
        row_max = ws.max_row +1

        # 设置列宽
        ws.column_dimensions[col_pic_insert_r].width = 15

        for i in range(row_start,row_max):
            # 设置行高
            ws.row_dimensions[i].height=80

            # 图片名称
            pic_name = str(ws[col_pic_name_r + str(i)].value)

            if pic_name in dict_name.keys():

                pic_dir = dict_name[pic_name]
                cell = col_pic_insert_r + str(i)

                # 获取图片地址
                img=openpyxl.drawing.image.Image(pic_dir)

                # 设置图片的宽度
                img.width  = 114
                img.height = 101

                # 在单元格中添加img图像
                ws.add_image(img,cell)

                # 加一个输出,查看程序运行情况
                print(str(pic_name) + '插入成功')

            else:
                print(str(pic_name) + ' 奇怪了,居然真的没有插入成功')
            
    wb.save(f_file_book_r)       
    wb.close()

补充

优化的里面主是预先做了个图片名称与地址的字典函数, 插入图片时直接调用, 在这里补上

def build_pic_dir_dict(f_file,file_book,sht_name,col_pic_name,col_pic_insert,row_start,pic_file='Awork/00-sanho pictrue library/00-文件插入图片专用新图片/'):
    # 向excle 添加图片,首先先建立一个图片名关键字与对应图片路径的字典
    # f_file 表格地址
    # file_book 工作薄名称
    # sht_name 工作表名称
    # col_pic_name 插入的图片名称列,数字或字母,优选数字
    # col_pic_insert 图片插入列,数字或字母,优选数字
    # row_start 插入图片的起始行
    import pandas as pd

    f_file_book = f_file + file_book

    df = pd.read_excel(f_file_book,header=row_start-2,sheet_name=sht_name)
    
    # 将含图片名称列转为数列
    pic_name_li = df.iloc[:,col_pic_name-1].tolist()

    # 调用函数获取图片路径
    a = os_file_dir(pic_file)
    # 将图片路径转为字典
    dict_name = dict(zip(a[1],a[0]))
    
    # 建立插入图片的含图片名(key)及图片路径(value)的字典
    dict_new = {}
    
    # 建立图片名称列(key),实为图片名称含想插入图片关健字及路径的字典
    for pic_name in pic_name_li:
        # 判断如果字典有就跳过,避免有相同图片名的路径
        if str(pic_name) not in dict_new.keys():
            # 循环图片名(图片名为字典的keys
            for j in dict_name.keys():
                # 判断图片名是否包含想插入图片的关键字
                if str(pic_name) in j:
                    # 图片路径
                    pic_dir = dict_name[j]
                    # 图片名关键字
                    new_key = str(pic_name)
                    # 生成字典
                    dict_new[new_key] = pic_dir
        continue
    return dict_new

3、使用

import pandas as pd

f_file = r"/Users/add58/Downloads/"
file_book = "23年清仓品库存数.xlsx"
sht_name_li = ["Sheet1"]
col_pic_name = 1 # 要插入图片的图片名称所在的列,比如, A列
col_pic_insert = 3  # 图片插入在第几列, 3为插入在C列
row_start = 2 # 从第2行开始插入图片

add_pic_to_excel(
    f_file, file_book, sht_name_li, col_pic_name, col_pic_insert, row_start
)
print("finish")

插入成本则显示 插入成本, 如果图片名不对或没有这张图片, 显示 ' 奇怪了,居然真的没有插入成功'

2024-9-19 补充

有人问os_file_dir()这个函数, 之前忘记放上了

## 查找图片
def os_file_dir(
        file_path='Awork/00-sanho pictrue library/00-文件插入图片专用新图片/',
        FILE_TYPE=['.png', '.jpg', 'JPG', 'PNG']):
    # 函数作用读取文夹下面的文件的全路径 和 文件名
    # file_path 图片存放的位置, 我自己的图片位置就给了默认值, 可重新赋值
    # FILE_TYPE 图片的格式, 一定加.  一般常用图片的后缀名就这几种, 根据实际需求可重新赋值
    # 模块os中的walk()函数可以遍历文件夹下所有的文件
    # 该函数可以得到一个三元组tupple(dirpath, dirnames, filenames).
    # dirpath:string,代表目录的路径;
    # dirnames:list,包含了当前dirpath路径下所有的子目录名字(不包含目录路径);
    # filenames:list,包含了当前dirpath路径下所有的非目录子文件的名字(不包含目录路径)。
    # dirnames和filenames均不包含路径信息,如需完整路径,可使用os.path.join(dirpath, dirnames)
    import os
    # 以下这个判断是我自己在用的, 别人一般用不到这个判断
    if 'Users' in file_path:
        FILE_PATH = file_path
    else:
        FILE_PATH = f_dir + file_path
    Full_filepath_name = []
    The_file_name = []
    for root, dirs, files in os.walk(FILE_PATH):
        for file in files:
            # 这句是判断文件夹下面是否有指定的 FILE_TYPE 格式的文件
            if os.path.splitext(file)[1] in FILE_TYPE:
                Full_filepath_name.append(os.path.join(root, file))
                The_file_name.append(file)
    return Full_filepath_name, The_file_name

4、全部代码

将以上所有函数和代码封装为类, 在本次封装中,对原代码进行了简化, 并对函数名和参数名进行了规范,使其更加方便的阅读.

其中类方法get_image_paths中的2个参数

1、file_path='/Users/add58/Library/Mobile Documents/com~apple~CloudDocs/Awork/00-sanho pictrue library/00-文件插入图片专用新图片',

2、file_types=['.png', '.jpg', 'JPG', 'PNG'])

需要根据实际情况进行修改

为方便查阅, 添加了详尽的注释.

import string
import openpyxl
import pandas as pd
import os

class ExcelImageInserter:
    """一个用于向Excel表格中插入图片的类"""

    def __init__(self, file_path, file_name):
        """
        初始化ExcelImageInserter类

        :param file_path: Excel文件的路径
        :param file_name: Excel文件的名称
        """
        self.file_path = file_path  # 保存文件路径
        self.file_name = file_name  # 保存文件名称
        self.full_file_path = os.path.join(file_path, file_name)  # 拼接完整的文件路径

    @staticmethod
    def get_excel_column_letter(column_number):
        """
        根据列号获取Excel列的字母代码

        :param column_number: 列号(从1开始)
        :return: 对应的Excel列字母
        """
        if column_number <= 0:  # 如果列号小于等于0,返回空字符串
            return ''
        letters = string.ascii_uppercase  # 获取所有大写字母
        column_letter = ''  # 初始化列字母
        while column_number > 0:  # 当列号大于0时循环
            column_number -= 1  # 列号减1
            column_letter = letters[column_number % 26] + column_letter  # 计算当前字母并添加到前面
            column_number //= 26  # 列号整除26,准备下一轮计算
        return column_letter  # 返回最终的列字母

    def add_images_to_excel(self, sheet_names, image_name_col, image_insert_col, start_row):
        """
        向指定的Excel工作表中插入图片

        :param sheet_names: 工作表名称列表
        :param image_name_col: 图片名称列(数字或字母)
        :param image_insert_col: 图片插入列(数字或字母)
        :param start_row: 插入图片的起始行
        """
        output_file_path = os.path.join(self.file_path, '图片版' + self.file_name)  # 拼接输出文件路径

        # 确保列名是字符串
        image_name_col_str = str(image_name_col)  # 将图片名称列转换为字符串
        image_insert_col_str = str(image_insert_col)  # 将图片插入列转换为字符串

        # 获取列字母
        image_name_col_letter = self.get_excel_column_letter(int(image_name_col_str)) if image_name_col_str.isdigit() else image_name_col_str  # 获取图片名称列的字母
        image_insert_col_letter = self.get_excel_column_letter(int(image_insert_col_str)) if image_insert_col_str.isdigit() else image_insert_col_str  # 获取图片插入列的字母

        workbook = openpyxl.load_workbook(self.full_file_path)  # 加载Excel工作簿

        for sheet_name in sheet_names:  # 遍历每个工作表名称
            image_dict = self.build_image_path_dict(sheet_name, image_name_col, start_row)  # 构建图片路径字典
            worksheet = workbook[sheet_name]  # 获取当前工作表
            print(f'_____现在给 {sheet_name} 插入图片_____')  # 打印当前插入图片的工作表名称

            max_row = worksheet.max_row + 1  # 获取当前工作表的最大行数
            worksheet.column_dimensions[image_insert_col_letter].width = 15  # 设置插入列的宽度

            for row in range(start_row, max_row):  # 遍历从起始行到最大行
                worksheet.row_dimensions[row].height = 80  # 设置当前行的高度
                image_name = str(worksheet[image_name_col_letter + str(row)].value)  # 获取当前行的图片名称

                if image_name in image_dict:  # 如果图片名称在字典中
                    image_path = image_dict[image_name]  # 获取对应的图片路径
                    cell = f'{image_insert_col_letter}{row}'  # 计算插入图片的单元格位置
                    img = openpyxl.drawing.image.Image(image_path)  # 创建图片对象
                    img.width, img.height = 114, 101  # 设置图片的宽度和高度
                    worksheet.add_image(img, cell)  # 在指定单元格中添加图片
                    print(f'{image_name} 插入成功')  # 打印插入成功的信息
                else:
                    print(f'{image_name} 奇怪了,居然真的没有插入成功')  # 打印未能插入的图片名称

        workbook.save(output_file_path)  # 保存修改后的工作簿
        workbook.close()  # 关闭工作簿

    def build_image_path_dict(self, sheet_name, image_name_col, start_row):
        """
        建立图片名称与路径的字典

        :param sheet_name: 工作表名称
        :param image_name_col: 图片名称列(数字)
        :param start_row: 数据起始行
        :return: 包含图片名称和路径的字典
        """
        df = pd.read_excel(self.full_file_path, header=start_row - 2, sheet_name=sheet_name)  # 读取指定工作表的数据
        image_name_list = df.iloc[:, image_name_col - 1].tolist()  # 获取图片名称列的数据
        image_paths = self.get_image_paths()  # 获取图片路径和文件名
        image_dict = dict(zip(image_paths[1], image_paths[0]))  # 创建图片名称与路径的字典

        image_name_dict = {}  # 初始化图片名称字典
        for image_name in image_name_list:  # 遍历每个图片名称
            image_name_str = str(image_name)  # 确保图片名称是字符串
            if image_name_str not in image_name_dict:  # 如果字典中没有该图片名称
                for key in image_dict:  # 遍历图片路径字典的键
                    if image_name_str in key:  # 如果图片名称在键中
                        image_name_dict[image_name_str] = image_dict[key]  # 将图片名称和路径添加到字典
        return image_name_dict  # 返回图片名称与路径的字典

    @staticmethod
    def get_image_paths(file_path='/Users/add58/Library/Mobile Documents/com~apple~CloudDocs/Awork/00-sanho pictrue library/00-文件插入图片专用新图片', file_types=['.png', '.jpg', 'JPG', 'PNG']):
        """
        读取指定文件夹下的所有图片路径和文件名

        :param file_path: 图片存放的文件夹路径
        :param file_types: 支持的图片文件类型
        :return: 包含图片路径和文件名的元组
        """
        full_file_paths = []  # 初始化完整文件路径列表
        file_names = []  # 初始化文件名列表
        for root, dirs, files in os.walk(file_path):  # 遍历指定文件夹
            for file in files:  # 遍历文件夹中的每个文件
                if os.path.splitext(file)[1] in file_types:  # 如果文件类型在支持的类型中
                    full_file_paths.append(os.path.join(root, file))  # 添加完整路径到列表
                    file_names.append(file)  # 添加文件名到列表
        return full_file_paths, file_names  # 返回完整路径和文件名的元组

# 示例调用
file_path = r"/Users/add58/Downloads/"  # 设置Excel文件的路径
file_name = "礼品展选品pprice.xlsx"  # 设置Excel文件的名称
sheet_names = ["Sheet1"]  # 设置要处理的工作表名称
image_name_col = 2  # 设置图片名称列
image_insert_col = 7  # 设置图片插入列
start_row = 2  # 设置插入图片的起始行

image_inserter = ExcelImageInserter(file_path, file_name)  # 创建ExcelImageInserter对象
image_inserter.add_images_to_excel(sheet_names, image_name_col, image_insert_col, start_row)  # 调用方法插入图片
print("finish")  # 打印完成信息

效果展示:

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐