背景:
报表里面的图片一般都是不会直接存图片的实体,一般是存图片存放的位置,也就是url,然后报表的使用对象也不是程序相关工作者,只会使用简单的excel功能,于是有了如下对话:
小哥哥,你可以把里面的url变成图片吗?这样我们就可以直接使用啦。
这不就来看看咋弄合适。
可能用到的库:
import io
import requests
import time
import re
from openpyxl import load_workbook
from openpyxl.drawing.image import Image
用户场景分析:
使用对象一般是这种格式的excle:
很明显第一行是标题,第二行开始就是内容,而我们需要转换的内容在第n(n>=2)行的C(?)列,那么我们想要把图片的url拿出来,那至少要知道url在哪里列,这个url,可能有多个,所以我们可以提取第二行(显然可以肯定要求变更行数)的数据进行清洗。
def urlpoint(data):
NumTip = []
if data == []:
return -1
for i in range(len(data)):
strname =str(data[i])
# 用于匹配至少一个图片形式
pattern = re.compile(r'(.png|.img|.gif|.jpg|.jpeg)$')
m = pattern.search(strname)
if m == None:
continue
else:
NumTip.append(i)
# 如果一个图片地址都没有找到就返回-1,不然返回下表的集合
if NumTip == []:
return -1
else:
return NumTip
这样就可以得到我们的目标列的下标了, 在图示中的url是没有带前面的路由地址的,因为一个公司的图片网址是往往是固定的,这样存储可以省一点空间,但是我们要兼容有些直接就是图片地址的情况。于是:
url = cell.value
#阻止某些为空
if url == None:
continue
#事实上这里可以检查一下url是否有前缀http 这样可以兼容一下其他形式的图片
pattern = re.compile(r'^(https://|http://)')
# 用于匹配至少一个数字
m = pattern.match(url)
if m == None:
url ='https://image.baidu.com/' +url
然后我们需要去通过url获取到图片,将图片存在内存里,然后在写入excel里,这个时候需要对获取的图片按比例进行裁剪,具体函数:
def img_resize(width, height):
if width > height:
height = height*200//width
width = 200
else:
width = width*200//height
height = 200
return width, height
然后我们将这个写入excel:
# 删除超链接
cell.hyperlink = None
# # 删除内容
cell.value = ""
# 设置行高
ws.row_dimensions[cell.row].height = 200
# 下载图片到内存
res = requests.get(url)
img = Image(io.BytesIO(res.content))
# 等比例缩放图片
width, height = img_resize(img.width, img.height)
img.width = width
img.height = height
# 拼接目标单元格 subscript 是替换url Ccolumns+i+1 是按顺序放后面
endnum =str(Cnum[subscript]) + str(cell.row)
print('成功添加到第:',endnum,'列')
# 添加图片到指定单元格
ws.add_image(img, endnum)
这个时候一行的图片就转换好了,然后我们对整个文档进行遍历,就可以完成了。
完整代码如下:
from csv import excel
import io
import requests
import time
import re
from openpyxl import load_workbook
from openpyxl.drawing.image import Image
# 保持图片的比例
def img_resize(width, height):
if width > height:
height = height*200//width
width = 200
else:
width = width*200//height
height = 200
return width, height
# 获得选中的表的最大行数和最大列数
def getRowsClosNum(self):
rows = self.max_row
columns = self.max_column
return rows,columns
def get_row_value(self, row):
columns = self.max_column
row_data = []
for i in range(1, columns + 1):
cell_value = self.cell(row=row, column=i).value
row_data.append(cell_value)
return row_data
def urlpoint(data):
NumTip = []
if data == []:
return -1
for i in range(len(data)):
strname =str(data[i])
# 用于匹配至少一个图片形式
pattern = re.compile(r'(.png|.img|.gif|.jpg|.jpeg)$')
m = pattern.search(strname)
if m == None:
continue
else:
NumTip.append(i)
# 如果一个图片地址都没有找到就返回-1,不然返回下表的集合
if NumTip == []:
return -1
else:
return NumTip
def TurnURLPictures(dataname,textname,ExcleSheet=0):
start = time.clock()
# 用户下载的位置
textname ='download/' +str(dataname)+'.xlsx'
# 用户上传的位置
dataname ='files/'+str(dataname)+'.xlsx'
wb = load_workbook(dataname)
Sheetnames =wb.sheetnames
#默认是第一个表
ws = wb[Sheetnames[ExcleSheet]]
# 获得第二行的数据,通常来说第一行是标题名,带入get_row_value()里面,
cData = get_row_value(ws,2)
#得到这个表的行高
Crows,Ccolumns= getRowsClosNum(ws)
#url 所在列
urlnum =urlpoint(cData)
if urlnum == -1:
print ('Its second line does not have a URL')
return -1
#拼接操作的xlsx 文件的行数 一般为2-maxrow
Cnum ={1:"A",2:"B",3:"C",4:"D",5:"E",6:"F",7:"G",8:"H",9:"I",10:"J",11:"K",12:"L",13:"M",14:"N","15":"O",16:"P",17:"Q",18:"R",19:"S",20:"T",21:"U",22:"V",23:"W",24:"X",25:"Y"}
#
GroupNum = len(urlnum)
for i in range(GroupNum):
subscript = urlnum[i]+1
name =str(Cnum[subscript])+'2:'+str(Cnum[subscript])+str(Crows)
ws.column_dimensions[Cnum[subscript]].width = 50
for cell, in ws[name]:
url = cell.value
#阻止某些为空
if url == None:
continue
#事实上这里可以检查一下url是否有前缀http 这样可以兼容一下其他形式的图片
pattern = re.compile(r'^(https://|http://)')
# 用于匹配至少一个数字
m = pattern.match(url)
if m == None:
url ='https://image.baidu.com/' +url
# 删除超链接
cell.hyperlink = None
# # 删除内容
cell.value = ""
# 设置行高
ws.row_dimensions[cell.row].height = 200
# 下载图片到内存
res = requests.get(url)
img = Image(io.BytesIO(res.content))
# 等比例缩放图片
width, height = img_resize(img.width, img.height)
img.width = width
img.height = height
# 拼接目标单元格 subscript 是替换url Ccolumns+i+1 是按顺序放后面
endnum =str(Cnum[subscript]) + str(cell.row)
print('成功添加到第:',endnum,'列')
# 添加图片到指定单元格
ws.add_image(img, endnum)
start2 = time.clock()
wb.save(textname)
print('Running time: %s 毫秒' % (start2*1000-start*1000))
return Crows/60
if __name__=="__main__":
TurnURLPictures('bbf579f8a4c311ec8f8b1831bf2aef29','测试')
效果如下: