针对百度地图和高德地图POI数据限制,提出的正多边形搜索。

您所在的位置:网站首页 高德地图poi编码 针对百度地图和高德地图POI数据限制,提出的正多边形搜索。

针对百度地图和高德地图POI数据限制,提出的正多边形搜索。

2024-07-12 00:30| 来源: 网络整理| 查看: 265

最近公司需要收集某个站点的POI数据,但是这些API默认有POI条数限制,针对高德和百度地图的开放平台周边搜索poi限制200条数据,搜索网上大部分是开通服务或者是多边形搜索的矩形搜索,我想要的是类似于圆形的周边搜索,于是提出正多边形的多边形搜索,建议正8边形起步(我这是12边形),可以达到类似圆形效果,本质是多个等腰三角形合在一起,然后两条腰的交点是公用的,也就是中心坐标,理论上说边数越多,越像圆形,就跟数学积分一样。

在这里展示的是高德地图POI数据多边形获取,其实百度地图开放平台也差不多。

1、api数据获取的类型尽量使用小类名,不要使用大类,例如餐饮属于大类、中餐馆属于中类、粤菜属于小类,如果你想把一个大类的全部爬取下来,建议是下载相对应的POI类别的excel表然后导入程序,然后然后把大类对应的全部小类导入到程序中,开发者文档里有下载链接,自己可以找找。

2、我这里其实算法不够完美,因为我这里搜索的POI数据少,用不上更深入的算法,理论上说,12-18边形足够满足圆形的需求,如果在12-18边形内,有一个三角形的POI数据超过200条(加一个判断,如果该三角形的poi数据大于170或者页码>17还存在poi数据的话(默认每页10条)则认为这个三角形的poi数据可能会超过200(不建议直接大于200,因为是不会到200条的,我亲测最高180几条)),则可以把这个等腰三角形分成两个全等三角形,这样子不会改变整体的边数,只是在一个三角形内部分成两个单独算,如果分开后仍然有上述POI总数大于170的情况,就再分开,类似于递归调用。

上代码展示。

from geopy.distance import geodesic import pandas as pd import json import urllib.request import urllib.parse import math import os # 坐标字符串转换成数值坐标 def getLocation(locationStr): # 提取坐标值 lon_str, lat_str = locationStr.split(',') # 转换为浮点数 lon = float(lon_str) lat = float(lat_str) # 保留六位小数 lon = round(lon, 6) lat = round(lat, 6) return lon, lat # 计算两个坐标的距离 # 该作用的方法是计算站点内的数据点到中心点的直线距离,因为用的是多边形搜索,所以默认没有中心点 def haversine_distance(lat1, lon1, lat2, lon2): # 四个参数分别是两个坐标的经纬度 # 将经度和纬度转换为弧度 lat1_rad = math.radians(lat1) lon1_rad = math.radians(lon1) lat2_rad = math.radians(lat2) lon2_rad = math.radians(lon2) # 应用 Haversine 公式计算距离 dlon = lon2_rad - lon1_rad dlat = lat2_rad - lat1_rad a = math.sin(dlat / 2) ** 2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlon / 2) ** 2 c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) radius = 6371 # 地球半径,单位为千米 distance = radius * c * 1000 # 将距离转换为米 return round(distance, 2) # 参数1:大类中文名称;参数2:poi类别文件路径 # 该方法的作用是提取大类相对应的小类,并传入url作为参数 def littleTypeList(bigType, PoiTypeOfPath): df = pd.read_excel(PoiTypeOfPath, usecols=['大类', '小类']) littleTypeStr = "" for index, row in df.iterrows(): if row['大类'] == bigType: littleTypeStr = row['小类'] + '|' + littleTypeStr littleTypeStr = littleTypeStr[:-1] return littleTypeStr # 选择是否导出excel def toExcel(df, stationName, centerLon, centerLat, radius): # 选择是否导入并保存文件 while True: yes = input("选择是否将该数据导入文件,是请输入yes,否输入no:") # 选择是否导入文件 if yes == "yes": while True: path = input("请输入存放路径目录,注意如果路径最后没有斜杠 ,加上斜杠\:") if os.path.exists(path): # 判断文件夹是否存在 df.to_excel(f"{path}{stationName}-{centerLon, centerLat}-{bigType}-{radius}米.xlsx") break else: print("路径不存在,请重新输入") continue break elif yes == "no": print(df) break else: print("输入错误,请重新输入") continue # 参数1:站点名称;参数2:中心点经度;参数3:中心点维度;参数4:多边形边数;参数5:中心的范围,单位米;参数6:大类中文并称;参数7: # 主方法,计算中心站点要修范围内的数据点及其相关信息 def calculate_location(stationName, centerLon, centerLat, num, radius, GaoDeKey, headers, bigType, PoiTypeOfPath): # 每次旋转的扫描的方位角:每一小部分根据中心点顺时针旋转,保留五位小数 # 初始旋转方位角 init_bearing = 0 # 360/num 表示获取方位角并保留5位小数 bearing = round(360 / num, 5) # 数据帧,用来存放已经处理好的数据,以便后期导出excel文件 df = pd.DataFrame( columns=['parent', 'address', 'distance', 'pcode', 'adcode', 'pname', 'cityname', 'type', 'typecode', 'adname', 'citycode', 'name', 'location', 'id']) # 数据帧索引,从0开始 dfIndex = 0 for i in range(1, num + 1): # 三角形坐标 # 计算偏移后的坐标 destination1 = geodesic(kilometers=radius / 1000).destination((centerLat, centerLon), init_bearing) destination2 = geodesic(kilometers=radius / 1000).destination((centerLat, centerLon), init_bearing + bearing) # 计算偏移后的坐标保留6位小数 lat2, lon2 = round(destination1.latitude, 6), round(destination1.longitude, 6) lat3, lon3 = round(destination2.latitude, 6), round(destination2.longitude, 6) init_bearing = init_bearing + bearing littleTypeStr = littleTypeList(bigType, PoiTypeOfPath) # 设置最大访问页数,因为我这边POI数据少,所以每个三角形一般不到两百条,可以根据自己情况设定 for page_num in range(1, 11): # 高德地图开放平台API url = f'https://restapi.amap.com/v5/place/polygon?polygon={centerLon},{centerLat}|{lon2},{lat2}|{lon3},{lat3}|{centerLon},{centerLat}&types={littleTypeStr}&page_size=25&page_num={page_num}&output=json&key={GaoDeKey}' # 对 URL 进行编码 url = urllib.parse.quote(url, safe=':/?&=|') req = urllib.request.Request(url=url, headers=headers, method='GET') response = urllib.request.urlopen(req) text = response.read().decode('utf-8') jsonStr = json.loads(text) pois = jsonStr["pois"] # 设置数据帧打印选项,不省略行和列 pd.set_option('display.max_rows', 10) pd.set_option('display.max_columns', 15) # 判断爬取的内容当页有没有数据, if len(pois) == 0: # 如果该页没有数据,则表示该三角形内已经爬取完成,则开始爬到下一个三角形的poi数据,节约访问次数。 print("该页没有数据,进入下一个三角形地区的数据获取") break else: print("该页有数据") for j in range(0, len(pois)): df.loc[dfIndex] = pois[j] rad_lon, rad_lat = getLocation(pois[j]["location"]) df.at[dfIndex, "distance"] = haversine_distance(centerLon, centerLat, rad_lon, rad_lat) dfIndex = dfIndex + 1 print(df) print("数据展示成功") toExcel(df, stationName, centerLon, centerLat, radius) if __name__ == '__main__': # 高德地图分类文档下载,需要自行查看自己所要查询的分类,这个文件一定要存在 # https://lbs.amap.com/api/webservice/download # 导入分类文件,选出大类相对应的小类当作类别 # 中心点经度,保留六位小数 centerLon = # 中心点维度,保留六位小数 centerLat = # 多边形边数 num = 12 # POI类别文件路径,就是刚刚要求下载的文件,可以去官网搜索下载,然后每次直接导入 PoiTypeOfPath = r"PoiTypeOf.xlsx" # 自己相对应的大类 bigType = "poi大类中文名" # 请求头 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'} # 搜索范围、单位米,最大取值5000000 radius = 500 # 高德地图开发Key: GaoDeKey = "你的高德地图开放平台key" # stationName,站点中文名称 stationName = "站点中文名称" # 调用主方法 # 参数1,2:中心坐标经度纬度;参数3:多边形边数;参数4:中心点范围,单位米,最大值位5000000;参数6:高德地图APIkey;参数7:请求头; 参数8:大类名称;参数9: calculate_location(stationName, centerLon, centerLat, num, radius, GaoDeKey, headers, bigType, PoiTypeOfPath)

POI文件内容文件内容(高德地图开放平台,百度地图的内容不一样)如下,去开发者文档里找,里面有下载链接

如果想要使用,首先要把库安装好,然后把下图的参数值改成自己的就行。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3