本文转载自微信公众号《早起的Python》,作者刘早起。转载本文请联系早起Python公众号。大家好,在使用Python进行办公自动化操作的时候,一定少不了与Excel表格的交互。我们通常使用pandas来处理表数据,但大多数情况下,我们都是读取表中的值进行分析。那么你知道如何用Python读取Excel中的图片吗?如何用Python将图片直接写入Excel?甚至用Python做一个Excel可视化大屏?由于图片的存储格式不同于数字数据,实现起来有点复杂,本文将对以下两部分进行深入讲解:Python读取Excel图片Python写入Excel图片涉及到的Python模块有PILwin32oszipfilenumpyxlsxwriter一、准备工作我们需要在命令行中使用pip来安装pipinstallpillow#这是模块的安装PTLpipinstallpypiwin32#这是win32的安装pipinstallospipinstallzipfilepipinstallnumpypipinstallxlsxwriter在下载过程中,有些包是比较大,会出现超时错误。这里有几个国内的镜像,大家可以试试其中一个,速度会比纯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清华代码如下:pipinstallmodulename-i网站以清华镜像为例pipinstallpillow-ihttps://pypi.tuna.tsinghua.edu.cn/simple注意:如果是在原来的cmd窗口安装,会提示添加一个--user命令,读者按照说明操作即可。2、Python读取Excel图片上面说了Python读取Excel图片有两种方式。第一种方法:将xlsx的后缀名改为zip形式,即压缩。然后读取存放图片的文件,取出里面的图片。第二种方法:使用提取到剪贴板的方法将图片保存为JPG、PNG等格式。这两种方法各有优缺点。第一种方法的缺点是代码量比较长,优点是通用,所有格式的Excel都可以使用。可以使用。第二种的优点是代码量小,缺点是不能用于一些xlsx文件。首先,我们先讲解第一种方法,然后在讲解第二种方法时,大家可以做个对比!在讲解之前,我们使用了如下的example.xlsx文件,里面包含了四个工作表,每个工作表都有一个数据可视化图。比如worksheet3中的气泡图如下:2.1方法一和上一篇一样,我们先给出所有的代码和效果图,然后讲解importosimportzipfileimportosfromPILimportImageimportnumpyasnppath=r'D:'count=1forfileinos.listdir(path):new_file=file.replace(".xlsx",".zip")os.rename(os.path.join(path,file),os.path.join(path,new_file))count+=1print('total'+str(count)+'folders')number=0craterDir="D:/"#存放zip文件的文件夹路径saveDir="D:/"#存放图片的路径list_dir=os.listdir(craterDir)foriinrange(len(list_dir)):if'zip'notinlist_dir[i]:list_dir[i]=''while''inlist_dir:list_dir.remove('')forzip_nameinlist_dir:print(zip_name)azip=zipfile.ZipFile(craterDir+zip_name)namelist=(azip.namelist())foridxinrange(0,len(namelist)):ifnamelist[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+=1azip.close()#关闭文件,肯定是可用的,释放内存效果如下图:可以看到example.xlsx中的四个工作表中的图片都被提取出来保存到本地了。现在让我们分析代码。首先导入相关包importosimportzipfilefromPILimportImageimportnumpyasnp。其次,将xlsx格式末尾的文件夹压缩成zip末尾的文件path=r'D:'#excelfilelocationcount=1forfileinos.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盘根目录下。如果读者需要进行调整,只需修改路径中的代码行即可。其次,os模块的listdir函数用于返回指定文件夹中包含的文件或文件夹的名称列表。然后用for循环遍历list,将.xlsx结尾改成.zip结尾。同时使用os.rename()函数重命名对应的文件夹。count用于告诉用户这个文件夹中有多少个文件需要检查。最后,从这些压缩文件中提取图像。代码如下number=0craterDir="D:/"#存放zip文件的文件夹路径saveDir="D:/"#存放图片的路径list_dir=os.listdir(craterDir)#获取所有文件名foriinrange(len(list_dir)):if'zip'notinlist_dir[i]:list_dir[i]=''while''inlist_dir:list_dir.remove('')下面是代码分析:首先使用number=0在最后为图片命名。craterDir指的是zip存放文件夹的路径,saveDir指的是存放解压图片的指定路径。使用os.listdir()函数获取该路径下的所有文件名。这里强调一下,本章代码使用的路径,除了上面提到的路径外,都是使用绝对路径,因为os模块、zipfile模块等模块使用绝对路径是不会报错的。下面使用for循环和while循环的目的是消除不以.zip结尾的文件夹。这时候有读者会问了,用for循环加一个listdel函数不好吗?其实也不可能,你可以试试。原因是每次delwanlist的一个元素,list的值总是会变化的,而不是固定的,这会导致超出索引的错误。forzip_nameinlist_dir:print(zip_name)#defaultmoder,readazip=zipfile.ZipFile(craterDir+zip_name)#返回所有文件夹和文件namelist=(azip.namelist())foridxinrange(0,len(namelist)):ifnamelist[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+=1azip.close()#关闭文件,必须有,释放内存最后读取zip中的图片文件。使用for循环遍历我们处理过的列表——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方法二下面对方法二进行说明,首先从PILimportImageGrabimportwin32com.clientaswin32excel=win32.gencache.EnsureDispatch('Excel.Application')workbook=excel.Workbooks.Open(r'D:\example.xlsx')上传代码num=1forsheetinworkbook.Worksheets:fori,shapeinenumerate(sheet.Shapes):ifshape.Name.startswith('Picture'):shape.Copy()image=ImageGrab.grabclipboard()image.convert('RGB').保存(r'D:\{}.jpg'.format(num),'jpeg')num+=1excel.Quit()效果渲染:从上图可以看出,和方法一的效果相比,基本上是一样,只是没有压缩,先简单说一下来自PILimportImageGrabimportwin32com.clientaswin32excel=win32.gencache.EnsureDispatch('Excel.Application')workbook=excel.Workbooks.Open(r'D:\example.xlsx')的代码介绍方法二相关的模块,第三行代码是导入模块win32中Excel的应用程序。第四行同方法一,读取D盘根目录下的example.xlsx文件。num=1forsheetinworkbook.Worksheets:fori,shapeinenumerate(sheet.Shapes):ifshape.Name.startswith('Picture'):shape.Copy()image=ImageGrab.grabclipboard()image.convert('RGB').save(r'D:\{}.jpg'.format(num),'jpeg')num+=1excel.Quit()第一行num=1用来给下面存储图片的图片命名,下一步为embedding的一组for,第一个for循环的目的是遍历选中的Excel文件中的工作表,我们有四张图片分别放在example.xlsx的四个不同的工作表中。第二个for循环用于遍历每个工作表中的图片,并将它们复制到剪贴板。其中,enumerate()函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合成一个索引序列,同时列出数据和数据下标,一般用于for环形。这里的意思是存放每张图片的数据信息的索引。i为数据下标,shape为数据shape。Name.startswith('Picture')是判断获取的shape中名称信息的开头是否符合'picture',若符合则返回True。shape.Copy()函数是字典的浅拷贝(copy)。简单地说,它只是在程序中被复制。ImageGrab.grabclipboard()函数是第二种方法的精华。此函数抓取当前剪贴板的快照并返回模式为“RGB”的图像或文件名列表。如果剪贴板不包含图像数据,则此函数返回NULL。读者可以使用函数isinstance()来检查函数是否返回有效的图像对象或其他数据。语句image.convert('RGB').save(r'D:\{}.jpg'.format(num),'jpeg')将获取的图片以jpg格式存储。这里的jpeg其实就是jpg,只不过模块中用的是jpeg而不是jpg。请注意,此处必须使用convert('RGB')。如果不使用.convert('RGB')转换,读出的图像是RGBA四通道,A通道是透明通道,出厂时没有图像显示。所以使用convert('RGB')进行通道转换。至此,我们就讲完了使用Python提取Excel中图片的两种方法。大家可以根据自己的情况选择在Excel中提取图片。2.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参数andinsert_image()方法接受字典形式的可选参数,对图像进行定位和缩放,默认值为{'x_offset':0,#inpixels,可以大于每个cell的宽高'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参数提供s鼠标悬停在包含超链接的图像上时的可选提示信息。image_data参数用于在io.BytesIO中添加内存中的字节流,一般不带定位参数可以用来控制图片对象的位置。接下来我会做一个简单的程序来演示一下:这里我用一段数据简单的画了一个折线图。数据是广汇汽车的一个股票数据,从月底到10月底的8个数据。画一个带有收盘价和时间的简单折线图。代码如下:importpandasaspdimportmatplotlib.pyplotaspltimportmatplotlib.styleeaspslimportxlsxwriterfig=plt.figure()df=pd.read_excel(r'D:\data.xlsx')title=['日期','收盘价']df=df[title]plt.plot(df['日期'],df['收盘价'])plt.gcf().autofmt_xdate()#自动调整角度plt.savefig(r'D:\数据线图.jpg')Python绘制的图形如下:现在我们要把它插入到一个名为dataimage.xlsx的excel文件中,看看代码怎么写??先用xlswriter新建一个Excel文件,添加工作表。workbook=xlsxwriter.Workbook(r'D:\dataimages.xlsx')worksheet=workbook.add_worksheet()下面使用.insert_image插入图片。worksheet.write('A2','插入第一张图片:')worksheet.insert_image('B2',r'D:\Datalinechart.jpg')worksheet.write('A12','插入第二张图片位置offsetimage:')worksheet.insert_image('B12',r'D:\datalinechart.jpg',{'x_offset':15,'y_offset':10})#插入缩放后的图片。worksheet.write('A23','插入第三张缩放图片:')worksheet.insert_image('B23',r'D:\DataLineChart.jpg',{'x_scale':0.5,'y_scale':0.5})workbook.close()最后必须用workbook.close()生成。效果如下。可以看到我们使用Matplotlib生成的折线图插入到了我们预定的指定位置!至此,本文就结束了,相信你已经学会了如何使用Python与Excel图片进行交互,并且可以根据具体需求进行批量操作!
