背景
最近在計(jì)劃明年從北京rebase到深圳去,所以最近在看深圳的各個(gè)方面。去年在深圳呆過一段時(shí)間,印象最深的是,深圳總是突然就下雨,還下好大的雨。對(duì)于我這種從小在南方長(zhǎng)大但是后面又在北京呆了2年多的人來說,熟悉而又無奈。
今天早上本來想隨便瀏覽瀏覽一個(gè)天氣網(wǎng)站,看看深圳的歷史天氣如何的,但是,一不小心發(fā)現(xiàn),這家網(wǎng)站竟然直接能用API來抓數(shù)據(jù),這~~~還不抓一波,省的自己一個(gè)月一個(gè)月地看。
先上最后的效果圖:
所有的code都在我的GitHub上:boydfd
下面從幾個(gè)方面講一講我是怎么做的:
- 爬取數(shù)據(jù)
- 用pandas顯示數(shù)據(jù)
- 功能擴(kuò)展
- 遇到的坑
爬取數(shù)據(jù)
先是在http://tianqi.2345.com上面瀏覽了一下深圳的6月份天氣。然后發(fā)現(xiàn)點(diǎn)切換月份的時(shí)候,網(wǎng)址沒有變,那應(yīng)該有請(qǐng)求API吧,看看這個(gè)API長(zhǎng)啥樣吧。
發(fā)現(xiàn)返回值就是純JS代碼,那就解析一下吧:
-
去掉
var =
和最后的;
。 -
用到
demjson
解析成Python的List[Dict]
對(duì)象。 -
轉(zhuǎn)成pandas的
DataFrame
- 加上我們的date字段
date = '201905'
weather = requests.get('http://tianqi.2345.com/t/wea_history/js/{date}/59493_{date}.js'.format(date=date)).text.split('=')[1][:-1]
weather = demjson.decode(weather)['tqInfo']
df = pd.DataFrame(weather)
df['month'] = date
結(jié)果是這樣的:
用Pandas顯示數(shù)據(jù)
太多雨天
我們可以看到,有各種雷陣雨啊,陰轉(zhuǎn)雨啊,雨轉(zhuǎn)陰之類的,這樣看到的天氣太雜了,所以我就統(tǒng)一了一下,按照雨、多云、陰、晴的順序來排序,先出出現(xiàn)的關(guān)鍵詞優(yōu)先級(jí)更高。
寫一個(gè)函數(shù)來處理之:
rain = '雨'
rain_index = ' ' + rain
cloudy = '多云'
cloudy_index = ' ' + cloudy
overcast = '陰'
overcast_index = ' ' + overcast
sunny = '晴'
sunny_index = ' ' + sunny
def weath_category(row):
tianqi = row['tianqi']
if tianqi.find(rain) != -1:
return rain_index
if tianqi.find(overcast) != -1:
return overcast_index
if tianqi.find(cloudy) != -1:
return cloudy_index
return sunny_index
多個(gè)月的數(shù)據(jù)
一個(gè)月的數(shù)據(jù)不夠啊,我們想要很多個(gè)月的數(shù)據(jù),那就寫得函數(shù)來生成月份吧。
def date_generate(start, end):
start = datetime.strptime(start, '%Y%m')
end = datetime.strptime(end, '%Y%m')
while True:
next_start = start + relativedelta(months=1)
yield start.strftime('%Y%m')
if next_start > end:
break
start = next_start
畫圖
分好類,爬了多個(gè)月份的數(shù)據(jù),就剩最終的畫圖部分了。使用Pandas提供給我們的函數(shù),可以很容易就畫出圖來。
def plot_weather(start, end):
df = read_weather(start, end).dropna().reset_index()
df['weather'] = df.apply(weath_category, axis=1)
from pylab import rcParams
rcParams['figure.figsize'] = 40, 10
weather_df = df.groupby(['month', 'weather']).aqi.count().unstack().reset_index()
weather_df.plot.bar(x='month', y=[rain_index, overcast_index, cloudy_index, sunny_index])
功能擴(kuò)展
現(xiàn)在只能收集到一個(gè)月的數(shù)據(jù),想收集多個(gè)月的數(shù)據(jù),還都自己去頁(yè)面上找城市代表的code是啥,太低效了。
這個(gè)網(wǎng)站這么容易爬,那就再試試能不能找到調(diào)用code的API。
啊哦,一不小心找到了所有的code,哈哈哈。
那就在JS里面提取一下。
- 先把所有的JS代碼都復(fù)制到瀏覽器的console里, 結(jié)果長(zhǎng)這樣:
- 將其轉(zhuǎn)換成字符串。
provqx.flatMap(a => a).join('|')
- 在Python里處理它。
def line_to_city_code(line):
return line.split(' ')[1].split('-')
def get_city_to_code():
city_code_list = list(map(line_to_city_code, city_code.split('|')))
return {city_code[0]: city_code[1] for city_code in city_code_list if len(city_code) == 2}
這樣我們就拿到所有的code了,只需要輸入城市,開始時(shí)間,結(jié)束時(shí)間,一張漂亮的圖就出來了,我還寫了個(gè)類稍微封裝了一下,只需要這樣就能使用了:
Weather('深圳').plot_weather('201701', '201906')
遇到的坑
以前在電腦里面處理過一次,就是matplotlib畫圖中文亂碼的事情,這次換了新電腦又碰到了。所以又搞了一次,
大概的步驟可以參考https://www.jianshu.com/p/8ed59ac76c06
我為了以防下次再經(jīng)歷一次,就寫了個(gè)腳本自動(dòng)處理這件事,目前只支持macOS和Python3。
腳本也在我的GitHub:bash,
直接執(zhí)行下面的bash腳本就可以解決這個(gè)問題:
curl -o- https://raw.githubusercontent.com/boydfd/one_step_solve/master/matplotlib_chinese.sh | bash
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
