讓米帝領事館給你報空氣質量(動態網頁爬取及簡單的數據整理)

自從有娃之後,好久沒有時間好好摸一摸編程了,週末的時候正好出門溜娃,就想到了空氣質量的問題,雖然有APP啊上海發佈啊之類的能夠查,但我恰恰就是手賤要爬米帝領事館的數據。(PM2.5監測網上的監測站點更多,但數據彷佛老是低於美國領事館公佈的AQI)python

是時候撿起python了!因而回到家,等孩子他媽哄睡了寶寶以後(媽媽真辛苦),我開始研究怎麼實現我想要的功能。首先我上了一下數據監測頁面http://aqicn.org/city/shanghai/quanshipingjun/cn/正則表達式

 

右側就是咱們想要的每一個監測點的數據,然而這是個動態網頁,讓我一個只學過怎麼爬靜態網頁的人一臉懵逼……一番搜刮學習以後我找到了解決之道——一切沒解決的問題均可以先用F12解決!編程

打開瀏覽器的F12,切換到Network標籤,觀察下面的JS或者XHR,試着拖動那張地圖,看看下方的列表有沒有變化,果真,每拖動一次XHR下就會生成1條記錄,點進去一看,嘿~嘿~嘿~這不就是咱們要的東西嗎?json

 

點擊左側的Headers還能看到動態網頁的網址:api

 

咱們把這個網址複製下來,並解析,形如:瀏覽器

https://api.waqi.info/mapq/bounds/?bounds=31.043521630684204,121.19293212890624,31.466153715024294,121.84112548828125&inc=placeholders&k=_2Y2EzVxxIDVsfIydASBRWXmldZA4+LREbFkY3ZQ==&_=1497098578289微信

好長……是否是有點累覺不愛了?不過仔細看一下的話,bounds=後面的東西像不像座標?這應該指的就是這張圖的邊界。多抓幾回就會發現,每次不同的除了座標就只有最後那串數字,每次都不同。我猜測這個會不會和時間有關呢?因而我每隔10秒移動一次地圖,發現果真,每十秒鐘差很少增長10000單位,那就是時間戳沒跑了(其實後來發現,及時每次提交的時間戳即便一毛同樣數據也會自動刷新……)。知道了這些以後就是寫網頁解析的代碼了,這個就沒太大難度了。數據結構

 1 url ="https://api.waqi.info/mapq/bounds/?bounds=31.064698120353743,121.201171875,31.487235582017444,121.84936523437499&inc=placeholders&k=_2Y2EzVxxIDVsfIydASBRWXmldZA4+LREbFkY3ZQ==&_=1497098578289" #動態網頁網址
 2 
 3 user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
 4 headers = { 'User-Agent' : user_agent } #頭文件
 5 
 6 try:
 7     request = urllib.request.Request(url,headers = headers)
 8     response = urllib.request.urlopen(request) #獲取數據
 9 except urllib.error.URLError as e:
10     if hasattr(e,"code"):
11         print(e.code)
12     if hasattr(e,"reason"):
13         print(e.reason)
14 
15 aqi_trans=json.load(response) #json數據的解析
16 """
17 aqi_trans[0]數據結構:
18 {'aqi': '68',
19 'city': 'Yangpu Sipiao, Shanghai (上海楊浦四漂)',
20 'idx': 702,
21 'img': '_c_azCs5IzEvPSMzUfzZ3xbOty57Onv1sTxMA',
22 'lat': 31.2659,
23 'lon': 121.536,
24 'pol': 'pm25',
25 'stamp': 1497160800,
26 'tz': '+0800',
27 'utime': '2017-06-11 14:00:00',
28 'x': '482'}
29 共11個數據點
30 """

這裏咱們獲得的aqi_trans是一個列表,列表中的每一個元素都是一個字典,字典的內容就是監測站的名稱啦,AQI指數啦,經緯度啦之類的信息。app

 

以後就是簡單的數據整理,這就交給pandas了。這裏我選擇了4個數據,idx應該是監測點的索引(但隔一段時間會換,不過序列狀況不變),utime就是監測的時間,city是監測點的名字,用正則表達式去掉括號,AQI就是空氣質量指數啦~不過AQI只有數值,沒有等級,但這個很簡單,一個cut函數就解決了。函數

 1 aqi_table=pd.DataFrame(columns=['Idx','Time','Site','AQI'])
 2 
 3 for i in range(len(aqi_trans)):
 4     pos_idx=int(aqi_trans[i]['idx'])
 5     record_time=aqi_trans[i]['utime']
 6     site=re.findall(r'上海\S*(?=\))',aqi_trans[i]['city'])[0] #正則,提取括號裏的文字
 7     aqi=int(aqi_trans[i]['aqi'])
 8     aqi_table=aqi_table.append({'Idx':pos_idx,'Time':record_time,'Site':site,'AQI':aqi},ignore_index=True)
 9 aqi_table=aqi_table.sort_values('Idx',ascending=True)
10 aqi_table=aqi_table.set_index(pd.Series(range(0,11)))
11 aqi_table['Level']=pd.cut(aqi_table['AQI'],[0,50,100,150,200,300,10000],labels=[u'',u'',u'輕度污染',u'中度污染',u'重度污染',u'嚴重污染']) #打標籤

 

最後我決定寫一個函數,把獲取AQI的功能打包一下,而後定時運行一下這個函數(領事館數據貌似每小時更新一次),監測的數據就放進一個csv文件裏,方便後續處理。彙總一下代碼以下:

import urllib #python 3中urllib和urllib2合併了,不少語法不一樣了
import json
import re
import pandas as pd

def Get_AQI(t):
    url ="https://api.waqi.info/mapq/bounds/?bounds=31.064698120353743,121.201171875,31.487235582017444,121.84936523437499&inc=placeholders&k=_2Y2EzVxxIDVsfIydASBRWXmldZA4+LREbFkY3ZQ==&_=%d"%(t)
    #這裏用的是動態時間戳,但時間戳好像並不影響數據的實時性,那隻要隔一段時間提交一次一樣的網址就好了

    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers = { 'User-Agent' : user_agent }

    try:
        request = urllib.request.Request(url,headers = headers)
        response = urllib.request.urlopen(request)
    except urllib.error.URLError as e:
        if hasattr(e,"code"):
            print(e.code)
        if hasattr(e,"reason"):
            print(e.reason)

    aqi_trans=json.load(response)
    aqi_table=pd.DataFrame(columns=['Idx','Time','Site','AQI'])
   
    for i in range(len(aqi_trans)):
        pos_idx=int(aqi_trans[i]['idx'])
        record_time=aqi_trans[i]['utime']
        site=re.findall(r'上海\S*(?=\))',aqi_trans[i]['city'])[0]
        aqi=int(aqi_trans[i]['aqi'])
        aqi_table=aqi_table.append({'Idx':pos_idx,'Time':record_time,'Site':site,'AQI':aqi},ignore_index=True)
    aqi_table=aqi_table.sort_values('Idx',ascending=True)
    aqi_table=aqi_table.set_index(pd.Series(range(0,11)))
    aqi_table['Level']=pd.cut(aqi_table['AQI'],[0,50,100,150,200,300,10000],\
             labels=[u'',u'',u'輕度污染',u'中度污染',u'重度污染',u'嚴重污染']) #分段打標籤
    return aqi_table

import time

sleep_time=1800 #30分鐘運行一次

if __name__ == '__main__':
    while True:
        now_time=int(time.time()*1000)
        aqi_database=Get_AQI(now_time)
        aqi_database.to_csv('D:\\AQI\\aqi_database.csv',mode='a+') #記錄csv文件,a+爲追加寫入       
        print(time.ctime())
        print(Get_AQI(now_time))
        time.sleep(sleep_time)

終於磕磕絆絆地碼完了,發現本身果真忘了很多東西,python3和python2也有不少不一樣點了,還須要學習一個,提升姿式水平啊~心滿意足之餘,我還YY了一下把這功能放在一個樹莓派裏,而後定時給微信推送,白日夢真是美妙極了~

啊~白日夢……

相關文章
相關標籤/搜索