【数据技术】利用Python获取高德地图POI数据——以上海瑞幸门店为例

一、概述

本文讲述利用Python获取高德地图POI数据的思路以及具体步骤。

此处以上海瑞幸门店为例,目的是同时讲述多边形搜索关键词搜索以及POI类型搜索的具体用法。

本文完整代码的获取方式在文末,有需求的小伙伴自取。

上海瑞幸门店地图可视化
上海瑞幸门店地图可视化

二、获取思路

通过调用高德地图API中的搜索POI(多边形搜索)接口来获取POI数据。

搜索POI接口

https://lbs.amap.com/api/webservice/guide/api/search#around

理论上来说,只需要将接口输入参数中的polygon设置为上海边界经纬度值,将keywords设置为瑞幸,将types设置为餐饮服务(编码:050000),就能够获取上海范围内的瑞幸咖啡门店数据。

GeoJSON格式的上海边界数据

但在多边形搜索接口中每个边界范围能够获取到的POI数量是有限制的,超过该限制的POI数据则不会返回。

因此,想要获取全量POI数据,需要将一个大多边形切割成若干个符合数量限制的小多边形。

此处,引入四叉树索引的概念,将大的多边形不断四分,直到所有小多边形均满足数量限制为止。

完成上述操作后,遍历所有小多边形并获取瑞幸POI,即可得到全量的上海瑞幸POI数据。

三、具体步骤

步骤1:申请高德地图API密钥

高德地图API密钥需要通过高德官网申请

高德地图API官网(https://lbs.amap.com/)

具体操作步骤可参考下面链接:https://kdocs.cn/l/coOAaCYwW0tg

步骤2:获取上海边界范围外接矩形的坐标值

# 通过读取GeoJSON格式的上海边界数据
# 获取上海边界外接矩形的最小经度、最大经度、最小纬度、最大纬度
​
import geopandas as gp
​
# 结果变量
resultMinLon = 99999.0  # 最小经度
resultMaxLon = 0.0  # 最大经度
resultMinLat = 99999.0  # 最小纬度
resultMaxLat = 0.0  # 最大纬度
​
# 读取上海边界数据
loadGeoData = gp.read_file("D:\\上海边界数据.geojson")
for i in range(0, len(loadGeoData)):
    # 读取几何数据
    loadGeometry = loadGeoData.loc[i, "geometry"]
    # 上海边界的几何数据是由多个多边形组成,如崇明岛、长兴岛、上海市区等
    # 所以需要遍历所有多边形
    # 多边形的类型是Polygon或者MultiPolygon
    for j in range(0, len(loadGeometry)):
        loadPolygon = loadGeometry[j]
        # 读取多边形的边界
        # 边界的类型是LineString(单线)或MultiLineString(多线)
        if loadPolygon.boundary.geom_type == 'LineString':
            # 读取边界中的每个坐标点
            for z in range(0, len(loadPolygon.boundary.coords)):
                loadLon = loadPolygon.boundary.coords[z][0]  # 经度
                loadLat = loadPolygon.boundary.coords[z][1]  # 纬度
                # 进行大小判断,并替换结果
                if loadLon <= resultMinLon:
                    resultMinLon = loadLon
                if loadLon >= resultMaxLon:
                    resultMaxLon = loadLon
                if loadLat <= resultMinLat:
                    resultMinLat = loadLat
                if loadLat >= resultMaxLat:
                    resultMaxLat = loadLat
        elif loadPolygon.boundary.geom_type == 'MultiLineString':
            # 如果边界是MultiLineString,则需要遍历其中的每条LineString
            for z in range(0, len(loadPolygon.boundary[0].coords)):
                loadLon = loadPolygon.boundary[0].coords[z][0]
                loadLat = loadPolygon.boundary[0].coords[z][1]
                if loadLon <= resultMinLon:
                    resultMinLon = loadLon
                if loadLon >= resultMaxLon:
                    resultMaxLon = loadLon
                if loadLat <= resultMinLat:
                    resultMinLat = loadLat
                if loadLat >= resultMaxLat:
                    resultMaxLat = loadLat
# 结果输出
print("上海最小经度:", resultMinLon)
print("上海最大经度:", resultMaxLon)
print("上海最小纬度:", resultMinLat)
print("上海最大纬度:", resultMaxLat)
步骤2输出结果

步骤3:以四叉树索引的方式不断四分矩形,直到所有矩形符合POI数量限制

import requests
​
# 上海边界经纬度值
minLon = 120.859465  # 最小经度
maxLon = 122.122756  # 最大经度
minLat = 30.677191  # 最小纬度
maxLat = 31.868458  # 最大纬度
​
# 存放符合POI数量限制多边形的列表
resultPolygonList = []
# 用来存放不符合POI数量限制多边形的列表
currentPolygonList = [[minLon, maxLon, minLat, maxLat]]
​
# 以四叉树的方式不断四分外接矩形
for currentLevel in range(1, 9999999):
    # 用来存放不符合POI数量限制多边形的临时列表
    tempPolygonList = []
    for z in range(0, len(currentPolygonList)):
        loadMinLon = currentPolygonList[z][0]
        loadMaxLon = currentPolygonList[z][1]
        loadMinLat = currentPolygonList[z][2]
        loadMaxLat = currentPolygonList[z][3]
        # 判断当前矩形是否符合POI数量限制
        # 如果符合则放入resultPolygonList
        # 如果不符合则进行四分,并将四分结果放入tempPolygonList
        ifSatisfy = judgeIfSatisfy_GaoDe([loadMinLon, loadMaxLon, loadMinLat, loadMaxLat])
        if ifSatisfy == True:
            resultPolygonList.append([loadMinLon, loadMaxLon, loadMinLat, loadMaxLat])
        else:
            # 进行四叉树
            tempQuadtree = executeQuadtree(loadMinLon, loadMaxLon, loadMinLat, loadMaxLat)
            # 左下角
            tempPolygonList.append(tempQuadtree[0])
            # 右下角
            tempPolygonList.append(tempQuadtree[1])
            # 右上角
            tempPolygonList.append(tempQuadtree[2])
            # 左上角
            tempPolygonList.append(tempQuadtree[3])
    currentPolygonList = tempPolygonList.copy()
    # 如果没有多边形进入下一层级,则跳出
    print("第", currentLevel, "层", "......", "符合要求的矩形:", len(resultPolygonList), "......", "剩余矩形:",
          len(currentPolygonList))
    if len(currentPolygonList) == 0:
        break
步骤3结果

步骤4:遍历所有矩形,获取上海瑞幸POI

# 遍历所有矩形,获取上海瑞幸POI数据
savePoiList = []  # 存放POI数据的结果列表
for i in range(0, len(resultPolygonList)):
    # 读取每个矩形
    loadPolygon = resultPolygonList[i]
    # 获取矩形中的POI数据,并添加到结果列表中
    savePoiList.extend(getPoiFromPolygon(loadPolygon, gaodeKey))

下面代码为获取单个矩形中POI数据的方法

# 从单个矩形获取瑞幸POI的方法
# 其中key为高德地图API密钥,需要自行申请
def getPoiFromPolygon(inputPolygon, key):
    # 存放POI数据结果的列表
    resultList = []
    # 由于POI数量限制是100,每页返回POI数量是20
    # 因此,最大的页数为5
    for currentPage in range(1, 6):
        # 组成Url
        currentUrl = "https://restapi.amap.com/v3/place/polygon?polygon=" + str(inputPolygon[0]) + "," + str(
            inputPolygon[2]) + "|" + str(inputPolygon[1]) + "," + str(
            inputPolygon[2]) + "|" + str(inputPolygon[1]) + "," + str(inputPolygon[3]) + "|" + str(
            inputPolygon[0]) + "," + str(inputPolygon[3]) + "|" + str(inputPolygon[0]) + "," + str(
            inputPolygon[2]) + "&offset=20&page=" + str(
            currentPage) + "&keywords=瑞幸&types=050000&output=json&key=" + key
        # 发送Get请求,并接收返回内容
        response = requests.get(currentUrl, stream=True, verify=False, timeout=60)
        returnData = response.json()
        returnPoiList = returnData['pois']
        if len(returnPoiList) > 0:
            for i in range(0, len(returnPoiList)):
                saveName = returnPoiList[i]['name']
                saveType = returnPoiList[i]['type']
                saveAddress = returnPoiList[i]['address']
                saveLocation = returnPoiList[i]['location']
                saveProvince = returnPoiList[i]['pname']
                saveCity = returnPoiList[i]['cityname']
                saveArea = returnPoiList[i]['adname']
                resultList.append(
                    [saveName, saveType, saveType, saveAddress, saveLocation, saveProvince, saveCity, saveArea])
                print(saveName, saveType, saveType, saveAddress, saveLocation, saveProvince, saveCity, saveArea)
        else:
            # 如果当前页POI数量为0,则返回已获取的POI数据并跳出
            return resultList
    return resultList
上海瑞幸POI数据

四、代码获取方式

点击下面链接获取代码

【数据技术】利用Python获取高德地图POI数据——以上海瑞幸门店为例 (qq.com)

物联沃分享整理
物联沃-IOTWORD物联网 » 【数据技术】利用Python获取高德地图POI数据——以上海瑞幸门店为例

发表评论