You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用geopy库获取哥伦比亚城市列表?解决KeyError: address报错

问题分析与解决

原代码的错误点

  • 无效地址导致location为None:你用的"Calle 1, Ciudad, Colombia"是虚构地址,geolocator.geocode()会返回None,直接访问location.raw会触发错误,后续的location.raw['address']自然会引发KeyError。
  • 错误解析locality字段:即使地理编码成功,location.raw['address']['locality']是单个字符串(比如某个城市名),不是列表,遍历它会逐个字符拆分,完全不符合需求。
  • Nominatim单条查询无法直接获取全国城市列表:Nominatim是地理编码工具,不是行政区划数据集,直接查国家无法返回所有城市。

正确实现方案

要获取哥伦比亚城市列表并入库,我们可以通过Nominatim的搜索接口批量获取城市数据,再处理后存入数据库,以下是完整步骤:

1. 基础配置与错误处理

首先确保请求合法(Nominatim要求设置合理的user_agent,且避免高频请求),并处理geocode返回None的情况:

import time
import sqlite3
from geopy.geocoders import Nominatim
from geopy.exc import GeocoderTimedOut, GeocoderServiceError

# 初始化地理编码器,替换成你的应用标识
geolocator = Nominatim(user_agent="colombia-city-scraper")
# 数据库连接(SQLite示例,可替换为MySQL/PostgreSQL)
conn = sqlite3.connect('colombia_cities.db')
cursor = conn.cursor()
# 创建城市表
cursor.execute('''
CREATE TABLE IF NOT EXISTS cities (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    latitude REAL,
    longitude REAL,
    country TEXT DEFAULT 'Colombia'
)
''')
conn.commit()

2. 批量获取哥伦比亚城市数据

通过Nominatim的搜索接口,指定查询关键词和国家过滤,分页获取结果(注意Nominatim有请求频率限制,需加延时):

def get_colombia_cities(page=1, limit=50):
    cities = []
    try:
        # 搜索哥伦比亚的城市,结构化参数过滤
        results = geolocator.geocode(
            query={'country': 'Colombia', 'featuretype': 'city'},
            exactly_one=False,
            limit=limit,
            page=page
        )
        if not results:
            return cities
        
        for result in results:
            # 提取城市名、经纬度
            city_name = result.raw.get('display_name', '').split(',')[0].strip()
            lat = result.latitude
            lon = result.longitude
            cities.append((city_name, lat, lon))
        return cities
    except (GeocoderTimedOut, GeocoderServiceError):
        # 超时或服务错误时重试一次
        time.sleep(2)
        return get_colombia_cities(page, limit)

# 循环获取多页结果(根据需求调整页数)
page_num = 1
while True:
    print(f"获取第 {page_num} 页数据...")
    city_data = get_colombia_cities(page=page_num)
    if not city_data:
        break
    # 批量插入数据库
    cursor.executemany('''
    INSERT OR IGNORE INTO cities (name, latitude, longitude)
    VALUES (?, ?, ?)
    ''', city_data)
    conn.commit()
    page_num += 1
    # 遵守Nominatim的请求限制,每次请求后延时
    time.sleep(1)

3. 验证与关闭资源

# 查询数据库中的城市数量
cursor.execute('SELECT COUNT(*) FROM cities')
print(f"共存入 {cursor.fetchone()[0]} 个哥伦比亚城市")

# 关闭连接
conn.close()

注意事项

  • Nominatim使用限制:Nominatim禁止大规模爬虫,若需要完整的哥伦比亚城市列表,建议使用专门的行政区划数据集(比如GeoNames),再用geopy补充经纬度信息。
  • 数据去重:使用INSERT OR IGNORE避免重复入库,确保城市名唯一性。
  • 请求频率:必须添加延时(至少1秒),否则会被Nominatim封禁IP。

内容的提问来源于stack exchange,提问作者MR Santy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 12:14:55