Python實現爬取天氣數據並可視化分析

今天我們分享一個小案例,獲取天氣數據,進行可視化分析,帶你直觀瞭解天氣情況!

核心功能設計

總體來說,我們需要先對中國天氣網中的天氣數據進行爬取,保存為csv文件,並將這些數據進行可視化分析展示。

拆解需求,大致可以整理出我們需要分為以下幾步完成:

1.通過爬蟲獲取中國天氣網7.20-7.21的降雨數據,包括城市,風力方向,風級,降水量,相對濕度,空氣質量。

2.對獲取的天氣數據進行預處理,分析河南的風力等級和風向,繪制風向風級雷達圖。

3.根據獲取的溫度和濕度繪制溫濕度相關性分析圖,進行溫度、濕度對比分析。

4.根據獲取的各城市的降雨量,可視化近24小時的每小時時段降水情況。

5.繪制各城市24小時的累計降雨量。

實現步驟

爬取數據

首先我們需要獲取各個城市的降雨數據,通過對中國天氣網網址分析發現,城市的天氣網址為:http://www.weather.com.cn/weather/101180101.shtml。

根據對數據分析,返回的json格式數據,不難發現:

101180101就是代表城市編號- 7天的天氣預報數據信息在div標簽中並且id=“7d”- 日期、天氣、溫度、風級等信息都在ul和li標簽 網頁結構我們上面已經分析好瞭,那麼我們就可以來動手爬取所需要的數據瞭。獲取到所有的數據資源之後,可以把這些數據保存下來。

請求網站

天氣網的網址:http://www.weather.com.cn/weather/101180101.shtml。如果想爬取不同的地區隻需修改最後的101180101地區編號,前面的weather代表是7天的網頁。

def getHTMLtext(url):
 """請求獲得網頁內容"""
 try:
  r = requests.get(url, timeout = 30)
  r.raise_for_status()
  r.encoding = r.apparent_encoding
  print("Success")
  return r.text
 except:
  print("Fail")
  return" "

處理數據

采用BeautifulSoup庫對剛剛獲取的字符串進行數據提取。獲取我們需要的風力方向,風級,降水量,相對濕度,空氣質量等。

def get_content(html,cityname):
 """處理得到有用信息保存數據文件"""
 final = []          # 初始化一個列表保存數據
 bs = BeautifulSoup(html, "html.parser")  # 創建BeautifulSoup對象
 body = bs.body
 data = body.find('div', {<!-- -->'id': '7d'})    # 找到div標簽且id = 7d
 # 下面爬取當天的數據
 data2 = body.find_all('div',{<!-- -->'class':'left-div'})
 text = data2[2].find('script').string
 text = text[text.index('=')+1 :-2]   # 移除改var data=將其變為json數據
 jd = json.loads(text)
 dayone = jd['od']['od2']     # 找到當天的數據
 final_day = []           # 存放當天的數據
 count = 0
 for i in dayone:
  temp = []
  if count &lt;=23:
   temp.append(i['od21'])     # 添加時間
   temp.append(cityname+'市')   # 添加城市
   temp.append(i['od22'])     # 添加當前時刻溫度
   temp.append(i['od24'])     # 添加當前時刻風力方向
   temp.append(i['od25'])     # 添加當前時刻風級
   temp.append(i['od26'])     # 添加當前時刻降水量
   temp.append(i['od27'])     # 添加當前時刻相對濕度
   temp.append(i['od28'])     # 添加當前時刻控制質量
#    print(temp)
   final_day.append(temp)
   data_all.append(temp)
  count = count +1
 # 下面爬取24h的數據
 ul = data.find('ul')                     # 找到所有的ul標簽
 li = ul.find_all('li')                   # 找到左右的li標簽
 i = 0                                    # 控制爬取的天數
 for day in li:                          # 遍歷找到的每一個li
     if i &lt; 7 and i &gt; 0:
         temp = []                        # 臨時存放每天的數據
         date = day.find('h1').string     # 得到日期
         date = date[0:date.index('日')]  # 取出日期號
         temp.append(date)
         inf = day.find_all('p')          # 找出li下面的p標簽,提取第一個p標簽的值,即天氣
         temp.append(inf[0].string)

         tem_low = inf[1].find('i').string   # 找到最低氣溫

         if inf[1].find('span') is None:   # 天氣預報可能沒有最高氣溫
             tem_high = None
         else:
             tem_high = inf[1].find('span').string  # 找到最高氣溫
         temp.append(tem_low[:-1])
         if tem_high[-1] == '℃':
          temp.append(tem_high[:-1])
         else:
          temp.append(tem_high)

         wind = inf[2].find_all('span')  # 找到風向
         for j in wind:
          temp.append(j['title'])

         wind_scale = inf[2].find('i').string # 找到風級
         index1 = wind_scale.index('級')
         temp.append(int(wind_scale[index1-1:index1]))
         final.append(temp)
     i = i + 1
 return final_day,final

城市的天氣數據拿到瞭,同理我們可以根據不同的地區編號獲取河南省各個地級市的天氣數據。

Citycode = {<!-- --> "鄭州": "101180101",
             "新鄉": "101180301",
             "許昌": "101180401",
             "平頂山": "101180501",
             "信陽": "101180601",
             "南陽": "101180701",
             "開封": "101180801",
             "洛陽": "101180901",
             "商丘": "101181001",
             "焦作": "101181101",
             "鶴壁": "101181201",
             "濮陽": "101181301",
             "周口": "101181401",
             "漯河": "101181501",
             "駐馬店": "101181601",
             "三門峽": "101181701",
             "濟源": "101181801",
             "安陽": "101180201"}
citycode_lists = list(Citycode.items())
for city_code in citycode_lists:
    city_code = list(city_code)
    print(city_code)
    citycode = city_code[1]
    cityname = city_code[0]
    url1 = 'http://www.weather.com.cn/weather/'+citycode+ '.shtml'    # 24h天氣中國天氣網
 html1 = getHTMLtext(url1)
 data1, data1_7 = get_content(html1,cityname)  # 獲得1-7天和當天的數據

存儲數據

def write_to_csv(file_name, data, day=14):
 """保存為csv文件"""
 with open(file_name, 'a', errors='ignore', newline='') as f:
  if day == 14:
   header = ['日期','城市','天氣','最低氣溫','最高氣溫','風向1','風向2','風級']
  else:
   header = ['小時','城市','溫度','風力方向','風級','降水量','相對濕度','空氣質量']
  f_csv = csv.writer(f)
  f_csv.writerow(header)
  f_csv.writerows(data)
write_to_csv('河南天氣.csv',data_all,1)

這樣我們就可以把全省的各個地級市天氣數據保存下來瞭。

風向風級雷達圖

統計全省的風力和風向,因為風力風向使用極坐標的方式展現比較清晰,所以我們采用極坐標的方式展現一天的風力風向圖,將圓分為8份,每一份代表一個風向,半徑代表平均風力,並且隨著風級增高,藍色加深。

def wind_radar(data):
 """風向雷達圖"""
 wind = list(data['風力方向'])
 wind_speed = list(data['風級'])
 for i in range(0,24):
  if wind[i] == "北風":
   wind[i] = 90
  elif wind[i] == "南風":
   wind[i] = 270
  elif wind[i] == "西風":
   wind[i] = 180
  elif wind[i] == "東風":
   wind[i] = 360
  elif wind[i] == "東北風":
   wind[i] = 45
  elif wind[i] == "西北風":
   wind[i] = 135
  elif wind[i] == "西南風":
   wind[i] = 225
  elif wind[i] == "東南風":
   wind[i] = 315
 degs = np.arange(45,361,45)
 temp = []
 for deg in degs:
  speed = []
  # 獲取 wind_deg 在指定范圍的風速平均值數據
  for i in range(0,24):
   if wind[i] == deg:
    speed.append(wind_speed[i])
  if len(speed) == 0:
   temp.append(0)
  else:
   temp.append(sum(speed)/len(speed))
 print(temp)
 N = 8
 theta = np.arange(0.+np.pi/8,2*np.pi+np.pi/8,2*np.pi/8)
 # 數據極徑
 radii = np.array(temp)
 # 繪制極區圖坐標系
 plt.axes(polar=True)
 # 定義每個扇區的RGB值(R,G,B),x越大,對應的顏色越接近藍色
 colors = [(1-x/max(temp), 1-x/max(temp),0.6) for x in radii]
 plt.bar(theta,radii,width=(2*np.pi/N),bottom=0.0,color=colors)
 plt.title('河南風級圖--Dragon少年',x=0.2,fontsize=16)
 plt.show()

結果如下:

觀察可以發現,當天的東北風最多,平均風級達到瞭1.75級。

溫濕度相關性分析

我們可以分析溫度和濕度之間是否存在關系,為瞭更加清楚直觀地驗證,可以使用離散點plt.scatter()方法將溫度為橫坐標、濕度為縱坐標,每個時刻的點在圖中點出來,並且計算相關系數。

def calc_corr(a, b):
 """計算相關系數"""
 a_avg = sum(a)/len(a)
 b_avg = sum(b)/len(b)
 cov_ab = sum([(x - a_avg)*(y - b_avg) for x,y in zip(a, b)])
 sq = math.sqrt(sum([(x - a_avg)**2 for x in a])*sum([(x - b_avg)**2 for x in b]))
 corr_factor = cov_ab/sq
 return corr_factor


def corr_tem_hum(data):
 """溫濕度相關性分析"""
 tem = data['溫度']
 hum = data['相對濕度']
 plt.scatter(tem,hum,color='blue')
 plt.title("溫濕度相關性分析圖--Dragon少年")
 plt.xlabel("溫度/℃")
 plt.ylabel("相對濕度/%")
 # plt.text(20,40,"相關系數為:"+str(calc_corr(tem,hum)),fontdict={'size':'10','color':'red'})
 plt.show()
 print("相關系數為:"+str(calc_corr(tem,hum)))

結果如下:

觀察可以發現,一天的溫度和濕度具有強烈的相關性,呈負相關。當溫度較低時,空氣中水分含量較多,濕度自然較高,而溫度高時空氣中可容納的水汽增大,相對濕度隨之降低,但其實空氣中的水汽往往是增加的。

24小時內每小時時段降水

from pyecharts import options as opts
from pyecharts.charts import Map,Timeline
#定義一個timeline和map的組合圖
def timeline_map(data):
    tl = Timeline().add_schema(play_interval =300,height=40,is_rewind_play=False,orient = "horizontal",is_loop_play = True,is_auto_play=False)#設置播放速度、是否循環播放等參數
    for h in time_line_final:
        x =data[data["小時"]==h]['城市'].values.tolist() #選取指定城市
        y=data[data["小時"]==h]['降水量'].values.tolist() #選取時間的降水量
        map_shape = (
            Map()
            .add("{}h時降水量(mm)".format(h),[list(z) for z in zip(x, y)],"河南") #打包輸入地區及對應降水量數據
            .set_series_opts(label_opts=opts.LabelOpts("{b}")) #配置系列參數,{b}為顯示地區數據
            .set_global_opts(
                title_opts=opts.TitleOpts(title="河南省降雨分佈--Dragon少年"), #全局參數中設置標題
                visualmap_opts=opts.VisualMapOpts(max_=300,  #設置映射配置項的最大值
                                                  is_piecewise=True, #設置是否為分段顯示
                                                  pos_top = "60%", #映射配置項距圖片上部的距離
                                                  pieces=[
                                                        {"min": 101, "label": '>100ml', "color": "#FF0000"},  # 分段指定顏色及名稱
                                                        {"min": 11, "max": 50, "label": '11-50ml', "color": "#FF3333"},
                                                        {"min": 6, "max": 10, "label": '6-10ml', "color": "#FF9999"},
                                                        {"min": 0.1, "max": 5, "label": '0.1-5ml', "color": "#FFCCCC"}])
        ))
        tl.add(map_shape, "{}h".format(h)) #將不同日期的數據加入到timeline中
    return tl
timeline_map(data).render("rainfall.html")

24小時累計降雨量

from pyecharts import options as opts
from pyecharts.charts import Map,Timeline
#定義一個timeline和map的組合圖
time_line_final = list(data1['小時'].iloc[0:24])
def timeline_map(data1):
    tl = Timeline().add_schema(play_interval =200,height=40,is_rewind_play=False,orient = "horizontal",is_loop_play = True,is_auto_play=True)#設置播放速度、是否循環播放等參數
    for h in time_line_final:
        x =data1[data1["小時"]==h]['城市'].values.tolist() #選取指定城市
        y=data1[data1["小時"]==h]['降水量'].values.tolist() #選取時間的降水量
        map_shape1 = (
            Map()
            .add("{}h時累計降水量(mm)".format(h),[list(z) for z in zip(x, y)],"河南") #打包輸入地區及對應降水量數據
            .set_series_opts(label_opts=opts.LabelOpts("{b}")) #配置系列參數,{b}為顯示地區數據
            .set_global_opts(
                title_opts=opts.TitleOpts(title="河南省累計降雨分佈--Dragon少年"), #全局參數中設置標題
                visualmap_opts=opts.VisualMapOpts(max_=300,  #設置映射配置項的最大值
                                                  is_piecewise=True, #設置是否為分段顯示
                                                  pos_top = "60%", #映射配置項距圖片上部的距離
                                                  pieces=[
                                                        {"min": 251, "label": '特大暴雨', "color": "#800000"},  # 分段指定顏色及名稱
                                                        {"min": 101, "max": 250, "label": '暴雨', "color": "#FF4500"},
                                                        {"min": 51, "max": 100, "label": '暴雨', "color": "#FF7F50"},
                                                        {"min": 25, "max": 50, "label": '大雨', "color": "#FFFF00"},
                                                        {"min": 10, "max": 25, "label": '中雨', "color": "#1E90FF"},
                                                        {"min": 0.1, "max": 9.9, "label": '小雨', "color": "#87CEFA"}])
        ))
        tl.add(map_shape1, "{}h".format(h)) #將不同日期的數據加入到timeline中
    return tl
timeline_map(data1).render("rainfalltoall_1.html")

至此,天氣數據分析可視化就完成啦

以上就是Python實現爬取天氣數據並可視化分析的詳細內容,更多關於Python爬取天氣數據的資料請關註WalkonNet其它相關文章!

推薦閱讀: