Py学习  »  Python

轻松获取城市道路数据 | 用Python发现北京一共有1.5万条道路!

凹凸数据 • 2 年前 • 394 次点击  

大家好,我是小五🧐

今天分享一篇文章,主要演示如何获取城市道路数据。

好了,我们开始今天的案例介绍。

1. 需求分析

我们以北京为例,希望获取该城市全部道路名称信息,主要字段有道路id、道路名称及所在区,基于高德地图的api接口。

我们找到高德api文档:https://lbs.amap.com/api/webservice/guide/api/search#t8

在搜索POI部分发现了查询城市道路名称的关键字搜索接口如下,但是该接口最多只能返回1000个数据。很明显北京市不止1000条道路,那么如何获取全部道路呢?

关键字搜索

终于,我们发现多边形搜索的接口,它可以对指定的矩形区域内的道路进行搜索,这样我们就脑洞一个想法将北京市按照经纬度分割为若干小区域,如果搜索各个区域内的道路数据后汇总就可以了,为了尽可能不要有遗漏,我们可以将区域颗粒度划分的小一些。

多边形搜索

那么,新的问题也来了:如何进行经纬度区域划分呢?我们又找到了行政区域查询接口文档:https://lbs.amap.com/api/webservice/guide/api/district

该接口通过行政区名称关键字就可以返回该行政区域的边界经纬度,如果我们只需要取经纬度各自的最大最小值就可以得到北京市所在的矩形区域,接着对这个矩形区域进行细化即可。

行政区域查询

思路有了,我们就开始干活吧!

2. 获取行政区域边界数据

直接按照开发者文档的案例演示编写代码如下:

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=['经纬度'])  
df[['经度','纬度']] = df['经纬度'].str.split(',',n=1,expand=True).astype(float)  
  
# 获取区域边界经纬度  
latitude_max = df['经度'].max()  
latitude_min =  df['经度'].min()  
longitude_max =  df['纬度'].max()  
longitude_min =  df['纬度'].min()  

最后,矩形区域的四个点的经纬度如下:

左上角:115.423411,41.060816  
右上角:117.514625,41.060816  
左下角:115.423411,39.442758  
右下角:117.514625,39.442758  
矩形区域

上图中我们可以看到矩形区域很多部分不属于北京,所以在后续的道具数据采集的时候需要进行判断道路归属省份是否为北京。

3. 将行政区域分块

既然我们得到了北京所属矩形区域的边界点经纬度,那么直接这个矩形区域进行网格化就行了,处理过程比较简单,直接看代码:

# 绘制网格,这里按照20*20共400个网格  
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  

我们得到了用于区域搜索经纬度坐标对如下:

# 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',  
...  
]  
网格化

4. 获取道路数据

到这一步,我们只需要遍历全部的坐标对polygons,然后搜索该区域内满足归属省份为北京市的全部道路即可。

# 获取指定区域指定page的道路数据并存到本地  
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 = '北京道路名称数据.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个区域  
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个区域的道路数据',end='')  

最终,我们得到了北京一共有14994条道路,其中各区道路数分别如下:

道路数
顺义区2164
大兴区1826
通州区1310
朝阳区1264
海淀区1088
房山区912
密云区907
西城区896
东城区818
昌平区801
平谷区770
丰台区673
延庆区553
门头沟区378
怀柔区372
石景山区262
总计14994

以上就是本次全部内容,感兴趣的同学在下方公众号【快学Python】(非本号)中回复道路可以获得源码。

后续我们结合道具数据试试一些好玩的探索吧,或者你有什么想法可以留言交流哦!

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/117380
 
394 次点击