1. 程式人生 > >Python突破高德API限制爬取交通態勢資料+GIS視覺化(超詳細)

Python突破高德API限制爬取交通態勢資料+GIS視覺化(超詳細)

一、需求:

       爬取高德的交通態勢API,將資料視覺化為含有交通態勢資訊的向量路網資料。

二、使用的工具:

       Python IDLE、記事本編輯器、ArcGIS 10.2、申請的高德開發者KEY(免費)。

三、主要思路:

       本文的思路是使用Python的requests模組爬取高德API的返回資訊,將返回的資訊資料(JSON),通過程式碼解析的方式存入CSV檔案中,再匯入ArcGIS中進行視覺化處理。

四、分析階段:

       根據高德提供的交通態勢資訊API文件,注意到高德提供了兩種獲取交通態勢資訊的方式,一種是通過設定矩形區域(傳入左下角以及右上角座標)的方式,一種是通過設定圓形區域的方式(設定圓心座標和半徑),本文使用的是設定矩形區域的方式。 但是問題來了,高德對使用者的API行為進行了限制,要求設定的矩形區域的對角線長度不超過10公里,但這是難不倒程式猿的,可以使用網格的思想來突破這一限制,如下圖:

        即將爬取區域分成多個網格,每個網格在高德規定的10公里範圍之內即可,這樣雖然增加了API的呼叫次數,但不得不說是較為合適的解決方案,本思想同樣也適用於POI資訊的爬取,在本文中筆者使用了簡單的for迴圈來實現網格爬取,當然讀者也可以參考:

        這篇博文中的LocaDiv類來實現更為複雜化的網格爬取方式。

五、編寫程式碼:

        由於本文的爬蟲程式比較簡單,因此筆者為了方便直接使用Python自帶的IDLE進行程式編寫,程式碼如下:

import requests
import pandas as pd
import json
import time

#初始API的URL
url="https://restapi.amap.com/v3/traffic/status/rectangle?key=申請的key&extensions=all&rectangle="

#設定整個網格左下角座標的經緯度值
baselng=116.927748
baselat=36.62361
#設定每個網格單元的經緯度寬
widthlng=0.05
widthlat=0.04
#用於儲存資料
x=[]
#用於標識交通態勢線段
num=0

#爬取過程可能會出錯中斷,因此增加異常處理
try:
    #迴圈每個網格進行資料爬取,在這裡構建了3X3網格
    for i in range(0,3):
        #設定網格單元的左下與右上座標的緯度值
        #在這裡對資料進行處理,使之保留6位小數(不保留可能會莫名其妙出錯)
        startlat=round(baselat+i*widthlat,6)
        endlat=round(startlat+widthlat,6)
        for j in range(0,3):
            #設定網格單元的左下與右上座標的經度值
            startlng=round(baselng+j*widthlng,6)
            endlng=round(startlng+widthlng,6)
            #設定API的URL並進行輸出測試
            locStr=str(startlng)+","+str(startlat)+";"+str(endlng)+","+str(endlat)
            thisUrl=url+locStr
            print(thisUrl)
            #爬取資料
            data=requests.get(thisUrl)
            s=data.json()
            a=s["trafficinfo"]["roads"]
            #注意,提取數值需要使用XXX.get()的方式來實現,如a[k].get('speed')
            #若使用a[k]['speed']來提取,或會導致KeyError錯誤
            for k in range(0,len(a)):
                s2=a[k]["polyline"]
                s3=s2.split(";")
                for l in range(0,len(s3)):
                    s4=s3[l].split(",")
                    x.append([a[k].get('name'),a[k].get('status'),a[k].get('speed'),num,float(s4[0]),float(s4[1])])
                num=num+1
            #若爬取網格較多,可使用time.sleep(秒數)來避免高德的單秒API呼叫次數的限制
except Exception  as e:
    pass

#將資料結構化儲存至規定目錄的CSV檔案中
c = pd.DataFrame(x)
c.to_csv('E:/BigRoads.csv',encoding='utf-8-sig')#感謝網友weixin_43475766的提醒

六、CSV資料處理:

        在相關目錄下找到爬取的CSV檔案,用記事本開啟,刪除第一行的內容(,0,1,2,3,4,5),否則會導致匯入ArcGIS時出錯。

七、交通態勢資訊視覺化:

        1、開啟Arcmap,在右側的catlog(目錄)中找到爬取的CSV檔案直接拖入左側的內容列表中,如圖:    

        2、右鍵點選該CSV資料,選擇“顯示XY資料”:

        3、在彈出的設定框中,進行如下設定:

        需要注意的是,本文中爬取的高德資料的座標值使用的是GCJ-02座標系,若要應用至專案中,需要轉換為WGS-84座標系,本文為了省事,且為了與高德線上底圖對比驗證,直接當作WGS84座標來處理。點選兩次確定,即可看到CSV檔案成功的轉換為了點要素檔案。

        4、接下來的一步十分重要,開啟生成要素的屬性表可以發現,屬性表並沒有FID(objectID)欄位,若無該欄位,該點要素將無法轉換為線要素,因此需要將該要素匯出為SHP檔案,方法是右鍵單擊該要素,選擇資料->匯出資料,如下圖:

        然後進行如下設定,注意要匯出為shp格式:

        5、接下來是將交通態勢點轉換為線,在toolbox中找到“點集轉線”工具(資料管理工具->要素->點集轉線),在彈出的設定介面進行如下設定:

        注意線欄位選擇Field5(即程式碼中的num變數),排序欄位選擇FID。

        6、等待片刻,完整的路網呈現在眼前:

        看到了路網是不是一陣狂喜,但是開啟屬性表,似乎笑不出來了,原來的交通態勢屬性去哪了!!!

        不要著急,接下來一步,將屬性完美的找回來。

        7、右鍵路網資料,選擇連線和關聯->連線,如下圖:

        在彈出的設定框中進行如下設定:

        第二個選項可以是原始的CSV表,也可以是用來轉線的點檔案(即本文的jinan.shp),點選確定,再開啟屬性表,屬性是不是回來了呢?

        8、分級渲染視覺化一下,美滋滋~

        什麼?為什麼這麼醜?不要在意這些細節...........