如何获取全国省市区行政边界数据
今天我們以高德地圖為例,講解一下如何獲取全國省市區行政邊界數據。
高德開放平臺Web服務API
https://lbs.amap.com/
依次點擊開發支持–Web服務–Web服務API,即可進入到高德開放平臺Web服務API頁面。
可以發現,官方已開放了行政區域查詢的接口。
點擊查看該接口的詳細介紹:
其實就是先申請Key,然后構造Http請求,發送請求解析返回數據即可。
同時接口文檔提到,該接口只能返回國、省、市、區的polyline(邊界點集合),不支持街道級別,但已經滿足我們的需求了。
首先分析下接口請求參數:
有4點值得關注:
- keywords支持行政區名稱、citycode、adcode這3種格式,行政區名稱可能存在重復(尤其level是縣/區時),而citycode只有level在市或市以下才有,只有adcode可以唯一指定某個行政區,所以檢索的時候,我們使用adcode作為keywords傳入;
- subdistrict可以指定子級行政區的嵌套層數;
- 當最外層的districts超過20個元素時,需要配合page參數來獲取全部元素;
- 只有extensions配置為all時,接口才會返回我們需要的區域邊界數據。
想要一次性采集全國省市區行政邊界數據的話,第1步肯定是先設法拿到省、市、區的列表,然后逐個遍歷。
我們可以設置keywords為"中華人民共和國",然后將subdistrict設置為3,下3層(省、市、區)的子行政區信息就會返回。
這樣,我們發送1次請求就可以拿到省、市、區的列表了。
接著,我們將subdistrict調整為1(減少數據冗余),依次遍歷各個行政區域即可。
實現代碼如下:
# -*- coding:utf-8 -*-import requests import time import mongo_util #自行封裝的操作mongodb的工具類def get_district_info(key, col, time_delay, headers={}):request_url = 'https://restapi.amap.com/v3/config/district'country_name = '中華人民共和國'params = {'subdistrict':'3','extensions':'all','key':key,'output':'json','keywords':country_name,}# 設置subdistrict為3,1次請求獲取到國、省、市、區的信息country_res = requests.get(url=request_url, headers=headers, params=params).json()if country_res['status'] != "1":print("調用高德地圖Web API失敗!")returncountry = country_res['districts'][0]col.insert_one(country)print(f'{country_name}數據插入成功!')params['subdistrict'] = '1'# 遍歷省provinces = country['districts']for province in provinces:province_name = province['name']params['keywords'] = province['adcode']prov_res = requests.get(url=request_url, headers=headers, params=params).json()if prov_res['status'] == "0":print(f'{country_name}-{province_name}數據獲取失敗!')continuecol.insert_one(prov_res['districts'][0])print(f'{country_name}-{province_name}數據插入成功!')time.sleep(time_delay)# 遍歷市cities = province['districts']if len(cities) == 0:continuefor city in cities:city_name = city['name']params['keywords'] = city['adcode']city_res = requests.get(url=request_url, headers=headers, params=params).json()if city_res['status'] == "0":print(f'{country_name}-{province_name}-{city_name}數據獲取失敗!')continuecol.insert_one(city_res['districts'][0])print(f'{country_name}-{province_name}-{city_name}數據插入成功!')time.sleep(time_delay)# 遍歷區districts = city['districts']if len(districts) == 0:continuefor district in districts:distinct_name = district['name']params['keywords'] = district['adcode']distinct_res = requests.get(url=request_url, headers=headers, params=params).json()if distinct_res['status'] == "0":print(f'{country_name}-{province_name}-{city_name}-{distinct_name}數據獲取失敗!')continuecol.insert_one(distinct_res['districts'][0])print(f'{country_name}-{province_name}-{city_name}-{distinct_name}數據插入成功!')time.sleep(time_delay) # 主函數 if __name__ == '__main__':key = "******"# 接口請求之間的間隔time_delay = 0.01db_name = 'web_map'col_name = 'distinct'# MongoDB數據庫所在的服務器host = '******'port = 27017# 獲取mongodb的表句柄col = mongo_util.get_col(db_name, col_name, host, port)# 獲取全國各級行政區的數據get_district_info(key, col, time_delay)因為接口返回的是JSON類型的嵌套數據,所以這里選擇MongoDB作為存儲組件。
為了防止爬取過程中,進程宕掉導致已請求的數據丟失,可以拿到1條數據就入庫1條數據。
避免數據全都在內存中,執行批量插入的過程中異常退出,又得重復請求,但每個賬號的天請求次數是有限制的。
同時,各個接口均有QPS閾值,所以我們通過time_delay參數來控制數據采集的頻率。
但是高德開方平臺Web服務API有天調用次數的限制,如果想獲取大量數據,可能需要多個賬號或者分多天進行請求,有沒有更好的方法呢?
帶著這樣的疑問,我又看了看高德地圖其他的API版塊。
JS API
瀏覽高德開放平臺的JS API示例,里面也有個行政區邊界查詢的Demo。
https://lbs.amap.com/demo/jsapi-v2/example/district-search/draw-district-boundaries
打開瀏覽器的"開發者工具",我們抓包一下哪個請求是用來獲取行政區域數據的。
哈哈哈,其實跟開放的Web API接口地址是一致的,而且通過分析接口請求,我們直接可以拿到key。
也就是說,不需要用自己高德賬號里生成的key值了。
使用這個key構建接口請求,悲傷的發現,接口返回異常。
說明該接口其實還是跟開放的Web API接口還是有區別的,一般體現在請求參數和Headers上。
我們把瀏覽器抓取到的請求參數和Headers配置原封不動的拷貝過來,再次構建接口請求,此時接口正常返回。
但請求參數里的csid是個啥東西,而且不同行政區域請求里的csid還不同。
嘗試著去掉該參數,然后構建接口請求,發現接口仍然可以正常返回,說明該參數是可選參數,而且不是檢索字段。
按照這個思路,我們逐步嘗試去掉其他請求參數和Headers里的配置。
發現該接口與開放的Web API接口相比,本質僅有2點不同:
- 請求參數
請求參數需要額外指定: s=rsv3
- Headers
需要添加如下Headers:
調整原來的代碼:
- 在params里增加s配置
- 在發送請求的時候傳入headers
該種方法的優點是繞開了第1種方法的日調用次數限制(高德是否有額外的反爬策略,待驗證)。
AMAP Service
其實前面headrs的Referer配置就提醒我了,是不是高德地圖在https://lbs.amap.com/這個地址下也有功能相同的接口。
所以就在高德平臺上隨意點了點,逛了逛,還真就發現了,哈哈哈。
與上面兩個接口不同的是,這個接口是POST請求,而且竟然不需要指定key,這也太爽了吧,哈哈哈。
接著看一下請求參數:
參數和開放平臺Web服務API的完全一致。
最后看一下表單數據:
顯然表單數據是用來配置請求哪個接口的,這里的config/district代表的就是行政區域查詢。
代碼調整起來也不難:
# 調整請求的url request_url = 'https://lbs.amap.com/service/api/restapi' # 將所有的請求調整為POST,并傳入表單數據,例如: body = {"type": "config/district","version": "v3"} country_res = requests.post(url=request_url, params=params, data=body).json()該接口跟第2種接口相比,更近一步,連key值都省略了。
總結
本文介紹了3種基于高德地圖獲取全國省市區行政邊界數據的方法。
獲取到數據之后,可以進一步處理。
比如: 我使用pyshp包將采集到的數據轉換成了shp文件,然后可以在GIS軟件里進行可視化編輯。
也可以再爬取各個行政區的人口、GDP等數據,制作人口熱力圖等,這里不再贅述,讀者可自行實踐。
總結
以上是生活随笔為你收集整理的如何获取全国省市区行政边界数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python四大金刚之二:字典
- 下一篇: csv mysql_将csv的数据导入m