上一次分享了使用matplotlib對爬取的豆瓣書籍排行榜進行分析,但是發現python本身自帶的這個繪圖分析庫還是有一些局限,繪圖不夠美觀等,在網上搜索了一波,發現現在有很多的支持python的繪圖庫可以使用,本次嘗試使用pyecharts對爬取的數據進行分析,然后發現這個庫實在是太好用了,生成的庫也很好看,還能生成動態圖,簡直是進行數據分析的一大神器!
pyecharts: pyecharts是一個封裝百度開源圖表庫echarts的包,使用pyecharts可以生成獨立的網頁,也可以在flask、django中集成使用。
本次爬取的首頁地址是:
http://www.tianqihoubao.com/lishi/nanjing.html
爬取步驟:
- 爬取主網頁,獲取進入每個南京市具體年份月份的天氣數據的鏈接
- 爬取上方獲取的具體鏈接的數據
- 存儲數據
- 對數據進行篩選后使用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得到的圖表更加好看,這里上傳的圖片是靜態的,在網頁打開的時查看其實是動態的。
這里只爬取了南京市的歷史天氣,感興趣的朋友可以嘗試爬取更多城市的,甚至可以在此基礎上編寫一個小軟件,隨時隨地查看不同地區的歷史天氣,不過前提是該網站的源代碼不發生大變動。
本次分享就到此為止,如果有錯誤或者疑問或者是建議歡迎大家隨時指正,我也會積極回應。