想知道所在的城市有多少條道路?我用Python發(fā)現(xiàn)北京一共有1.5萬條道路!
本文轉載自微信公眾號「可以叫我才哥」,作者才哥。轉載本文請聯(lián)系可以叫我才哥公眾號。
大家好,我是才哥。
最近被催更了,害~
今天我們開啟一個系列吧,關于城市道路的,本篇主要演示獲取城市道路數(shù)據(jù),接下來我們會在此基礎上拓展1-2篇好玩的案例,敬請期待!
好了,我們開始今天的案例介紹。
1. 需求分析
我們以北京為例,希望獲取該城市全部道路名稱信息,主要字段有道路id、道路名稱及所在區(qū),基于高德地圖的api接口。
我們找到高德api文檔:https://lbs.amap.com/api/webservice/guide/api/search#t8
在搜索POI部分發(fā)現(xiàn)了查詢城市道路名稱的關鍵字搜索接口如下,但是該接口最多只能返回1000個數(shù)據(jù)。很明顯北京市不止1000條道路,那么如何獲取全部道路呢?
關鍵字搜索
終于,我們發(fā)現(xiàn)多邊形搜索的接口,它可以對指定的矩形區(qū)域內(nèi)的道路進行搜索,這樣我們就腦洞一個想法將北京市按照經(jīng)緯度分割為若干小區(qū)域,如何搜索各個區(qū)域內(nèi)的道路數(shù)據(jù)后匯總就可以了,為了盡可能不要有遺漏,我們可以將區(qū)域顆粒度劃分的小一些。
多邊形搜索
那么,新的問題也來了:如何進行經(jīng)緯度區(qū)域劃分呢?我們又找到了行政區(qū)域查詢接口文檔:https://lbs.amap.com/api/webservice/guide/api/district
該接口通過行政區(qū)名稱關鍵字就可以返回該行政區(qū)域的邊界經(jīng)緯度,如何我們只需要取經(jīng)緯度各自的最大最小值就可以得到北京市所在的矩形區(qū)域,接著對這個矩形區(qū)域進行細化即可。
行政區(qū)域查詢
思路有了,我們就開始干活吧!
2. 獲取行政區(qū)域邊界數(shù)據(jù)
直接按照開發(fā)者文檔的案例演示編寫代碼如下:
- import requests
- import pandas as pd
- import os
- url = 'https://restapi.amap.com/v3/config/district?'
- key = '你的key' # 自己在高德開放平臺注冊一個即可
- keywords = '北京' # 可以換成你所在的城市
- params = {
- 'key':key,
- 'keywords':keywords,
- 'subdistrict':0,
- 'extensions':'all',
- }
- r = requests.get(url,params=params)
- data = r.json()
- polyline = data['districts'][0]['polyline']
- polyline_list = polyline.split(';')
- df = pd.DataFrame(polyline_list,columns=['經(jīng)緯度'])
- df[['經(jīng)度','緯度']] = df['經(jīng)緯度'].str.split(',',n=1,expand=True).astype(float)
- # 獲取區(qū)域邊界經(jīng)緯度
- latitude_max = df['經(jīng)度'].max()
- latitude_min = df['經(jīng)度'].min()
- longitude_max = df['緯度'].max()
- longitude_min = df['緯度'].min()
最后,矩形區(qū)域的四個點的經(jīng)緯度如下:
- 左上角:115.423411,41.060816
- 右上角:117.514625,41.060816
- 左下角:115.423411,39.442758
- 右下角:117.514625,39.442758
矩形區(qū)域
上圖中我們可以看到矩形區(qū)域很多部分不屬于北京,所以在后續(xù)的道具數(shù)據(jù)采集的時候需要進行判斷道具歸屬省份是否為北京。
3. 將行政區(qū)域分塊
既然我們得到了北京所屬矩形區(qū)域的邊界點經(jīng)緯度,那么直接這個矩形區(qū)域進行網(wǎng)格化就行了,處理過程比較簡單,直接看代碼:
- # 繪制網(wǎng)格,這里按照20*20共400個網(wǎng)格
- def get_polygons(latitude_num,longitude_num):
- # latitude_num = 20
- # longitude_num = 20
- latitude_step = (latitude_max - latitude_min)/latitude_num
- longitude_step = (longitude_max - longitude_min)/longitude_num
- polygons = []
- for i in range(latitude_num):
- latitude_leftup = latitude_min + latitude_step * i
- latitude_rightdown = latitude_min + latitude_step * (i+1)
- for j in range(longitude_num):
- longitude_leftup = longitude_max - longitude_step * j
- longitude_rightdown = longitude_max - longitude_step * (j+1)
- polygon = f'{latitude_leftup},{longitude_leftup}|{latitude_rightdown},{longitude_rightdown}'
- polygons.append(polygon)
- return polygons
我們得到了用于區(qū)域搜索經(jīng)緯度坐標對如下:
- # polygons
- ['115.423411,41.060816|115.5279717,40.979913100000005',
- '115.423411,40.979913100000005|115.5279717,40.8990102',
- '115.423411,40.8990102|115.5279717,40.8181073',
- '115.423411,40.8181073|115.5279717,40.7372044',
- ...
- ]
網(wǎng)格化
4. 獲取道路數(shù)據(jù)
到這一步,我們只需要遍歷全部的坐標對polygons,然后搜索該區(qū)域內(nèi)滿足歸屬省份為北京市的全部道路即可。
- # 獲取指定區(qū)域指定page的道路數(shù)據(jù)并存到本地
- def get_road(polygon,page):
- url = 'https://restapi.amap.com/v3/place/polygon?'
- params = {
- 'key':key,
- 'polygon':polygon,
- 'keywords':'道路名',
- 'types':190301,
- 'offset':20,
- 'page':page,
- 'extensions':'all',
- }
- r = requests.get(url,params=params)
- data = r.json()
- pois = data['pois']
- file_name = '北京道路名稱數(shù)據(jù).csv'
- for poi in pois:
- if poi['pname'] =='北京市':
- df = pd.DataFrame({
- 'road_id' : poi['id'],
- 'road_name' : poi['name'],
- 'road_adname' : poi['adname']
- },index=[0])
- if os.path.exists(file_name):
- df.to_csv(file_name, mode='a', header=False,
- index=None, encoding='utf_8_sig')
- else:
- df.to_csv(file_name, index=None, encoding='utf_8_sig')
- return pois
- # 這里分為20*20共400個區(qū)域
- polygons = get_polygons(20,20)
- for i,polygon in enumerate(polygons):
- page = 1
- while True:
- pois = get_road(polygon, page)
- if pois == []:
- break
- page += 1
- print(f'\r正在爬取第{i+1}/400個區(qū)域的道路數(shù)據(jù)',end='')
最終,我們得到了北京一共有14994條道路,其中各區(qū)道路數(shù)分別如下:
區(qū) | 道路數(shù) |
---|---|
順義區(qū) | 2164 |
大興區(qū) | 1826 |
通州區(qū) | 1310 |
朝陽區(qū) | 1264 |
海淀區(qū) | 1088 |
房山區(qū) | 912 |
密云區(qū) | 907 |
西城區(qū) | 896 |
東城區(qū) | 818 |
昌平區(qū) | 801 |
平谷區(qū) | 770 |
豐臺區(qū) | 673 |
延慶區(qū) | 553 |
門頭溝區(qū) | 378 |
懷柔區(qū) | 372 |
石景山區(qū) | 262 |
總計 | 14994 |