那么你知道如何使用Python读取Excel中的图片 ?又如何使用Python直接往Excel中写入图片 ?甚至使用Python制作一个Excel可视化大屏?
因为图片的存储格式与数字数据格式不一样,所以实现起来稍显复杂,本文就将对以下两个部分进行深入讲解:
涉及的Python模块有以下几个
由于此次包比较多,我们需要在命令行中使用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图片有两种方法 。
“ 第一种 :将xlsx
后缀名改为zip
形式,即进行压缩。而后读取里面存储图片的文件,将里面的图片取出来。
第二种 :用提取到粘贴板中的方法将图片保存到JPG
、PNG
等格式中
” 两种方法各有缺点和优点,第一种方法缺点是代码量比较长,优点是万能 ,Excel的所有格式都可以运用。
第二种的优点是代码量少,缺点是对于一些xlsx
的文件运用不了 。
首先我们先讲解第一种方法,之后在讲解第二种方法时,大家可以进行对比!
讲解之前我们用的是以下的example.xlsx
文件,里面有四个工作表,每个工作表都有一张数据可视化图。例如工作表3中的气泡图如下:
和之前的文章一样,我们先给出全部代码与效果图 之后再进行讲解
import osimport zipfileimport osfrom PIL import Imageimport 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 osimport zipfilefrom PIL import Imageimport 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图像,如果是黑白的话就要调一下参数。有兴趣的读者可以自行查阅文献。
” 接下来讲解第二种方法,先上代码
from PIL import ImageGrabimport 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 ImageGrabimport 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 文件中。
我们常用的模块是xlsxwriter
。这里先介绍这个模块的常用插入图片函数
worksheet.insert_image(row,col,image[,options]
:在工作表单元格中插入一张图片
参数介绍如下:
“ 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_scale
和y_scale
参数可以用于水平及垂直的缩放图片。url
参数可以为图片添加超链接/url, tip
参数为含有超链接的图片提供可选的鼠标悬停时的提示信息image_data
参数用于在io.BytesIO中添加内存中的字节流,一般不用positioning
参数可以用来控制图片对象的位置” 接下来会做一个简单的程序来演示:
这里用一份数据简单的画出一个折线图,数据是一份广汇汽车的股票数据 ,从8月底到10月底的数据。以收盘价和时间画一个简单的折线图.
代码如下:
import pandas as pdimport matplotlib.pyplot as pltimport matplotlib.style as pslimport 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为你开启陪读模式,解答你在阅读本书时的一切疑问。 添加微信 crossin123 ,加入编程教室共同学习 ~