Python实战:用高德地图API批量获取地址所属街道并写回Excel

在日常的数据处理工作中,我们经常需要根据公司、事件或门店的注册地址 ,批量获取其所在的街道信息 ,例如"浦东新区张江镇""徐汇区龙华街道"等。 手动查询显然低效,而借助 Python + 高德地图API,我们可以轻松实现自动化批量查询并将结果写入 Excel 文件中。

本文将完整展示一个从 Excel 读取地址 → 调用高德API → 获取街道 → 写回Excel的实用脚本,并讲解实现细节与优化思路。


一、功能概述

这段脚本的功能可以总结为四步:

  1. 从 Excel 文件中读取地址数据;
  2. 调用高德地图地理编码(geocode)与逆地理编码(regeo)接口获取街道名称;
  3. 自动将查询结果写回到 Excel 的新列中;
  4. 对查询失败的地址进行重试与记录,保证数据尽量完整。

二、项目依赖与准备工作

在开始之前,请确保安装以下依赖:

bash 复制代码
pip install pandas openpyxl requests

并在高德开放平台申请一个 API Key,申请地址为: 👉 lbs.amap.com/api/webserv...

拿到 key 后,将它填入脚本开头的配置部分:

python 复制代码
key = "你的高德API_KEY"

三、核心逻辑讲解

1. Excel文件读取与列处理

脚本使用 pandas 和 openpyxl 结合读取 Excel 文件:

python 复制代码
df = pd.read_excel(input_file)
if '注册地址' not in df.columns:
    df['注册地址'] = df.iloc[:,16]
addresses = df['注册地址'].tolist()

这段代码首先读取整个 Excel,然后确认是否存在"注册地址"列; 如果没有,则自动取第 17 列(索引16)作为地址列,保证兼容不同格式的表格。

随后,脚本用 openpyxl 打开同一个文件,以保留单元格样式,准备写入新的"街道"列:

python 复制代码
wb = load_workbook(input_file)
ws = wb.active
ws.insert_cols(target_col)
ws.cell(row=header_row_index, column=target_col, value="街道")

这样既能读取数据,又能保持表格原有格式,方便下游人员直接查看。


2. 调用高德API获取街道信息

核心的查询函数如下:

python 复制代码
def get_street_from_amap(address, retries=max_retries):
    if not isinstance(address, str) or not address.strip():
        return ""
    for attempt in range(1, retries+1):
        try:
            geo_resp = requests.get(
                "https://restapi.amap.com/v3/geocode/geo",
                params={"key": key, "address": address, "city": "上海"},
                timeout=15
            ).json()

            if not geo_resp.get("geocodes"):
                continue

            location = geo_resp["geocodes"][0]["location"]

            regeo_resp = requests.get(
                "https://restapi.amap.com/v3/geocode/regeo",
                params={"key": key, "location": location, "extensions": "base", "radius":500},
                timeout=15
            ).json()

            if regeo_resp.get("regeocode"):
                township = regeo_resp["regeocode"]["addressComponent"].get("township","") or ""
                return township
        except Exception as e:
            print(f"[尝试 {attempt}/{retries}] 地址查询失败: {address}, 错误: {e}")
        time.sleep(sleep_time + random.random()*0.5)
    return None

这段逻辑分为两步:

  1. 正向地理编码(geocode):根据地址字符串获取经纬度;
  2. 逆向地理编码(regeo):根据经纬度反查街道名称(township)。

并加入了异常重试机制 与随机延时,防止频繁请求触发高德API限流。


3. 批量查询与缓存优化

查询过程通过循环实现:

python 复制代码
cache = {}
failed_addresses = []

for row_idx, addr in enumerate(addresses, start=header_row_index+1):
    if not isinstance(addr,str) or not addr.strip():
        ws.cell(row=row_idx, column=target_col, value="")
        continue
    if addr in cache:
        township = cache[addr]
    else:
        township = get_street_from_amap(addr)
        if township is None:
            failed_addresses.append((row_idx, addr))
            township = ""
        cache[addr] = township
        time.sleep(sleep_time + random.random()*0.5)
    ws.cell(row=row_idx, column=target_col, value=township)

这里有几个优化点:

  • 缓存(cache)机制:如果同一地址出现多次,只请求一次;
  • 延时策略 :sleep_time + random.random()*0.5,避免被API风控;
  • 实时进度输出:每50行打印一次进度。

4. 失败重试与错误记录

对于第一次查询失败的地址,脚本会自动发起第二轮重查:

python 复制代码
if failed_addresses:
    print(f"第一次查询失败地址共 {len(failed_addresses)} 条,开始自动重查......")
    still_failed = []
    for row_idx, addr in failed_addresses:
        township = get_street_from_amap(addr)
        if township is None:
            still_failed.append((row_idx, addr))
            township = ""
        cache[addr] = township
        ws.cell(row=row_idx, column=target_col, value=township)
        time.sleep(sleep_time + random.random()*0.5)
    failed_addresses = still_failed

最终仍查询失败的地址会被写入单独的 Excel 文件:

python 复制代码
if failed_addresses:
    df_fail = pd.DataFrame([addr for _, addr in failed_addresses], columns=["地址"])
    df_fail.to_excel(failed_file, index=False)

这样可以方便人工二次处理,比如手动调整地址格式或补录缺失信息。


四、运行结果

执行脚本后,控制台会显示类似输出:

复制代码
已处理 50 行,最近地址:上海市浦东新区张江路123号 → 张江镇
已处理 100 行,最近地址:上海市浦东新区川沙路56号 → 川沙新镇
第一次查询失败地址共 5 条,开始自动重查......
完成,已保存:事件列表-上海浦东-带街道.xlsx
最终仍失败的地址已保存到 查询失败地址.xlsx

最终输出文件中会新增一列"街道",完整保留原有格式:

注册地址 街道
上海市浦东新区张江路123号 张江镇
上海市浦东新区川沙路56号 川沙新镇

五、实用建议与扩展方向

  1. 批量查询速度控制

    • 高德API对单IP有请求频率限制,建议控制每秒请求数。
    • 若数据量大,可考虑多线程+限速队列模式。
  2. 地址清洗预处理

    • 可先对地址进行正则清洗,去掉多余标点、括号、空格等,提高命中率。
  3. 多城市适配

    • 当前城市固定为"上海",可通过参数配置实现全国适配。
  4. 异常日志记录

    • 建议在重查阶段输出更多日志,例如返回状态码、错误类型,方便调试。
  5. 接口替代方案

    • 若数据量巨大,可以使用高德地图的批量地理编码接口(支持最多 10 条一次),进一步提升效率。

六、总结

本文通过一个实战案例展示了如何用 Python + 高德地图API 实现"批量地址→街道归属"的自动化处理。 整个过程涵盖了数据读取、接口调用、异常重试、结果写回等完整流程,既是一个实用工具脚本,也体现了 Python 在数据自动化中的强大能力。

核心亮点:

模块 功能
pandas + openpyxl 高效读取与写入 Excel
requests 调用高德API进行地理解析
缓存与重试机制 提高查询稳定性与速度
自动生成失败文件 方便人工补录与质量控制

如果你日常需要处理大量企业、门店、事件地址,这个脚本可以帮你节省大量时间。


相关推荐
川石课堂软件测试4 小时前
学习软件测试需掌握的一些知识
数据库·python·sql·功能测试·网络协议·mysql·http
万化冥合4 小时前
PyBox屏幕键盘如何辅助演示键盘操作?
python·计算机外设
车软学堂4 小时前
从测试转开发,到底要补什么
网络·人工智能·python·功能测试·单片机·车载系统·自动化
天空依然蔚蓝4 小时前
分享一个自动检测网站在线状态的python程序
python·运维开发·1024程序员节
岁月宁静5 小时前
一个 AI 项目从本地到上线,要经过哪些步骤?全流程讲清楚
python·docker·agent
Cosolar5 小时前
不收费、不加水印、数据归你:我做了个开源的在线简历工具
后端·面试·前端框架
codists5 小时前
《crafting interpreters》阅读笔记:p45-p45
python
曲径海盗6 小时前
【Python 学习第 41 天】for 循环
python·学习笔记·编程入门
摇滚侠7 小时前
《On Java 中文版 基础卷》阅读笔记 实现隐藏 11
java·笔记·python
小蒜学长7 小时前
基于Spring Boot+Vue3的在线医疗咨询系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·在线问诊·在线医疗咨询系统