python办公自动化笔记(一):读写Excel图像数据

引言

本篇博客的初衷是在做天气检测测试的时候,为了将各种天气检测结果与图像相对应上,一时半会儿没想到有什么好的可视化工具,想了想那要不就用python代码将图片与图片对应的结果特征直接写进Excel中,可能会比较直观,另外,为了使本篇博客内容丰满一些,又去实验楼顺带做了openpyxl的一个试验,虽然最后的demo并没有用到这个东西,但这个库感觉比较好作为教程使用,下面介绍一些感觉会用到的一些功能。

openpyxl 使用 demo

1. 写入一行或多行数据:

from openpyxl import load_workbook
workbook = load_workbook(filename='imortTpl.xlsx')
sheet = workbook['Sheet1']
data1 = ['xiaoming', '22', 'M']
sheet.append(data1)
data2 = ['xiaohong', '20', 'F']
sheet.append(data2)
workbook.save(filename='/home/shiyanlou/new_test.xlsx')

在这里插入图片描述

2. 移动范围数据

以下图数据为例:
在这里插入图片描述
我们希望 D1:F2 的数据出现接在 A:C 列下面,因此需要对范围数据进行移动。

代码为 sheet.move_range('xx:xx',rows=n, cols=n), 其中数字为正为向下或向右,数字为负为向上或向左。

因此 sheet.move_range('D1:F2',rows=4, cols=-3) 就表示将 D1:F2 的数据整体向下移动 4 行后向左移动 3 列。

from openpyxl import load_workbook
workbook = load_workbook(filename='/home/shiyanlou/test.xlsx')
sheet = workbook.active
sheet.move_range('D1:F2',rows=4, cols=-3)
workbook.save(filename='/home/shiyanlou/new_test.xlsx')

在这里插入图片描述

3.删除行或列

从索引 idx 行开始删除 amount 行 (包括索引 idx 行)。

from openpyxl import load_workbook
workbook = load_workbook(filename='/home/shiyanlou/test.xlsx')
sheet = workbook['Sheet1']
sheet.delete_rows(idx=2, amount=2)
workbook.save(filename='/home/shiyanlou/new_test.xlsx')

从索引 idx 行开始删除 amount 列 (包括索引 idx 列)。

from openpyxl import load_workbook
workbook = load_workbook(filename='/home/shiyanlou/test.xlsx')
sheet = workbook['Sheet1']
sheet.delete_cols(idx=2, amount=2)
workbook.save(filename='/home/shiyanlou/new_test.xlsx')

4. 设置字体样式

  • font = Font(name=‘Arial’, size=12, bold=True, italic=True, color=‘FF0000’)

分别设置了字体名称、字号、加粗、斜体、颜色。完整代码如下:

from openpyxl import load_workbook
# 这里注意要导入方法
from openpyxl.styles import Font
workbook = load_workbook(filename='/home/shiyanlou/test.xlsx')
sheet = workbook.active
cell = sheet['A1']
font = Font(name='Arial', size=12, bold=True, italic=True, color='FF0000')
cell.font = font
workbook.save(filename='/home/shiyanlou/new_test.xlsx')

在这里插入图片描述

5.设置行高和列宽

代码如下(以调整第 1 行行高和第 C 列列宽为例):

sheet.row_dimensions[1].height = 50  # 行高
sheet.column_dimensions['C'].width = 20  # 列宽

6.单元格合并和取消合并

# 合并
sheet.merge_cells('A1:B2')  # 指定坐标范围
sheet.merge_cells(start_row=1, start_column=1,
                  end_row=2, end_column=2)  # 指定行列数

# 取消合并
sheet.unmerge_cells('A1:B2')   # 指定坐标范围
sheet.unmerge_cells(start_row=1, start_column=1,
                    end_row=2, end_column=2)  # 指定行列数

openpyxl 问题总结

目前来看,这个库还是会有很多bug,就我刚开始用就出现的问题有三个。第一个问题是:

openpyxl.utils.exceptions.InvalidFileException: openpyxl does not support the old .xls file format, please use xlrd to read this file, or convert it to the more recent .xlsx file format.

就我在尝试读取我之前存储的一个xls文档时,它提示我无法读取老格式,我寻思xls的格式确实是2013年之前的,但国内大部分人除非买电脑预装了office套装,否则应该还是用2013年左右的吧,因为就我之前参加很多场数模比赛,自己使用的以及听说大部分人用的,感觉还是xls和老版本,2016版本以后上云后联网速度打开太慢,不符合建模量子速读文献的作风,emmm…。

然后报了这个错后,因为我是在linux环境下,我理所当然的touch了一个新的xlsx,按照我之前使用pandas、xlsxwriter等包的时候它是可以的,即使后来我知道touch的方式是错误的,但是很多包还是有一个当前路径无Excel文件自动创建的机制,等同于判断了os.path.exists,那么openpyxl 的错误如下:

zipfile.BadZipFile: File is not a zip file

至于其它错误,无非是Excel内部的一些问题,这里就不再展示,主要提及我的一个应用场景。

图像等数据自动读写Excel

这里可以参照How to read pictures in Excel with Python? -Know 一文的思路,目前python能操作Excel图片的方式如下:

读出Excel图像

这里有几种方式,第一种是还可以根据 openpyxl 与 openpyxl-image-loader 做到指定位置读取,demo如下:

# Importing the modules
import openpyxl
from openpyxl_image_loader import SheetImageLoader

# loading the Excel File and the sheet
pxl_doc = openpyxl.load_workbook('myfile.xlsx')
sheet = pxl_doc['Sheet_name']

# calling the image_loader
image_loader = SheetImageLoader(sheet)

# get the image (put the cell you need instead of 'A1')
image = image_loader.get('A1')

# showing the image
image.show()

# saving the image
image.save('my_path/image_name.jpg')

还有一种直接用win32和pillow读取图片的,参照How to read pictures in Excel with Python? -Know 的demo如下:


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()  # 字典的浅拷贝(Copy)
            image = ImageGrab.grabclipboard()   # 该函数对当前剪贴板进行快照,返回一个模式为“RGB”的图像列表或文件名。如果剪贴板不包含图像数据,此函数返回 null。
            image.convert('RGB').save(r'D:\{}.jpg'.format(num), 'jpeg')
            num+=1
excel.Quit()

如果是Windows的话个人比较推荐第二种,因为openpyxl会比较慢,如果是大批量图像读取,根据下表来看可能会出现问题,而且不一定是无损图片,但我突然发现正常人可能会像Excel写入大量图片做对比,但写入后就不会再读了,那样不如对象存储,emmm。。。关于各种Excel的读写测试见如下图,这里就不再详细介绍其它库了:
在这里插入图片描述

## 写入Excel图像

最近我有一个需求是,有大概几百张图像要进行天气检测的测试,但是我测试完后,通过pandas可以得到图像的元数据,也就是它蕴含的特征,比如说什么天气,该图位于哪一个视频下等等,我当然可以将这些数据写入Excel,但写进去后还是需要跟服务器上的图像进行一一比对,用人眼判断对不对,想了想,觉得还是找个顺便把图也写进Excel的demo会比较好。但找了一会儿,发现网上大多是写入单张图的,不管单元格的格式,这种应用场景可能是一些数字各种计算后,直接画了一张统计图丢表中,如下,代码见如上一直参考的链接:
在这里插入图片描述
但是我的需求显然不是这样,然后又找了一会儿,发现知乎贴:怎么用Python向Excel中插入图片呢? 。对其进行一些修改与补充后,完整代码如下:

import pandas as pd
import os
import xlsxwriter
from PIL import Image

df = pd.read_excel("output.xlsx")

path = "/home/program/night"
pics = os.listdir(path)

# 定义一下写入的Excel和worksheet的名
book = xlsxwriter.Workbook("pic.xlsx")
sheet = book.add_worksheet("pic")

# 定义一下两列的name,再把要匹配的昵称填充进去。
sheet.write("A1", "Nickname")
sheet.write("B1", "Pic")
sheet.write_column(1, 0, df.image.values.tolist())  # 昵称放在第一列

# 要固定图片的大小,插入图片的那个单元格的大小也得调整
image_width = 160
image_height = 120
cell_width = 20
cell_height = 120
sheet.set_column("B:B", cell_width)  # 设置单元格列宽
images = [os.path.join(path, f) for f in os.listdir(path) if f.endswith(".png") or f.endswith(".jpeg")]
for i in range(len(df.image.values.tolist())):
    x_scale = image_width / (Image.open(images[i]).size[0])  # 固定宽度/要插入的原始图片宽
    y_scale = image_height / (Image.open(images[i]).size[1])  # 固定高度/要插入的原始图片高
    sheet.set_row(i + 1, cell_height)  # 设置行高 
    sheet.write_url(i+1, 2, images[i])
    sheet.insert_image(
        "B{}".format(i + 2),
        images[i],
        {
    
    "x_scale": x_scale, "y_scale": y_scale, "x_offset": 20, "y_offset": 15},
    )  # 设置一下x_offset和y_offset让图片尽量居中
book.close()

在这里插入图片描述

这里代码运行完只会有前面两列,后面是又通过pandas的concat拼起来的,原图是1920 * 1080,所以按照长宽比进行适量缩放,可能图片看得不清晰,在Excel打开后,还是能直接进行判断对不对,这也是不想加一个web网页功能的话,最稳妥的展示方式了(PS:不然又要加班?,emmm…)

猜你喜欢

转载自blog.csdn.net/submarineas/article/details/124865953