先看知乎上面的一个连接
用Python写过哪些【脑洞大开】的小工具?
这个哥们通过爬气象网站的气象雷达图,生成一个gif的动态图。非常有趣且很实用,那咱也实现下。
我们先实现一个从GIF提取帧的代码
我们这有个gif
代码如下:
from PIL importImageimportsysdefprocessImage(infile):try:
im=Image.open(infile)exceptIOError:print ("Cant load", infile)
sys.exit(1)
i=0
mypalette=im.getpalette()try:while 1:
im.putpalette(mypalette)
new_im= Image.new("RGBA", im.size)
new_im.paste(im)
new_im.save('image\\a'+str(i)+'.png')
i+= 1im.seek(im.tell()+ 1)exceptEOFError:pass #end of sequence
processImage('source.gif')
生成效果:
从gif提取frame是不是很简单,只需要一个PIL库搞定
但从frame生成gif就麻烦了,因为我们使用的是py3,网上一大堆代码用的是py2.*的 比如PythonMagick 、 images2gif
还有部分手写gif文件头部GIF89a,调用帧palette、NETSCAPE2.0写入图像等,你们都运行成功了,为什么我没有运行成功呢?
唉!
python就是牛,库如此之多,虽然本人Py一般般,但有前人为你写诗,您只要尾行加句号就可以了。这里我说的是imageio
下载地址: https://pypi.python.org/pypi/imageio (Version:2.2.0 by 2017-05-25)
importmatplotlib.pyplot as pltimportimageio,os
images=[]
filenames=sorted((fn for fn in os.listdir('.') if fn.endswith('.png')))for filename infilenames:
images.append(imageio.imread(filename))
imageio.mimsave('gif.gif', images,duration=1)
OK! gif生成了!
imageio.help('gif')
其实,PIL自身也有一个save方法,里面有一个‘save_all’ 参数,意思就是save多个,当format指定为gif时,生成的便是gif的动画
from PIL importImage
im=Image.open("a0.png")
images=[]
images.append(Image.open('a1.png'))
images.append(Image.open('a2.png'))
im.save('gif.gif', save_all=True, append_images=images,loop=1,duration=1,comment=b"aaabb")
读取第一帧,将第一个帧的像素设置为gif像素
python将png图片格式转换生成gif动画已经可以实现了,但我们这里要实现的是获取气象雷达图生成GIF。
1.获取数据
获取数据,我们使用pquery
from pyquery importPyQuery as pq
d= pq('http://products.weather.com.cn/product/radar/index/procode/JC_RADAR_AZ9210_JB')
DomTree= d('#slideform #slide option')
2.下载气象雷达png图
想这个用Image.open 直接打开url的文件路径就可以
images.append(Image.open('http://pi.weather.com.cn/i/product/pic/l/sevp_aoc_rdcp_sldas_ebref_az9210_l88_pi_20170621014800000.png'))
那肯定是失败的:
Traceback (most recent call last):
File"E:/project/test2/my.py", line 29, in images.append(Image.open('http://pi.weather.com.cn/i/product/pic/l/sevp_aoc_rdcp_sldas_ebref_az9210_l88_pi_20170621014800000.png'))
File"C:\Python36\lib\site-packages\PIL\Image.py", line 2410, inopen
fp= builtins.open(filename, "rb")
OSError: [Errno22] Invalid argument: 'http://pi.weather.com.cn/i/product/pic/l/sevp_aoc_rdcp_sldas_ebref_az9210_l88_pi_20170621014800000.png'
异想天开呀!!!
imageio支持url文件路径 参考: http://imageio.readthedocs.io/en/latest/examples.html
importimageioimportvisvis as vv
im= imageio.imread('http://upload.wikimedia.org/wikipedia/commons/d/de/Wikipedia_Logo_1.0.png')
vv.imshow(im)
使用requests 库保存图片
importrequests
r= requests.get('http://pi.weather.com.cn/i/product/pic/l/sevp_aoc_rdcp_sldas_ebref_az9210_l88_pi_20170621014800000.png', timeout=3)
file= open('b1.png', 'wb')
size=file.write(r.content)
file.close()
3.生成气象雷达GIF图
python 生成gif在上面我们已经说到两种方法,一种是imageio 另一种是PIL自带save_all,这里我们直接写一个类封装方法
源码如下:
#-*- coding: UTF8 -*-
importrequestsfrom pyquery importPyQuery as pqimportos, sysimportimageiofrom PIL importImage'''天气预报.gif 生成class'''
classweatherForecast():def __init__(self, weatherSite, path, endpng, savemodel):
self.savemodel=savemodelif notos.path.exists(path):
os.makedirs(path)defgetPic(self):'''获取资源'''
print('获取pic')
d=pq(weatherSite)
DomTree= d('#slideform #slide option') #获取DOM节点option 标签
num = 100
for bigpic inDomTree.items():
pic= bigpic.attr('bigpic') #获取bigpic 属性指
num += 1self.download(pic,'a' + str(num) + '.png') #下载pic
print('pic下载成功,共下载' + str(num - 100) + '个png')
self.download(endpng,'a1200.png') #下载end.png
self.download(endpng, 'a1201.png')
self.download(endpng,'a1202.png')
self.download(endpng,'a1203.png')defdownload(self, url, fname):'''下载pic
:return images size'''size=0try:
r= requests.get(url, timeout=3)
file= open(path + fname, 'wb')
size=file.write(r.content)
file.close()except:pass
returnsizedefgetGIF(self):'''生成gif'''images=[]print('执行开始')
self.getPic()#获取图片资源
filenames = sorted(fn for fn in os.listdir(path) if fn.endswith('.png'))if self.savemodel == 1: #imageio方法
for filename infilenames:
images.append(imageio.imread(path+filename))print('执行conversion操作')
imageio.mimsave('weather.gif', images, duration=0.5, loop=1) #duration 每帧间隔时间,loop 循环次数
print('完成……')elif self.savemodel == 2: #PIL 方法
imN = 1
for filename infilenames:if imN == 1: #执行一次 im的open操作,PIL在保存gif之前,必须先打开一个生成的帧,默认第一个frame的大小、调色
im = Image.open(path +filename)
imN= 2images.append(Image.open(path+filename))print('执行conversion操作')
im.save('weather.gif', save_all=True, append_images=images, loop=1, duration=500,
comment=b"this is my weather.gif")print('完成……')'''注:loop循环次数在浏览器有效果,用看图软件不起作用'''
if __name__ == "__main__":
weatherSite= "http://products.weather.com.cn/product/radar/index/procode/JC_RADAR_AZ9210_JB" #上海南汇
path = 'images/' #png 图片存储位置
endpng = 'http://images.cnblogs.com/cnblogs_com/dcb3688/982266/o_end.png' #因gif是循环播放,end png 区分新loop
savemodel = 1 #1:imageio保存图片, 2:PIL保存图片
weatherForecast =weatherForecast(weatherSite, path, endpng, savemodel)
weatherForecast.getGIF()
sys.exit()
也可以修改gif尺寸大小,先修改png大小
defdownload(self, url, fname):'''下载pic
:return images size'''size=0try:
r= requests.get(url, timeout=3)
file= open(path + fname, 'wb')
size=file.write(r.content)
file.close()#修改图片大小,原:x=640*y=480 = 320*240
ima = Image.open(path +fname)
(x, y)= ima.size #read image size
x_s = 320y_s= int((y * x_s) / x) ##calc height based on standard width
out = ima.resize((x_s, y_s), Image.ANTIALIAS) #resize image with high-quality
out.save(path +fname)except:pass
return size
images目录
生成气象雷达图gif
4.外部访问气象雷达图
脚步写好了,如何让别人也能访问呢,直接仍到公网IP的website目录就行了,然后写一个crontab定时脚步,每5分钟生成一次
*/5 * * * * python /home/wwwroot/www/web/static/weather/weather_forecast.py #每5分钟执行天气查询脚本
在这里,如果执行crontab定时脚步,代码生成的gif就要指定位置,否则生成的gif会在/root 目录里面
imageio.mimsave('/home/wwwroot/www/web/static/weather/weather.gif', images, duration=0.5, loop=1) # duration 每帧间隔时间,loop 循环次数