Python 批量解析 Excel 经纬度,调用高德地图 API 获取中文地址

一、前言

在项目开发过程中,经常会遇到只有 GPS 经纬度,没有具体地址的数据,例如车辆轨迹、人员定位、设备定位等。

如下图所示,Excel 中保存了经纬度信息:

GIS_LON GIS_LAT GIS_LON_O GIS_LAT_O
121.473701 31.230416 121.473680 31.230390

希望最终生成:

GIS_LON GIS_LAT GIS_LON_O GIS_LAT_O 完整地址 区县 街道
121.473701 31.230416 121.473680 31.230390 上海市黄浦区人民大道100号 上海市 上海市 黄浦区 南京东路街道

本文介绍如何使用 Python + 高德地图 Web 服务 API 实现 Excel 经纬度批量解析中文地址。


二、准备工作

1、申请高德地图 Key

访问高德开放平台:

https://lbs.amap.com/

注册开发者账号。

进入:

text 复制代码
控制台
    ↓
我的应用

创建应用时,应用类型必须选择:

text 复制代码
Web 服务(Web Service)

注意:

不要创建 Android、iOS 或 Web 端(JS API) Key,否则调用接口会报:

text 复制代码
USERKEY_PLAT_NOMATCH
infocode:10009

创建完成后,复制生成的 Key,例如:

text 复制代码
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

三、安装依赖

安装所需 Python 库:

bash 复制代码
pip install pandas requests openpyxl tqdm

四、高德逆地理编码接口

接口地址:

text 复制代码
https://restapi.amap.com/v3/geocode/regeo

请求示例:

text 复制代码
https://restapi.amap.com/v3/geocode/regeo?key=你的Key&location=121.473701,31.230416

返回结果:

json 复制代码
{
  "status":"1",
  "regeocode":{
      "formatted_address":"上海市黄浦区人民大道100号",
      "addressComponent":{
          "province":"上海市",
          "city":"上海市",
          "district":"黄浦区",
          "township":"南京东路街道"
      }
  }
}

五、Python 完整代码

python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import time
import requests
import pandas as pd
from tqdm import tqdm

# ======================================================
# 配置
# ======================================================

# 高德Key
AMAP_KEY = ""

# 输入文件
INPUT_FILE = "0012.xlsx"

# 输出文件
OUTPUT_FILE = "baidu-gis-out.xlsx"

# 是否使用原始坐标(N、O)
USE_ORIGINAL = False

# 高德API
API = "https://restapi.amap.com/v3/geocode/regeo"

# ======================================================
# 缓存
# ======================================================

cache = {}

# ======================================================
# 查询地址
# ======================================================


def reverse_geocode(lon, lat):

    key = f"{lon},{lat}"

    if key in cache:
        return cache[key]

    params = {
        "key": AMAP_KEY,
        "location": key,
        "extensions": "all",
        "radius": 100
    }

    try:

        r = requests.get(API, params=params, timeout=10)

        data = r.json()

        if data["status"] != "1":
            print(data)
            return {}

        regeocode = data["regeocode"]

        component = regeocode.get("addressComponent", {})

        result = {
            "地址": regeocode.get("formatted_address", ""),
            "省": component.get("province", ""),
            "市": component.get("city", ""),
            "区县": component.get("district", ""),
            "街道": component.get("township", ""),
            "门牌号": component.get("streetNumber", {}).get("number", ""),
            "POI": ""
        }

        pois = regeocode.get("pois", [])

        if len(pois) > 0:
            result["POI"] = pois[0].get("name", "")

        cache[key] = result

        return result

    except Exception as e:

        print("查询失败:", key, e)

        return {}

# ======================================================
# 主程序
# ======================================================

print("读取Excel...")

df = pd.read_excel(INPUT_FILE)

query_lon = []
query_lat = []

address = []
province = []
city = []
district = []
township = []
street = []
poi = []

print("开始解析地址...")

for _, row in tqdm(df.iterrows(), total=len(df)):

    if USE_ORIGINAL:

        lon = row["GIS_LON_O"]
        lat = row["GIS_LAT_O"]

    else:

        lon = row["GIS_LON"]
        lat = row["GIS_LAT"]

    query_lon.append(lon)
    query_lat.append(lat)

    if pd.isna(lon) or pd.isna(lat):

        address.append("")
        province.append("")
        city.append("")
        district.append("")
        township.append("")
        street.append("")
        poi.append("")

        continue

    result = reverse_geocode(lon, lat)

    address.append(result.get("地址", ""))
    province.append(result.get("省", ""))
    city.append(result.get("市", ""))
    district.append(result.get("区县", ""))
    township.append(result.get("街道", ""))
    street.append(result.get("门牌号", ""))
    poi.append(result.get("POI", ""))

    # 防止QPS过高
    time.sleep(0.05)

# ======================================================
# 新增列
# ======================================================

df["查询经度"] = query_lon
df["查询纬度"] = query_lat
df["完整地址"] = address
df["省"] = province
df["市"] = city
df["区县"] = district
df["街道"] = township
df["门牌号"] = street
df["POI"] = poi

# ======================================================
# 保存
# ======================================================

df.to_excel(OUTPUT_FILE, index=False)

print()
print("======================================")
print("完成!")
print("输出文件:", OUTPUT_FILE)
print("共解析:", len(df), "条")
print("缓存命中:", len(cache), "个唯一坐标")
print("======================================")

六、运行效果

原始 Excel:

GIS_LON GIS_LAT
121.473701 31.230416

运行程序:

text 复制代码
开始解析...

100%|████████████████████|161585/161585

解析完成!
输出文件:坐标_解析结果.xlsx

生成新的 Excel:

GIS_LON GIS_LAT 查询经度 查询纬度 完整地址 区县 街道
121.473701 31.230416 121.473701 31.230416 上海市黄浦区人民大道100号 上海市 上海市 黄浦区 南京东路街道

七、常见问题

1、ImportError: cannot import name 'tqdm'

原因:

脚本命名为:

text 复制代码
tqdm.py

Python 导入时会优先加载当前目录,导致循环引用。

解决方法:

修改脚本名称,例如:

text 复制代码
reverse_geocode.py

同时删除:

text 复制代码
__pycache__

2、USERKEY_PLAT_NOMATCH(10009)

错误:

text 复制代码
USERKEY_PLAT_NOMATCH

原因:

创建了错误类型的 Key。

解决方法:

重新创建:

text 复制代码
Web 服务(Web Service)

不要使用:

  • Android
  • iOS
  • Web端(JS API)

3、为什么部分地址为空?

可能原因:

  • 经纬度为空。
  • 经纬度超出中国区域。
  • 海上坐标。
  • 高德暂无对应地址。
  • 网络请求失败。

八、优化建议

如果数据量较大(例如几万甚至几十万条),建议增加以下优化:

  • 缓存机制:相同坐标只查询一次,减少 API 请求次数。
  • 失败重试:网络异常时自动重试,提升成功率。
  • 限速控制:避免超过高德 API 的 QPS 限制。
  • 断点续跑:程序中断后可继续执行,无需重新解析全部数据。
  • 本地缓存:使用 SQLite 保存已解析结果,后续重复运行无需再次请求。

九、总结

本文介绍了如何使用 Python + Pandas + 高德地图 Web 服务 API,实现 Excel 经纬度批量转换中文地址。

整个流程包括:

  1. 申请高德 Web 服务 Key。
  2. 调用逆地理编码接口。
  3. 批量读取 Excel 中的经纬度。
  4. 将解析得到的地址信息写入新的 Excel 文件。
  5. 保留原始数据并新增地址字段。

对于一般业务场景,这套方案简单易用;如果需要处理几十万甚至上百万条数据,可以进一步增加缓存、重试、限速和断点续跑等能力,以满足生产环境的大规模数据处理需求。

相关推荐
金銀銅鐵1 小时前
[Python] 为 Vole 机器语言实现图形化界面
python·程序员
观远数据1 小时前
从离线开发到实时同步:DataFlow如何支撑企业级数据治理闭环
java·windows·microsoft·excel
小林ixn2 小时前
Python基础全梳理:从注释到函数,这些细节你都掌握了吗?
python·编程语言
nzz_1712142 小时前
PHP程序员转型AI岗位指南:核心技能、北京就业市场与转型路径分析
开发语言·人工智能·php
Risehuxyc2 小时前
C# 将doc转换为docx
开发语言·c#·xhtml
今天AI了吗2 小时前
Hermes Agent 搭建全流程:从本机试跑到可持续运行的个人 AI Agent
java·人工智能·python·学习·embedding
tianyatest3 小时前
表格分类统计及排序
java·excel·暖通
多加点辣也没关系3 小时前
JavaScript|第24章:事件循环与并发模型
开发语言·javascript·ecmascript
为啥全要学3 小时前
自注意力中随着根号dk的增大,qk点积的方差为什么也会增大
python·深度学习