社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

如何用Python读写Excel中图片?

Crossin的编程教室 • 1 周前 • 24 次点击  

大家好,在使用Python进行办公自动化操作时,一定少不了与Excel表格的交互,我们通常是用pandas处理表格数据,但大多数情况下,都是读取表格中的数值进行分析。

那么你知道如何使用Python读取Excel中的图片?又如何使用Python直接往Excel中写入图片?甚至使用Python制作一个Excel可视化大屏?

因为图片的存储格式与数字数据格式不一样,所以实现起来稍显复杂,本文就将对以下两个部分进行深入讲解:

  • Python读取Excel图片
  • Python写入Excel图片

涉及的Python模块有以下几个

  • PIL
  • win32
  • os
  • zipfile
  • numpy
  • xlsxwriter

  一、准备

由于此次包比较多,我们需要在命令行中使用pip进行安装

pip install pillow   #这是对模块PTL的安装
pip install pypiwin32    #这是对win32的安装
pip install os 
pip install zipfile
pip install numpy
pip install xlsxwriter

在下载的过程中,有些包是比较大的,会出现超时time out的报错现象。这里介绍几个国内的镜像,大家可以尝试其中一个,速度会比单纯的pip快10倍不止。地址如下:

http://pypi.douban.com/simple/ 豆瓣
http://mirrors.aliyun.com/pypi/simple/ 阿里
http://pypi.hustunique.com/simple/ 华中理工大学
http://pypi.sdutlinux.org/simple/ 山东理工大学
http://pypi.mirrors.ustc.edu.cn/simple/ 中国科学技术大学
https://pypi.tuna.tsinghua.edu.cn/simple 清华

代码如下:

pip install 模块名 -i 网址

清华镜像举例

pip install pillow -i https://pypi.tuna.tsinghua.edu.cn/simple

注意:如果是原生态的cmd窗口安装的,会提示加个--user命令,读者按照指示即可。

  二、Python读取Excel图片

上面说过,Python读取Excel图片有两种方法

第一种:将xlsx后缀名改为zip形式,即进行压缩。而后读取里面存储图片的文件,将里面的图片取出来。

第二种:用提取到粘贴板中的方法将图片保存到JPGPNG等格式中

两种方法各有缺点和优点,第一种方法缺点是代码量比较长,优点是万能,Excel的所有格式都可以运用。

第二种的优点是代码量少,缺点是对于一些xlsx的文件运用不了

首先我们先讲解第一种方法,之后在讲解第二种方法时,大家可以进行对比!

讲解之前我们用的是以下的example.xlsx文件,里面有四个工作表,每个工作表都有一张数据可视化图。例如工作表3中的气泡图如下:

2.1  方法一

和之前的文章一样,我们先给出全部代码与效果图之后再进行讲解

import os
import zipfile
import os
from PIL import Image
import numpy as np 
path = r'D:'
count = 1
for file in os.listdir(path):
    new_file = file.replace(".xlsx",".zip")
    os.rename(os.path.join(path,file),os.path.join(path,new_file))
    count+=1
print('总共有'+str(count)+'个文件夹')
number = 0
craterDir = "D:/"  # 存放zip文件的文件夹路径
saveDir = "D:/"  # 存放图片的路径 
list_dir = os.listdir(craterDir) 
for i in range(len(list_dir)):
    if 'zip' not in list_dir[i]:
        list_dir[i] = ''
while '' in list_dir:
    list_dir.remove('')    
for zip_name in list_dir:
    print(zip_name)
    azip = zipfile.ZipFile(craterDir + zip_name)
    namelist = (azip.namelist())
 
    for idx in range(0,len(namelist)):
        if namelist[idx][:9] == 'xl/media/':#图片是在这个路径下
            img_name = saveDir + str(number)+'.jpg'
            f = azip.open(namelist[idx])
            img = Image.open(f)
            img = img.convert("RGB")
            img.save(img_name,"JPEG")
            number += 1
azip.close()  #关闭文件,必须有,释放内存

效果展现如下:

可以看到example.xlsx里面的四张工作表里的图片都提取出来,保存在本地。

现在我们进行代码解析,首先,引入相关包

import os
import zipfile
from PIL import Image
import numpy as np 

其次,就是将xlsx格式结尾的文件夹进行压缩,转化成zip结尾的文件

path = r'D:'   #excel文件位置
count = 1
for file in os.listdir(path):
    new_file = file.replace(".xlsx",".zip")
    os.rename(os.path.join(path,file),os.path.join(path,new_file))
    count+=1 

这里首先设置了example.xlsx的文件位置,在D盘的根目录,读者需要做调整的话在path那行代码修改即可。

其次用os模块的listdir函数用于返回指定的文件夹包含的文件或文件夹的名字的列表。再用for循环遍历这个列表,将.xlsx结尾的改为.zip结尾。

同时再用os.rename()函数重命名对应的文件夹。count是用来告诉用户这个文件夹有多少个文件的,用于检验。

最后,就是在这些压缩过后的文件中,提取图片。代码如下

number = 0
craterDir = "D:/"  # 存放zip文件的文件夹路径
saveDir = "D:/"  # 存放图片的路径 
list_dir = os.listdir(craterDir) # 获取所有的文件名

for i in range(len(list_dir)):
    if 'zip' not in list_dir[i]:
        list_dir[i] = ''
while '' in list_dir:
    list_dir.remove('')   

下面是代码解析

首先,number=0是用来最后命名图片的。craterDir是指存放zip的文件夹路径,saveDir指存放提取后的图片的指定路径。用os.listdir()函数来获取在这个路径下的所有文件名字。

这里强调下,本章代码采用的路径,除了上面讲过的path外,其他都用绝对路径,因为如os模块和zipfile模块,这些模块用绝对路径更不会报错。

下面用一个for循环加个while循环的用途是剔除不是.zip结尾的文件夹。这时有读者会问,用for循环加个列表del函数不香吗?

其实是不行的,大家可以去尝试一下。原因是,你每次del广域网一个列表的元素,列表的数量值会一直在变而不是固定的,这样就会导致超出索引的错误。

for zip_name in list_dir:
    print(zip_name)
    # 默认模式r,读
    azip = zipfile.ZipFile(craterDir + zip_name)
    # 返回所有文件夹和文件
    namelist = (azip.namelist())
 
    for idx in range(0,len(namelist)):
        if namelist[idx][:9] == 'xl/media/':#图片是在这个路径下
            img_name = saveDir + str(number)+'.jpg'
            f = azip.open(namelist[idx])
            img = Image.open(f)
            img = img.convert("RGB")
            img.save(img_name,"JPEG")
            number += 1
azip.close()  #关闭文件,必须有,释放内存

最后就是读取zip文件中的图片。用for循环遍历我们已经处理过的list——dir列表,得到zip文件名,再用zipfile.ZipFile()函数来打开我们zip文件。其中azip.namelist()函数是用来装zip文件里面所有文件的文件名列表。

接下来可以进入到zip文件中仔细观察,可以发现我们所需要的图片在'xl/media/'这个路径下,有了这个目标后,我们再用for循环遍历zip文件里的所有文件,找到路径下的图片。

第二个for循环需要注意几点

azip.open()zipfile模块里的打开命令。相对应的,就有azip.close()这个命令,这个命令再整个程序运行完后必须运训,因为不仅可以清理所占空间,而且如果你需要还原xlsx文件格式的话,你就必须得关闭,不然会报错。

Image.open()是模块Pillow模块的读取图片函数,也算是我们本章最重要的函数之一了,与其搭配的是Image.save()函数,是用来存储的。中间插着一段代码img.convert("RGB"),这个一般都是要用到的,我们存储的图片大多数是有色的,也就是RGB图像,如果是黑白的话就要调一下参数。有兴趣的读者可以自行查阅文献。

2.2  方法二

接下来讲解第二种方法,先上代码

from PIL import ImageGrab
import win32com.client as win32

excel = win32.gencache.EnsureDispatch('Excel.Application')
workbook = excel.Workbooks.Open(r'D:\example.xlsx')

num = 1
for sheet in workbook.Worksheets:
    for i, shape in enumerate(sheet.Shapes):
        if shape.Name.startswith('Picture'):
            shape.Copy()
            image = ImageGrab.grabclipboard()   
            image.convert('RGB').save(r'D:\{}.jpg'.format(num), 'jpeg')
            num+=1
excel.Quit()

效果呈现:

从上图可以看到,与方法一的效果相比,基本一致,除了没有进行压缩,下面简单说一下代码

from PIL import ImageGrab
import win32com.client as win32
excel = win32.gencache.EnsureDispatch('Excel.Application')
workbook = excel.Workbooks.Open(r'D:\example.xlsx')

首先先引入方法二相关的模块,第三行代码是引入模块win32中对Excel中的运用程序。第四行和方法一一样是读取D盘根目录下的example.xlsx文件。

num = 1
for sheet in workbook.Worksheets:
    for i, shape in enumerate(sheet.Shapes):
        if shape.Name.startswith('Picture'):
            shape.Copy()
            image = ImageGrab.grabclipboard()   
            image.convert('RGB').save(r'D:\{}.jpg'.format(num), 'jpeg')
            num+=1
excel.Quit()

第一行num=1,是用来为下面存储图片的图片命名的

接下来就是进行for嵌套for,第一个for循环的目的是遍历所选Excel文件中的工作表,我们有四张图片放在example.xlsx的四个不同的工作表里。第二个for循环是用来遍历每个工作表中的图片并复制到粘贴板中的。

其中,enumerate()函数是用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。这里的意思就是存放每张图片数据信息的索引。i是数据下标,shape是数据

shape.Name.startswith('Picture')是判断获到的shape里面名字信息中的开头是否符合'pitcure',如果是,则返回True。

shape.Copy()函数是对一个一个字典的浅复制(拷贝)。简单来说就是只在程序中的复制。

ImageGrab.grabclipboard()函数是方法二的精髓,这个函数是抓取当前剪贴板的快照,返回一个模式为“RGB”的图像或者文件名称的列表。如果剪贴板不包括图像数据,这个函数返回空。读者可以使用函数isinstance()来检查该函数返回的是一个有效图像对象或者其他数据。

image.convert('RGB').save(r'D:\{}.jpg'.format(num), 'jpeg')这段语句,是将得到的image以jpg的格式存储。这里的jpeg其实就是jpg,只不过模块里以jpeg代替jpg。

注意,这里必须用convert('RGB'),如果不使用.convert('RGB')进行转换的话,读出来的图像是RGBA四通道的,A通道为透明通道,运出来是没有图像显示的。因此使用convert('RGB')进行通道转换。

至此,我们就讲完了使用Python提取Excel中图片的两种方法,大家可以根据自己的情况来选择如恶化提取Excel中的图片。

  二、Python写入Excel图片

在讲完如何用Python提取Excel中图片之后,下面我们将讲解如何用Python将图片写入到Excel文件中。

我们常用的模块是xlsxwriter。这里先介绍这个模块的常用插入图片函数

worksheet.insert_image(row,col,image[,options] :在工作表单元格中插入一张图片

参数介绍如下:

  • row(int) - 单元格所在的行(从0开始)
  • col(int) - 单元格所在的列(从0开始)
  • image(string) - 图片文件名(含路径)
  • options(dict) - 可选的图片位置,缩放,url参数

同时insert_image()方法接受字典形式的可选参数来定位和缩放图片。默认值为

{
    'x_offset'0,    #以像素为单位,可以大于每个单元格的宽度和高度
    'y_offset'0,
    'x_scale'1,
    'y_scale'1,
    'url'None,
    'tip'None,
    'image_data'None,
    'positioning'None,
}

上面几个参数主要作用如下:

  • x_scaley_scale参数可以用于水平及垂直的缩放图片。
  • url参数可以为图片添加超链接/url, tip 参数为含有超链接的图片提供可选的鼠标悬停时的提示信息
  • image_data参数用于在io.BytesIO中添加内存中的字节流,一般不用
  • positioning参数可以用来控制图片对象的位置

接下来会做一个简单的程序来演示:

这里用一份数据简单的画出一个折线图,数据是一份广汇汽车的股票数据,从8月底到10月底的数据。以收盘价和时间画一个简单的折线图.

代码如下:

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.style as psl
import xlsxwriter
fig = plt.figure()
df = pd.read_excel(r'D:\数据.xlsx')
title = ['日期','收盘价']
df = df[title]
plt.plot(df['日期'],df['收盘价'])
plt.gcf().autofmt_xdate()#自动调整角度
plt.savefig(r'D:\数据折线图.jpg')

Python画出的图如下:

现在我们要将其插入到一份名为数据image.xlsx的excel文件中,来看看代码怎么写👇

首先使用xlswriter创建一个新Excel文件并添加一个工作表


workbook = xlsxwriter.Workbook(r'D:\数据images.xlsx')
worksheet = workbook.add_worksheet()

下面使用.insert_image插入图片。

worksheet.write('A2''插入第一张图片:')
worksheet.insert_image('B2', r'D:\数据折线图.jpg')

worksheet.write('A12''插入第二张即位偏移图片:')
worksheet.insert_image('B12', r'D:\数据折线图.jpg', {'x_offset': 15, 'y_offset': 10})


# 插入一张缩放了的图片。
worksheet.write('A23''插入第三张缩放了的图片:')
worksheet.insert_image('B23', r'D:\数据折线图.jpg', {'x_scale': 0.5, 'y_scale': 0.5})

workbook.close()

最后要注意一定要用workbook.close()才能生成,效果呈现如下

可以看到,我们使用Matplotlib生成的折线图被插入到我们预定的指定位置中!

至此,本文就结束了,相信你已经学会如何使用Python与Excel图片之间的交互,并能够结合具体的需求进行批量操作

本文灵感来自某位群友的问题,欢迎大家来讨论群交流编程相关问题!



Crossin的新书《码上行动:用ChatGPT学会Python编程》已经上市了。本书以ChatGPT为辅助,系统全面地讲解了如何掌握Python编程,适合Python零基础入门的读者学习。【点此查看详细介绍】
购买后可加入读者交流群,Crossin为你开启陪读模式,解答你在阅读本书时的一切疑问。
Crossin的其他书籍:


添加微信 crossin123 ,加入编程教室共同学习~

感谢转发点赞的各位~
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/175450
 
24 次点击