Python實(shí)現(xiàn)爬取天氣數(shù)據(jù)并可視化分析
今天我們分享一個(gè)小案例,獲取天氣數(shù)據(jù),進(jìn)行可視化分析,帶你直觀了解天氣情況!
核心功能設(shè)計(jì)
總體來說,我們需要先對(duì)中國(guó)天氣網(wǎng)中的天氣數(shù)據(jù)進(jìn)行爬取,保存為csv文件,并將這些數(shù)據(jù)進(jìn)行可視化分析展示。
拆解需求,大致可以整理出我們需要分為以下幾步完成:
1.通過爬蟲獲取中國(guó)天氣網(wǎng)7.20-7.21的降雨數(shù)據(jù),包括城市,風(fēng)力方向,風(fēng)級(jí),降水量,相對(duì)濕度,空氣質(zhì)量。
2.對(duì)獲取的天氣數(shù)據(jù)進(jìn)行預(yù)處理,分析河南的風(fēng)力等級(jí)和風(fēng)向,繪制風(fēng)向風(fēng)級(jí)雷達(dá)圖。
3.根據(jù)獲取的溫度和濕度繪制溫濕度相關(guān)性分析圖,進(jìn)行溫度、濕度對(duì)比分析。
4.根據(jù)獲取的各城市的降雨量,可視化近24小時(shí)的每小時(shí)時(shí)段降水情況。
5.繪制各城市24小時(shí)的累計(jì)降雨量。
實(shí)現(xiàn)步驟
爬取數(shù)據(jù)
首先我們需要獲取各個(gè)城市的降雨數(shù)據(jù),通過對(duì)中國(guó)天氣網(wǎng)網(wǎng)址分析發(fā)現(xiàn),城市的天氣網(wǎng)址為:http://www.weather.com.cn/weather/101180101.shtml。

根據(jù)對(duì)數(shù)據(jù)分析,返回的json格式數(shù)據(jù),不難發(fā)現(xiàn):
101180101就是代表城市編號(hào)- 7天的天氣預(yù)報(bào)數(shù)據(jù)信息在div標(biāo)簽中并且id=“7d”- 日期、天氣、溫度、風(fēng)級(jí)等信息都在ul和li標(biāo)簽 網(wǎng)頁(yè)結(jié)構(gòu)我們上面已經(jīng)分析好了,那么我們就可以來動(dòng)手爬取所需要的數(shù)據(jù)了。獲取到所有的數(shù)據(jù)資源之后,可以把這些數(shù)據(jù)保存下來。
請(qǐng)求網(wǎng)站
天氣網(wǎng)的網(wǎng)址:http://www.weather.com.cn/weather/101180101.shtml。如果想爬取不同的地區(qū)只需修改最后的101180101地區(qū)編號(hào),前面的weather代表是7天的網(wǎng)頁(yè)。
def?getHTMLtext(url):
?"""請(qǐng)求獲得網(wǎng)頁(yè)內(nèi)容"""
?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"?"

處理數(shù)據(jù)
采用BeautifulSoup庫(kù)對(duì)剛剛獲取的字符串進(jìn)行數(shù)據(jù)提取。獲取我們需要的風(fēng)力方向,風(fēng)級(jí),降水量,相對(duì)濕度,空氣質(zhì)量等。
def?get_content(html,cityname):
?"""處理得到有用信息保存數(shù)據(jù)文件"""
?final?=?[]??????????#?初始化一個(gè)列表保存數(shù)據(jù)
?bs?=?BeautifulSoup(html,?"html.parser")??#?創(chuàng)建BeautifulSoup對(duì)象
?body?=?bs.body
?data?=?body.find('div',?{<!--?-->'id':?'7d'})????#?找到div標(biāo)簽且id?=?7d
?#?下面爬取當(dāng)天的數(shù)據(jù)
?data2?=?body.find_all('div',{<!--?-->'class':'left-div'})
?text?=?data2[2].find('script').string
?text?=?text[text.index('=')+1?:-2]???#?移除改var?data=將其變?yōu)閖son數(shù)據(jù)
?jd?=?json.loads(text)
?dayone?=?jd['od']['od2']?????#?找到當(dāng)天的數(shù)據(jù)
?final_day?=?[]???????????#?存放當(dāng)天的數(shù)據(jù)
?count?=?0
?for?i?in?dayone:
??temp?=?[]
??if?count?<=23:
???temp.append(i['od21'])?????#?添加時(shí)間
???temp.append(cityname+'市')???#?添加城市
???temp.append(i['od22'])?????#?添加當(dāng)前時(shí)刻溫度
???temp.append(i['od24'])?????#?添加當(dāng)前時(shí)刻風(fēng)力方向
???temp.append(i['od25'])?????#?添加當(dāng)前時(shí)刻風(fēng)級(jí)
???temp.append(i['od26'])?????#?添加當(dāng)前時(shí)刻降水量
???temp.append(i['od27'])?????#?添加當(dāng)前時(shí)刻相對(duì)濕度
???temp.append(i['od28'])?????#?添加當(dāng)前時(shí)刻控制質(zhì)量
#????print(temp)
???final_day.append(temp)
???data_all.append(temp)
??count?=?count?+1
?#?下面爬取24h的數(shù)據(jù)
?ul?=?data.find('ul')?????????????????????#?找到所有的ul標(biāo)簽
?li?=?ul.find_all('li')???????????????????#?找到左右的li標(biāo)簽
?i?=?0????????????????????????????????????#?控制爬取的天數(shù)
?for?day?in?li:??????????????????????????#?遍歷找到的每一個(gè)li
?????if?i?<?7?and?i?>?0:
?????????temp?=?[]????????????????????????#?臨時(shí)存放每天的數(shù)據(jù)
?????????date?=?day.find('h1').string?????#?得到日期
?????????date?=?date[0:date.index('日')]??#?取出日期號(hào)
?????????temp.append(date)
?????????inf?=?day.find_all('p')??????????#?找出li下面的p標(biāo)簽,提取第一個(gè)p標(biāo)簽的值,即天氣
?????????temp.append(inf[0].string)
?????????tem_low?=?inf[1].find('i').string???#?找到最低氣溫
?????????if?inf[1].find('span')?is?None:???#?天氣預(yù)報(bào)可能沒有最高氣溫
?????????????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')??#?找到風(fēng)向
?????????for?j?in?wind:
??????????temp.append(j['title'])
?????????wind_scale?=?inf[2].find('i').string?#?找到風(fēng)級(jí)
?????????index1?=?wind_scale.index('級(jí)')
?????????temp.append(int(wind_scale[index1-1:index1]))
?????????final.append(temp)
?????i?=?i?+?1
?return?final_day,final
城市的天氣數(shù)據(jù)拿到了,同理我們可以根據(jù)不同的地區(qū)編號(hào)獲取河南省各個(gè)地級(jí)市的天氣數(shù)據(jù)。
Citycode?=?{<!--?-->?"鄭州":?"101180101",
?????????????"新鄉(xiāng)":?"101180301",
?????????????"許昌":?"101180401",
?????????????"平頂山":?"101180501",
?????????????"信陽(yáng)":?"101180601",
?????????????"南陽(yáng)":?"101180701",
?????????????"開封":?"101180801",
?????????????"洛陽(yáng)":?"101180901",
?????????????"商丘":?"101181001",
?????????????"焦作":?"101181101",
?????????????"鶴壁":?"101181201",
?????????????"濮陽(yáng)":?"101181301",
?????????????"周口":?"101181401",
?????????????"漯河":?"101181501",
?????????????"駐馬店":?"101181601",
?????????????"三門峽":?"101181701",
?????????????"濟(jì)源":?"101181801",
?????????????"安陽(yáng)":?"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天氣中國(guó)天氣網(wǎng)
?html1?=?getHTMLtext(url1)
?data1,?data1_7?=?get_content(html1,cityname)??#?獲得1-7天和當(dāng)天的數(shù)據(jù)
存儲(chǔ)數(shù)據(jù)
def?write_to_csv(file_name,?data,?day=14):
?"""保存為csv文件"""
?with?open(file_name,?'a',?errors='ignore',?newline='')?as?f:
??if?day?==?14:
???header?=?['日期','城市','天氣','最低氣溫','最高氣溫','風(fēng)向1','風(fēng)向2','風(fēng)級(jí)']
??else:
???header?=?['小時(shí)','城市','溫度','風(fēng)力方向','風(fēng)級(jí)','降水量','相對(duì)濕度','空氣質(zhì)量']
??f_csv?=?csv.writer(f)
??f_csv.writerow(header)
??f_csv.writerows(data)
write_to_csv('河南天氣.csv',data_all,1)這樣我們就可以把全省的各個(gè)地級(jí)市天氣數(shù)據(jù)保存下來了。

風(fēng)向風(fēng)級(jí)雷達(dá)圖
統(tǒng)計(jì)全省的風(fēng)力和風(fēng)向,因?yàn)轱L(fēng)力風(fēng)向使用極坐標(biāo)的方式展現(xiàn)比較清晰,所以我們采用極坐標(biāo)的方式展現(xiàn)一天的風(fēng)力風(fēng)向圖,將圓分為8份,每一份代表一個(gè)風(fēng)向,半徑代表平均風(fēng)力,并且隨著風(fēng)級(jí)增高,藍(lán)色加深。
def?wind_radar(data):
?"""風(fēng)向雷達(dá)圖"""
?wind?=?list(data['風(fēng)力方向'])
?wind_speed?=?list(data['風(fēng)級(jí)'])
?for?i?in?range(0,24):
??if?wind[i]?==?"北風(fēng)":
???wind[i]?=?90
??elif?wind[i]?==?"南風(fēng)":
???wind[i]?=?270
??elif?wind[i]?==?"西風(fēng)":
???wind[i]?=?180
??elif?wind[i]?==?"東風(fēng)":
???wind[i]?=?360
??elif?wind[i]?==?"東北風(fēng)":
???wind[i]?=?45
??elif?wind[i]?==?"西北風(fēng)":
???wind[i]?=?135
??elif?wind[i]?==?"西南風(fēng)":
???wind[i]?=?225
??elif?wind[i]?==?"東南風(fēng)":
???wind[i]?=?315
?degs?=?np.arange(45,361,45)
?temp?=?[]
?for?deg?in?degs:
??speed?=?[]
??#?獲取?wind_deg?在指定范圍的風(fēng)速平均值數(shù)據(jù)
??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)
?#?數(shù)據(jù)極徑
?radii?=?np.array(temp)
?#?繪制極區(qū)圖坐標(biāo)系
?plt.axes(polar=True)
?#?定義每個(gè)扇區(qū)的RGB值(R,G,B),x越大,對(duì)應(yīng)的顏色越接近藍(lán)色
?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('河南風(fēng)級(jí)圖--Dragon少年',x=0.2,fontsize=16)
?plt.show()結(jié)果如下:

觀察可以發(fā)現(xiàn),當(dāng)天的東北風(fēng)最多,平均風(fēng)級(jí)達(dá)到了1.75級(jí)。
溫濕度相關(guān)性分析
我們可以分析溫度和濕度之間是否存在關(guān)系,為了更加清楚直觀地驗(yàn)證,可以使用離散點(diǎn)plt.scatter()方法將溫度為橫坐標(biāo)、濕度為縱坐標(biāo),每個(gè)時(shí)刻的點(diǎn)在圖中點(diǎn)出來,并且計(jì)算相關(guān)系數(shù)。
def?calc_corr(a,?b):
?"""計(jì)算相關(guān)系數(shù)"""
?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):
?"""溫濕度相關(guān)性分析"""
?tem?=?data['溫度']
?hum?=?data['相對(duì)濕度']
?plt.scatter(tem,hum,color='blue')
?plt.title("溫濕度相關(guān)性分析圖--Dragon少年")
?plt.xlabel("溫度/℃")
?plt.ylabel("相對(duì)濕度/%")
?# plt.text(20,40,"相關(guān)系數(shù)為:"+str(calc_corr(tem,hum)),fontdict={'size':'10','color':'red'})
?plt.show()
?print("相關(guān)系數(shù)為:"+str(calc_corr(tem,hum)))
結(jié)果如下:

觀察可以發(fā)現(xiàn),一天的溫度和濕度具有強(qiáng)烈的相關(guān)性,呈負(fù)相關(guān)。當(dāng)溫度較低時(shí),空氣中水分含量較多,濕度自然較高,而溫度高時(shí)空氣中可容納的水汽增大,相對(duì)濕度隨之降低,但其實(shí)空氣中的水汽往往是增加的。
24小時(shí)內(nèi)每小時(shí)時(shí)段降水
from pyecharts import options as opts
from pyecharts.charts import Map,Timeline
#定義一個(gè)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)#設(shè)置播放速度、是否循環(huán)播放等參數(shù)
for h in time_line_final:
x =data[data["小時(shí)"]==h]['城市'].values.tolist() #選取指定城市
y=data[data["小時(shí)"]==h]['降水量'].values.tolist() #選取時(shí)間的降水量
map_shape = (
Map()
.add("{}h時(shí)降水量(mm)".format(h),[list(z) for z in zip(x, y)],"河南") #打包輸入地區(qū)及對(duì)應(yīng)降水量數(shù)據(jù)
.set_series_opts(label_opts=opts.LabelOpts("")) #配置系列參數(shù),為顯示地區(qū)數(shù)據(jù)
.set_global_opts(
title_opts=opts.TitleOpts(title="河南省降雨分布--Dragon少年"), #全局參數(shù)中設(shè)置標(biāo)題
visualmap_opts=opts.VisualMapOpts(max_=300, #設(shè)置映射配置項(xiàng)的最大值
is_piecewise=True, #設(shè)置是否為分段顯示
pos_top = "60%", #映射配置項(xiàng)距圖片上部的距離
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)) #將不同日期的數(shù)據(jù)加入到timeline中
return tl
timeline_map(data).render("rainfall.html")24小時(shí)累計(jì)降雨量
from pyecharts import options as opts
from pyecharts.charts import Map,Timeline
#定義一個(gè)timeline和map的組合圖
time_line_final = list(data1['小時(shí)'].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)#設(shè)置播放速度、是否循環(huán)播放等參數(shù)
for h in time_line_final:
x =data1[data1["小時(shí)"]==h]['城市'].values.tolist() #選取指定城市
y=data1[data1["小時(shí)"]==h]['降水量'].values.tolist() #選取時(shí)間的降水量
map_shape1 = (
Map()
.add("{}h時(shí)累計(jì)降水量(mm)".format(h),[list(z) for z in zip(x, y)],"河南") #打包輸入地區(qū)及對(duì)應(yīng)降水量數(shù)據(jù)
.set_series_opts(label_opts=opts.LabelOpts("")) #配置系列參數(shù),為顯示地區(qū)數(shù)據(jù)
.set_global_opts(
title_opts=opts.TitleOpts(title="河南省累計(jì)降雨分布--Dragon少年"), #全局參數(shù)中設(shè)置標(biāo)題
visualmap_opts=opts.VisualMapOpts(max_=300, #設(shè)置映射配置項(xiàng)的最大值
is_piecewise=True, #設(shè)置是否為分段顯示
pos_top = "60%", #映射配置項(xiàng)距圖片上部的距離
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)) #將不同日期的數(shù)據(jù)加入到timeline中
return tl
timeline_map(data1).render("rainfalltoall_1.html")
至此,天氣數(shù)據(jù)分析可視化就完成啦
以上就是Python實(shí)現(xiàn)爬取天氣數(shù)據(jù)并可視化分析的詳細(xì)內(nèi)容,更多關(guān)于Python爬取天氣數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Python實(shí)戰(zhàn)實(shí)現(xiàn)爬取天氣數(shù)據(jù)并完成可視化分析詳解
- Python?數(shù)據(jù)可視化超詳細(xì)講解折線圖的實(shí)現(xiàn)
- Python?echarts實(shí)現(xiàn)數(shù)據(jù)可視化實(shí)例詳解
- Python?數(shù)據(jù)可視化實(shí)現(xiàn)5種炫酷的動(dòng)態(tài)圖
- 基于Python實(shí)現(xiàn)股票數(shù)據(jù)分析的可視化
- python實(shí)現(xiàn)股票歷史數(shù)據(jù)可視化分析案例
- Python實(shí)現(xiàn)數(shù)據(jù)可視化案例分析
相關(guān)文章
python+selenium select下拉選擇框定位處理方法
今天小編就為大家分享一篇python+selenium select下拉選擇框定位處理方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-08-08
python使用epoll實(shí)現(xiàn)服務(wù)端的方法
今天小編就為大家分享一篇python使用epoll實(shí)現(xiàn)服務(wù)端的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-10-10
python使用pygame框架實(shí)現(xiàn)推箱子游戲
這篇文章主要為大家詳細(xì)介紹了python使用pygame框架實(shí)現(xiàn)推箱子游戲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
使用PowerShell實(shí)現(xiàn)批量修改或替換文件名
這篇文章主要為大家介紹了基于PowerShell語(yǔ)言,對(duì)文件夾中全部文件的名稱加以批量替換、修改的方法,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-04-04
python通過cookie模擬已登錄狀態(tài)的初步研究
對(duì)于那些需要在登錄環(huán)境下進(jìn)行的爬蟲操作,模擬登陸或偽裝已登錄狀態(tài)是一個(gè)剛性需求。這篇文章主要介紹了python通過cookie模擬已登錄狀態(tài)的相關(guān)資料,需要的朋友可以參考下2016-11-11
Python實(shí)現(xiàn)的基數(shù)排序算法原理與用法實(shí)例分析
這篇文章主要介紹了Python實(shí)現(xiàn)的基數(shù)排序算法,簡(jiǎn)單說明了基數(shù)排序的原理并結(jié)合實(shí)例形式分析了Python實(shí)現(xiàn)與使用基數(shù)排序的具體操作技巧,需要的朋友可以參考下2017-11-11

