如今,电子地图已成为每个人生活中不可或缺的一部分,出行导航、购物逛街、聚会吃饭等各种场合都离不开它。不仅如此,它在社会学、经济学、地理学等研究领域也大放光彩,一度成为热点方法。本文以高德API做行政区查询为例,演示如何获取地理数据。(不过可能会有商务打电话要money


原理
和网站一样,我们看到的电子地图背后其实是一个巨大的数据库以及一台服务器。当我们搜索某个地方时,相当于向服务器发送了请求,服务器在数据库查询到结果后又将结果返回给我们。所以我们可以使用程序模拟人工搜索,批量发出请求,获取数据。这就是爬虫的基本原理。不过如果使用高德API,事情就更加简单了。
API全称Application Programming Interface,作用和函数相近。向接口输入请求数据,再从接口接收返回数据,隐藏不必要的中间过程。使用API获取数据的好处有以下几点:
- 不会被服务器拦截,放心爬取(不过高德有每日配额限制
- 不用分析网页结构,直接接收返回数据
代码
功能
输入需要查询的省份/城市,画出该行政区以及下一级子行政区的地图。
Input: 安徽省
Output:
注意:
- 查询四个直辖市需要输入xx城区,如北京市输入的是北京城区
- 查询两个特别行政区需要输入xx特别行政区,如香港输入的是香港特别行政区
- 不支持台湾省的详细区划查询
- 输入中国可查询34个省级行政区
- 不支持区县的下一级行政区查询
实现
需要安装的库有:
使用程序前需要先填入高德API Web类型 key,可在高德开放平台注册申请。
# Python 3.8.8
# -*- Coding: UTF-8 -*-
# CreateDate: 2022/3/4 22:39
# Author: wuhulamb
import json
import requests
from shapely.geometry import Polygon
import geopandas as gpd
from matplotlib import pyplot
url = 'https://restapi.amap.com/v3/config/district'
param = {
'key': '', # 填入高德API key
'keywords': '', # 查询关键字
'subdistrict': '1', # 返回数据包括下一级行政区
'extensions': 'all', # 控制返回数据详细程度
}
def single_polygon(single_district):
"""get_polygon私有函数, 返回单个Polygon对象"""
single = []
for item in single_district.split(';'):
lon, lat = item.split(',')
single.append((float(lon), float(lat)))
return Polygon(single)
def get_polygon(response):
"""返回请求区域中所有的Polygon对象的列表(部分地区包含飞地)"""
all = json.loads(response.text)
possible = [] # 存放获取的single_polygon(字符)
target = [] # 存放处理后的singe_polygon(Polygon对象)
for _ in all['districts'][0]['polyline'].split('|'):
possible.append(_)
for i in possible:
target.append(single_polygon(i))
return target
def get_subdistricts(response_text):
"""返回数据格式 {'城关区': ['adcode', (103.825315,36.056948)]}"""
subdistricts = {}
js = json.loads(response_text)
for i in js['districts'][0]['districts']:
lon, lat = i['center'].split(',')
subdistricts[i['name']] = [i['adcode'], (float(lon), float(lat))]
return subdistricts
def main():
region_name = input('请输入一个你想查询的城市/省份: ')
param['keywords'] = region_name
region_all = []
rep_text = requests.get(url, params=param).text
districts = get_subdistricts(rep_text)
for _ in districts:
param['keywords'] = districts[_][0]
x = get_polygon(requests.get(url, params=param))
for item in x:
region_all.append(item)
g = gpd.GeoSeries(region_all, crs='epsg:4326') # 设置坐标系为WGS84,即GPS
g.plot(facecolor='#87CEFA', edgecolor='#FF6347') # 设置填充和边界颜色
pyplot.rcParams['font.sans-serif'] = 'SimHei' # 设置字体使得中文正常显示
for i in districts: # 标注地名
pyplot.text(districts[i][1][0], districts[i][1][1], i, ha='center', va='top', fontsize=8)
pyplot.show()
if __name__ == '__main__': # 判断程序是否直接运行还是作为包导入
main()
具体实现可参考:
高德API返回的数据是经过加密偏移的,并非真实WGS84坐标系下的数据。不过偏移不大,大概为几百米,同时为了保证代码的简洁性,没有再额外进行坐标转换,想要深入了解可以看看 Coordtransform by wandergis & GitHub Project
Leave a comment