如何使用 Overpass API 精准查询指定城市的兴趣点(POI)

1次阅读

如何使用 Overpass API 精准查询指定城市的兴趣点(POI)

本文详解如何通过 overpass api 正确获取纽约市等城市范围内的兴趣点(如餐厅、公园、博物馆等),涵盖地理区域定位误区、推荐查询策略、nominatim 预处理技巧及可复用的 python 实现方案。

本文详解如何通过 overpass api 正确获取纽约市等城市范围内的兴趣点(如餐厅、公园、博物馆等),涵盖地理区域定位误区、推荐查询策略、nominatim 预处理技巧及可复用的 python 实现方案。

在 OpenStreetMap 生态中,Overpass API 是查询结构化地理数据的核心工具,但新手常因对 OSM 数据模型理解不足而遭遇查询失败。例如,直接使用 area[“name”=”New York City”] 无法命中目标区域——因为 OSM 中该行政实体的真实名称是 “City of New York”(见 OSM Relation #175905),而非日常简称。更关键的是,OSM 的 area 元素并非按“城市名”索引,而是依赖标准化标签组合(如 place=city + name=*)或层级化行政边界。

✅ 推荐做法:先通过 Nominatim 获取城市边界 ID,再交由 Overpass 查询 POI
这是最健壮、可泛化的方案,避免硬编码名称歧义,同时支持全球任意城市:

import requests  def get_city_pois(city_name: str, amenities: list = None, tourism: bool = True):     if amenities is None:         amenities = ["cafe", "restaurant", "park", "museum", "library", "cinema"]      # Step 1: Use Nominatim to resolve city boundary     nominatim_url = "https://nominatim.openstreetmap.org/search"     params = {         "q": city_name,         "format": "json",         "limit": 1,         "polygon_geojson": 0     }     resp = requests.get(nominatim_url, params=params, timeout=10)     resp.raise_for_status()     data = resp.json()     if not data:         raise ValueError(f"City '{city_name}' not found in Nominatim")      osm_id = data[0]["osm_id"]     osm_type = data[0]["osm_type"]  # 'relation', 'way', or 'node'      # Step 2: Build Overpass query using resolved area ID     area_id = f"{osm_type[0].upper()}{osm_id}"  # e.g., 'R175905'     amenity_filter = " | ".join([f'["amenity"="{a}"]' for a in amenities])     tourism_filter = '["tourism"]' if tourism else ''      overpass_query = f"""[out:json][timeout:60]; area({area_id})->.searchArea; (   node["amenity"](area.searchArea);   way["amenity"](area.searchArea);   relation["amenity"](area.searchArea);   node{tourism_filter}(area.searchArea);   way{tourism_filter}(area.searchArea);   relation{tourism_filter}(area.searchArea); ); out center;"""      # Step 3: Execute Overpass query     overpass_url = "https://overpass-api.de/api/interpreter"     result = requests.post(overpass_url, data={"data": overpass_query}, timeout=120)     result.raise_for_status()     return result.json()  # 示例:获取纽约市的咖啡馆与公园 try:     nyc_pois = get_city_pois("New York City", amenities=["cafe", "park"])     print(f"Found {len(nyc_pois['elements'])} POIs") except Exception as e:     print(f"Error: {e}")

⚠️ 注意事项:

  • 不要依赖 name= 标签直接构造 area 查询:OSM 中 name 存在多语言变体(name:en, alt_name)、拼写差异(”NYC” vs “New York”)及行政层级混淆(如 NYC 是 city,而纽约州是 state)。
  • 优先使用 place=city + name= 组合定位(仅限简单场景):
    [out:json]; area["place"="city"]["name"="City of New York"]->.nyc; node(area.nyc)["amenity"]; out;

    但此法稳定性远低于 Nominatim 方案,且不适用于无 place=city 标签的自治市(如部分欧洲城市)。

  • 性能优化:对大都市(如 NYC),建议添加 bbox 限制或使用 out body; 替代 out center; 获取完整几何;若只需坐标,out center; 更轻量。
  • 合规性提醒:Nominatim 有 使用政策,需添加 User-Agent 头并避免高频请求;生产环境建议自建 Nominatim 或使用商业 API(如 Photon)。

总结而言,将地理编码(Nominatim)与空间查询(Overpass)解耦,是构建可靠、可扩展 POI 提取管道的关键设计模式。它既规避了 OSM 数据标签的语义不确定性,又为多城市批量处理提供了清晰接口——你的下个项目,只需传入城市名,即可获得精准、结构化的兴趣点数据集。

text=ZqhQzanResources