原文地址:http://www.mapboxx.cn/article/poi-pology/
高德地图提供了三种方式来获取POI数据:
根据关键字搜索的可以参见目前实现的工具:http://www.mapboxx.cn/tool/poiview/
本次打算实现第三种,根据多边形范围爬取POI数据。大概思路如下:
申请高德开放平台账号,并且申请开发者认证,然后申请web服务类型的密钥。
使用的高德行政区划查询接口,地址:https://lbs.amap.com/api/webservice/guide/api/district
示例url:http://restapi.amap.com/v3/config/district?keywords=%E5%B9%BF%E5%B7%9E&key=4188efb67360681f89110ccdb11e563b&subdistrict=1&extensions=all
后续做JSON数据的解析,提取边界经纬度,并且使用math.max()和math.min()函数获取经纬度的最大和最小值。具体代码如下:
# 第一行必须有,否则报中文字符非ascii码错误
import urllib.request
from urllib.parse import quote
import json
#TODO 1
# 高德上申请的key
key = '4188efb67360681f89110ccdb11e563b' # 需替换为自己的
# TODO 2 搜索的城市名(全名)
addr_name = '广州'
url = 'http://restapi.amap.com/v3/config/district?'
def getlnglat(address):
uri = url + 'keywords=' + quote(address) + '&key=' + key + '&subdistrict=1' + '&extensions=all'
# 访问链接后,api会回传给一个json格式的数据
temp = urllib.request.urlopen(uri)
temp = json.loads(temp.read())
# polyline是坐标,name是区域的名字
Data = temp["districts"][0]['polyline']
lngs = []
lats = []
points = []
for line in str(Data).split(";"):
if len(line.split("|")) > 1:
for uu in line.split("|"):
if float(uu.split(",")[0]) != None:
lngs.append(float(uu.split(",")[0]))
lats.append(float(uu.split(",")[1]))
points.append([float(uu.split(",")[0]), float(uu.split(",")[1])])
else:
if float(line.split(",")[0]) != None:
lngs.append(float(line.split(",")[0]))
lats.append(float(line.split(",")[1]))
points.append([float(line.split(",")[0]), float(line.split(",")[1])])
print(points)
print(max(lngs), min(lngs), max(lats), min(lats))
return max(lngs), min(lngs), max(lats), min(lats)
getlnglat(addr_name)
第2步骤中已经知道了大矩形坐标范围,现在就可以根据它们去划分小矩形,在此之前需要指定小矩形的长度,(0.01-0.1之间最佳,单位为KM)。具体代码如下:
import numpy as np
def generate_grids(start_long,start_lat,end_long,end_lat,resolution):
"""
根据起始的经纬度和分辨率,生成需要需要的网格.
方向为左上,右下,所以resolution应为 负数,否则未空
:param start_long:
:param start_lat:
:param end_long:
:param end_lat:
:param resolution: 划分的网格长度,单位为KM
:return:
"""
assert start_long < end_long,'需要从左上到右下设置经度,start的经度应小于end的经度'
assert start_lat > end_lat,'需要从左上到右下设置纬度,start的纬度应大于end的纬度'
assert resolution>0,'resolution应大于0'
grids_lib=[]
longs = np.arange(start_long,end_long,resolution)
if longs[-1] != end_long:
longs = np.append(longs,end_long)
lats = np.arange(start_lat,end_lat,-resolution)
if lats[-1] != end_lat:
lats = np.append(lats,end_lat)
for i in range(len(longs)-1):
for j in range(len(lats)-1):
grids_lib.append([round(float(longs[i]),6),round(float(lats[j]),6),round(float(longs[i+1]),6),round(float(lats[j+1]),6)])
#yield [round(float(longs[i]),6),round(float(lats[j]),6),round(float(longs[i+1]),6),round(float(lats[j+1]),6)]
return grids_lib
grids_lib = generate_grids(112.958507, 23.932988, 114.059957, 22.51436,0.1)
最终获取到的grids_lib就是划分出的所有网格范围坐标,数据结构如下:
[[112.975216, 23.463609], [112.977106, 23.463297]]
剩下的逻辑就和关键字爬取一样,只是不需要指定city参数,而是替换为polygon
参数,参数示例:
112.975216, 23.463609|112.977106, 23.463297
分别是矩形的左上和右下点坐标。
在这个过程中,需要注意的是矩形的范围肯定是比一个城市范围大的,因此难免爬到的数据会出现所属城市不是所需要的城市的情况,此情况的处理办法是:根据POI数据的adcode和城市的adcode判断,前四位分别代表了省和城市,因此如果前四位编码相同,则是属于同一个城市的数据。
完整代码参见:https://github.com/liujiao111/poi
里面的
poi-pology
文件夹
需要改动的在app.py文件 中上部分用TODO样式标出来了。