使用Bing Maps API与folium时坐标结果不一致问题排查
Bing Maps API获取坐标与距离出现不一致问题
问题描述
我通过Bing Maps API获取地址坐标及距离时,发现同一起始地址在JSON响应中返回的坐标不一致,想请教这是我的代码存在问题,还是API响应本身就有较大差异?
背景信息
- 输入数据源:包含起始地址、配送地址的Excel文件(附图)
- 代码实现如下:
import urllib.parse import requests from haversine import haversine, Unit import pandas as pd df = df[['Starting Address', 'Delivery Address', 'Driving Distance (Miles)', 'Radial Distance (Miles)']] df = df.reset_index() for index, row in df.iterrows(): # 编码地址 enc_start = urllib.parse.quote(df['Starting Address'][index], safe='') print(enc_start) enc_del = urllib.parse.quote(df['Delivery Address'][index], safe='') print(enc_del) # 调用API url = f"http://dev.virtualearth.net/REST/V1/Routes/Driving?wp.0={enc_start}&wp.1={enc_del}&distanceUnit=mi&optmz=distance&key={bingMapsKey}" response = requests.get(url).json() # 获取JSON格式的API响应 try: # 从bbox中提取起始/配送地址坐标 s_lat = response["resourceSets"][0]["resources"][0]["bbox"][2] # 起始地址纬度 s_lon = response["resourceSets"][0]["resources"][0]["bbox"][3] # 起始地址经度 d_lat = response["resourceSets"][0]["resources"][0]["bbox"][0] # 配送地址纬度 d_lon = response["resourceSets"][0]["resources"][0]["bbox"][1] # 配送地址经度 coords_start = (s_lat, s_lon) # 起始地址坐标 coords_del = (d_lat, d_lon) # 配送地址坐标 print("c_str ", coords_start) print("c_del ", coords_del) # 获取优化后的驾车距离 travelDistance = response["resourceSets"][0]["resources"][0]["travelDistance"] print("travel dist ", travelDistance) df.loc[[index], 'Driving Distance (Miles)'] = travelDistance # folium.Marker(location=[d_lat, d_lon], popup = df["Delivery Address"][index]).add_to(mc) # 创建输出地图 except IndexError: pass # 计算直线距离 radialDistance = haversine(coords_start, coords_del, unit=Unit.MILES) df.loc[[index], 'Radial Distance (Miles)'] = radialDistance
输出异常
同一起始地址多次调用API后,返回的坐标值存在差异(附图)
问题原因及解决方案
1. 核心问题:用边界框(bbox)提取坐标完全错误
你当前从bbox中提取坐标的逻辑是错误的。Bing Maps路由API返回的bbox是整个驾车路线覆盖的地理范围,格式为[西南纬度, 西南经度, 东北纬度, 东北经度],并不是起始/终点的精准坐标。每次路线规划的路径可能因实时路况、道路优先级等因素略有差异,导致边界框变化,所以你提取的“起始坐标”其实是边界框的东北角,自然会出现不一致。
2. 正确的坐标提取方式
应该从路线的routeLegs节点下的startLocation/endLocation获取精准的起始/终点坐标:
# 替换原有的坐标提取代码 route = response["resourceSets"][0]["resources"][0] # 起始地址坐标 start_coords = route["routeLegs"][0]["startLocation"]["point"]["coordinates"] s_lat, s_lon = start_coords[0], start_coords[1] # 配送地址坐标 end_coords = route["routeLegs"][0]["endLocation"]["point"]["coordinates"] d_lat, d_lon = end_coords[0], end_coords[1]
3. 其他优化建议
- 地址精度优化:如果输入的起始地址不够精确(比如仅包含城市名),Bing Maps的地理编码服务可能返回不同的默认点位(如城市中心不同位置)。建议使用规范的地址格式(包含街道、门牌号、邮编)。
- API版本升级:你使用的
REST/V1是旧版API,建议升级到REST/V8版本,响应结构更稳定,功能更完善。 - 异常处理修复:原代码
except: IndexError的写法错误,应明确捕获异常,且异常发生时避免执行后续的直线距离计算(否则会复用之前的坐标值,导致错误数据)。
修正后的核心代码片段
try: route = response["resourceSets"][0]["resources"][0] # 获取准确的起始/终点坐标 start_coords = route["routeLegs"][0]["startLocation"]["point"]["coordinates"] s_lat, s_lon = start_coords[0], start_coords[1] end_coords = route["routeLegs"][0]["endLocation"]["point"]["coordinates"] d_lat, d_lon = end_coords[0], end_coords[1] coords_start = (s_lat, s_lon) coords_del = (d_lat, d_lon) print("c_str ", coords_start) print("c_del ", coords_del) travelDistance = route["travelDistance"] print("travel dist ", travelDistance) df.loc[index, 'Driving Distance (Miles)'] = travelDistance except IndexError as e: print(f"处理行{index}时出错: {e}") # 异常时设置默认值或跳过 df.loc[index, 'Driving Distance (Miles)'] = None df.loc[index, 'Radial Distance (Miles)'] = None else: # 仅在无异常时计算直线距离 radialDistance = haversine(coords_start, coords_del, unit=Unit.MILES) df.loc[index, 'Radial Distance (Miles)'] = radialDistance
内容的提问来源于stack exchange,提问作者Norwegian Salmon
相关产品推荐
相关产品推荐

