Python爬取南京市往年天氣預報,使用pyecharts進行分析


上一次分享了使用matplotlib對爬取的豆瓣書籍排行榜進行分析,但是發現python本身自帶的這個繪圖分析庫還是有一些局限,繪圖不夠美觀等,在網上搜索了一波,發現現在有很多的支持python的繪圖庫可以使用,本次嘗試使用pyecharts對爬取的數據進行分析,然后發現這個庫實在是太好用了,生成的庫也很好看,還能生成動態圖,簡直是進行數據分析的一大神器!

pyecharts: pyecharts是一個封裝百度開源圖表庫echarts的包,使用pyecharts可以生成獨立的網頁,也可以在flask、django中集成使用。


 

 本次爬取的首頁地址是:

http://www.tianqihoubao.com/lishi/nanjing.html

 

爬取步驟:

  1. 爬取主網頁,獲取進入每個南京市具體年份月份的天氣數據的鏈接
  2. 爬取上方獲取的具體鏈接的數據
  3. 存儲數據
  4. 對數據進行篩選后使用pyecharts進行分析

話不多說,馬上開始吧!

 

  • 步驟一

從上圖可知,我們需要先獲取進入每個具體月份的鏈接,才能爬取想要的數據,所以首先定義獲取具體鏈接的函數,然后在爬取會方便很多;查看網頁源代碼查找目標所在位置,本次我依然是使用lxml庫來進行數據的爬取(PS:感覺習慣了lxml其他庫就不好用了),這里需要注意的是,我是將獲得的結果一個一個的存入列表,這種方法很笨,但作為菜鳥的我確實不知道其他方法了,還有就是發現爬取的部分鏈接缺了一點,所以又定義了一個函數來補上。

具體代碼如下:           注:轉載代碼請標明出處

 
         
 1 def get_mainurl(url):   #定義獲取月份天氣的詳細url 函數
 2     res = requests.get(url, headers=headers)
 3     main_url = []
 4     if res.status_code == 200:  #判斷請求狀態
 5         selector = etree.HTML(res.text)
 6         htmlurls = selector.xpath('//div[contains(@id,"content")]/div') #循環點
 7         try:
 8             for htmlurl in htmlurls:
 9                 Jan = htmlurl.xpath('ul[1]/li[2]/a/@href')[0]   #一月份天氣url
10                 main_url.append(Jan)    #將網址放入列表中,一個一個放是很蠢的方法,但我也確實不知道其他方法了,下同
11                 Feb = htmlurl.xpath('ul[1]/li[3]/a/@href')[0]   #二月份天氣url
12                 main_url.append(Feb)
13                 Mar = htmlurl.xpath('ul[1]/li[4]/a/@href')[0]   #同上,下類推
14                 main_url.append(Mar)
15                 Apr = htmlurl.xpath('ul[2]/li[2]/a/@href')[0]
16                 main_url.append(Apr)
17                 May = htmlurl.xpath('ul[2]/li[3]/a/@href')[0]
18                 main_url.append(May)
19                 June = htmlurl.xpath('ul[2]/li[4]/a/@href')[0]
20                 main_url.append(June)
21                 July = htmlurl.xpath('ul[3]/li[2]/a/@href')[0]
22                 main_url.append(July)
23                 Aug = htmlurl.xpath('ul[3]/li[3]/a/@href')[0]
24                 main_url.append(Aug)
25                 Sep = htmlurl.xpath('ul[3]/li[4]/a/@href')[0]
26                 main_url.append(Sep)
27                 Oct = htmlurl.xpath('ul[4]/li[2]/a/@href')[0]
28                 main_url.append(Oct)
29                 Nov = htmlurl.xpath('ul[4]/li[3]/a/@href')[0]
30                 main_url.append(Nov)
31                 Dec = htmlurl.xpath('ul[4]/li[4]/a/@href')[0]
32                 main_url.append(Dec)
33 
34                 time.sleep(0.5)     #休眠0.5s
35         except IndexError:
36             pass
37         return main_url     #將存了所有url的列表返回
38     else:
39         pass
40 
41 
42 def link_url(url):      #上面獲取的url是不完整的,此函數使其完整
43     final_urls= []
44     list_urls = get_mainurl(url)
45     for list_url in list_urls:
46         if len(list_url) < 30:      #因為獲取的url有一些少了‘/lishi/’,所以需要判斷一下
47             list_url = 'http://www.tianqihoubao.com/lishi/' + list_url
48             final_urls.append(list_url)
49         else:
50             list_url = 'http://www.tianqihoubao.com' + list_url
51             final_urls.append(list_url)
52     return final_urls
 
         

 

 
  • 步驟二

接下來是獲取所需的數據,遍歷所在節點就行了,需要注意的是要跳過第一個節點,因為其內部沒有內容。

代碼如下:

def get_infos(detail_url):      #爬取月份天氣詳細數據函數
    main_res = requests.get(detail_url, headers=headers)
    main_sele = etree.HTML(main_res.text)
    main_infos = main_sele.xpath('//div[@class="hd"]/div[1]/table/tr')
    i = True
    try:
        for info in main_infos:
            if i:       #此處i的作用是跳過第一次循環,因為第一個是非天氣數據
                i = False
                continue
            else:
                date = info.xpath('td[1]/a/text()')[0].replace("\r\n", '').replace(' ', '')     #去掉換行符、空格等,下同
                weather = info.xpath('td[2]/text()')[0].replace("\r\n", '').replace(' ', '')
                temps = info.xpath('td[3]/text()')[0].replace('\r\n', '').replace(' ', '')
                clouds = info.xpath('td[4]/text()')[0].replace("\r\n", '').replace(' ', '')
                with open('Nanjing.csv', 'a+', newline='', encoding='utf-8')as fp:      #存入csv文件
                    writer = csv.writer(fp)
                    writer.writerow((date, weather, temps, clouds))
    except IndexError:
        pass

 

  • 步驟三

接下來執行主程序存儲就行了,使用了多進程來爬取加快速度,所以爬取的數據排列可能不按順序,使用wps或excel自行排序即可。

下方附上剩余代碼:

import requests
from lxml import etree
import time
import csv
from multiprocessing import Pool

#請求頭
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}




if __name__ == '__main__':      #執行主程序
    url = 'http://www.tianqihoubao.com/lishi/nanjing.html'  #獲取月份天氣url的網址
    get_mainurl(url)
    details = link_url(url)
    with open('Nanjing.csv', 'a+', newline='', encoding='utf-8')as ff:      #寫入第一行作為表頭
        writer = csv.writer(ff)
        writer.writerow(('日期', '天氣狀況', '氣溫', '風力風向'))
    pool = Pool(processes=4)        #使用多進程爬取
    pool.map(get_infos, details)    #需要注意爬取結果並不是按順序的,可以用excel進行排序

部分數據如下:

 

  • 步驟四

進行數據分析之前,先用pandas的read_csv()方法將數據讀出,然后將2011-2018年的溫度和天氣狀況提取出來進行分析,這里溫度需要將數字提取出來,天氣狀況需要將  ‘/’去掉,還有因為一天的天氣數據是多個的(例如一天氣溫有最高溫和最低溫),所以后面分析時發現數據量大於8年總天數,這是正常的。

 由於我也是第一次使用pyecharts,所以話不多說,直接上代碼:

  1 import pandas as pd
  2 from pyecharts import Line, Pie, Page, Bar
  3 
  4 
  5 page = Page(page_title='南京氣溫分析')    #page 使多個圖位於一個網頁,網頁名
  6 
  7 pd.set_option('display.max_rows', None) #設置使dataframe 所有行都顯示
  8 df = pd.read_csv('Nanjing.csv')     #讀取天氣數據
  9 
 10 #獲取最高氣溫
 11 Max_temps = []
 12 for max_data in df['氣溫']:
 13     Max_temps.append(int(max_data[0:2].replace('','')))
 14 Max_temps = Max_temps[:-109]
 15 
 16 #獲取最低氣溫
 17 Low_temps = []
 18 for low_data in df['氣溫']:
 19     Low_temps.append(int(low_data[-3:-1].replace('/', '')))
 20 Low_temps = Low_temps[:-109]
 21 
 22 #獲取2011年一月氣溫數據
 23 attr = ['{}號'.format(str(i))for i in range(1,32)]
 24 Jan_Htemps = Max_temps[:31]
 25 Jan_Ltemps = Low_temps[:31]
 26 #繪制氣溫折線圖
 27 line = Line('南京市2011年一月氣溫變化')   #賦予將折線圖對象, 命名
 28 line.add('當日最高氣溫', attr, Jan_Htemps, mark_point=['average', 'max', 'min'],  #顯示平均、最大/小值
 29          mark_point_symbol='diamond',   #特殊點用鑽石形狀顯示
 30          mark_point_textcolor='red',    #標注點顏色
 31          is_smooth=True     #圖像光滑
 32          )
 33 line.add('當日最低氣溫', attr, Jan_Ltemps, mark_point=['average', 'max', 'min'],
 34          mark_point_symbol='arrow',
 35          mark_point_textcolor='blue'
 36          )
 37 line.use_theme('dark')  #背景顏色
 38 line.show_config()      #調試輸出pyecharts的js配置信息
 39 page.add_chart(line)    #添加到page
 40 
 41 #統計2011-2018年的每天最高溫的氣溫分布情況,分四個階梯
 42 Hzero_down = Hthrity_up = Hzup_fifdown = Hfifup_thrdown = 0
 43 for i in Max_temps:
 44     if i <= 0:
 45         Hzero_down += 1
 46     elif i<=15:
 47         Hzup_fifdown += 1
 48     elif i<=30:
 49         Hfifup_thrdown += 1
 50     else:
 51         Hthrity_up +=1
 52 
 53 #統計2011-2018年的每天最高溫的氣溫分布情況分,分四個階層
 54 Lfiv_down = L25_up = Lfiv_tendown = Ltenup_25down = 0
 55 for i in Low_temps:
 56     if i <= -5:
 57         Lfiv_down += 1
 58     elif i<=10:
 59         Lfiv_tendown += 1
 60     elif i<=25:
 61         Ltenup_25down += 1
 62     else:
 63         L25_up +=1
 64 
 65 #繪圖
 66 attr2 = ['0℃及以下', '0-15℃', '15-30℃', '30℃及以上']  #標簽屬性
 67 H_data = [Hzero_down, Hzup_fifdown, Hfifup_thrdown, Hthrity_up]     #數據
 68 pie = Pie('南京市2011年-2018年每日最高氣溫分布', title_pos='center', title_color='red') #繪制餅圖,標題位於中間,標題顏色
 69 pie.add('',attr2, H_data, is_label_show=True,   #展示標簽
 70         legend_pos='right', legend_orient='vertical',   #標簽位置,標簽排列
 71         label_text_color=True, legend_text_color=True,   #標簽顏色
 72         )
 73 pie.show_config()
 74 page.add_chart(pie, name='餅圖')
 75 
 76 #繪制環形圖
 77 attr3 = ['-5℃及以下', '-5-10℃', '10-25℃', '25℃及以上']
 78 L_data = [Lfiv_down, Lfiv_tendown, Ltenup_25down, L25_up]
 79 pie2 = Pie('南京市2011年-2018年每日最低氣溫分布', title_pos='center')
 80 pie2.add('',attr3, L_data, radius=[30, 70], is_label_show=True, #radius環形圖內外圓半徑
 81          label_text_color=None, legend_orient='vertical',
 82          legend_pos='left', legend_text_color=None
 83          )
 84 pie2.show_config()
 85 page.add_chart(pie2, name='環形圖')
 86 
 87 
 88 #繪制南京2011-2018年天氣狀況條形統計圖
 89 Weather_NJ = []
 90 for Weathers in df['天氣狀況']:
 91     Weather_s = Weathers.split('/')
 92     Weather_NJ.append(Weather_s[0])
 93     Weather_NJ.append(Weather_s[1])
 94 Weather_NJ = Weather_NJ[:-218]
 95 
 96 sunny = rainy = yin_cloudy = lightening = duo_cloudy = snowy = 0
 97 for t in Weather_NJ:
 98     if t == '':
 99         sunny += 1
100     elif t == '':
101         yin_cloudy += 1
102     elif t == '多雲':
103         duo_cloudy += 1
104     elif t == '雷陣雨':
105         lightening += 1
106     elif '' in t and t != '雨夾雪':
107         rainy += 1
108     elif '' in t:
109         snowy += 1
110     else:
111         pass
112 Weather_attr = ['', '雨天', '多雲', '陰天', '雷陣雨', '雪天']
113 Weather_datas = [sunny, rainy, duo_cloudy, yin_cloudy, lightening, snowy]
114 bar = Bar('南京市2011-2018年天氣情況統計', '注意:一天有兩個天氣變化,部分日期天氣情況可能丟失', title_pos='center')
115 bar.add('天氣狀況', Weather_attr, Weather_datas, is_more_utils=True,
116         mark_point=['max', 'min'], legend_pos='right'
117         )
118 bar.show_config()
119 page.add_chart(bar)
120 
121 page.render('all_analysis.html')    #網頁地址

 圖像結果如下:

 

 


是不是發現使用pyecharts得到的圖表更加好看,這里上傳的圖片是靜態的,在網頁打開的時查看其實是動態的。

這里只爬取了南京市的歷史天氣,感興趣的朋友可以嘗試爬取更多城市的,甚至可以在此基礎上編寫一個小軟件,隨時隨地查看不同地區的歷史天氣,不過前提是該網站的源代碼不發生大變動。

本次分享就到此為止,如果有錯誤或者疑問或者是建議歡迎大家隨時指正,我也會積極回應。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM