先看知乎上面的一個連接
用Python寫過哪些【腦洞大開】的小工具?
https://www.zhihu.com/question/33646570/answer/157806339
這個哥們通過爬氣象網站的氣象雷達圖,生成一個gif的動態圖。非常有趣且很實用,那咱也實現下。
首先先了解下什么是幀,什么是GIF http://baike.baidu.com/item/GIF/217778
我們先實現一個從GIF提取幀的代碼
我們這有個gif

代碼如下:
from PIL import Image import sys def processImage(infile): try: im = Image.open(infile) except IOError: 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 += 1 im.seek(im.tell() + 1) except EOFError: 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)
import matplotlib.pyplot as plt import imageio,os images = [] filenames=sorted((fn for fn in os.listdir('.') if fn.endswith('.png'))) for filename in filenames: images.append(imageio.imread(filename)) imageio.mimsave('gif.gif', images,duration=1)
OK! gif生成了!
imageio查看參數: http://imageio.readthedocs.io/
imageio.help('gif')

其實,PIL自身也有一個save方法,里面有一個‘save_all’ 參數,意思就是save多個,當format指定為gif時,生成的便是gif的動畫
from PIL import Image 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.獲取數據
中國氣象網網站: http://products.weather.com.cn/product/radar/index/procode/JC_RADAR_AZ9210_JB 這里是上海南匯雷達站點圖
獲取數據,我們使用pquery
from pyquery import PyQuery 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 <module> 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, in open fp = builtins.open(filename, "rb") OSError: [Errno 22] 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
import imageio import visvis as vv im = imageio.imread('http://upload.wikimedia.org/wikipedia/commons/d/de/Wikipedia_Logo_1.0.png') vv.imshow(im)
使用requests 庫保存圖片
import requests 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 -*- import requests from pyquery import PyQuery as pq import os, sys import imageio from PIL import Image ''' 天氣預報.gif 生成class ''' class weatherForecast(): def __init__(self, weatherSite, path, endpng, savemodel): self.savemodel = savemodel if not os.path.exists(path): os.makedirs(path) def getPic(self): ''' 獲取資源 ''' print('獲取pic') d = pq(weatherSite) DomTree = d('#slideform #slide option') # 獲取DOM節點option 標簽 num = 100 for bigpic in DomTree.items(): pic = bigpic.attr('bigpic') # 獲取bigpic 屬性指 num += 1 self.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') def download(self, url, fname): ''' 下載pic :return images size ''' size = 0 try: r = requests.get(url, timeout=3) file = open(path + fname, 'wb') size = file.write(r.content) file.close() except: pass return size def getGIF(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 in filenames: 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 in filenames: if imN == 1: # 執行一次 im的open操作,PIL在保存gif之前,必須先打開一個生成的幀,默認第一個frame的大小、調色 im = Image.open(path + filename) imN = 2 images.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大小
def download(self, url, fname): ''' 下載pic :return images size ''' size = 0 try: 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 = 320 y_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 循環次數

