运行环境:Jupyter notebook(python 3.12.7)
维度 |
chinese-address-parser |
高德API |
---|---|---|
准确性 |
中(依赖规则) |
高(基于海量数据+AI模型) |
功能范围 |
仅地址结构解析 |
地址解析、地理编码、逆地理编码、POI搜索等 |
复杂地址处理 |
弱(无法处理模糊输入) |
强(支持语义分析、别名匹配) |
经纬度获取 |
不支持 |
支持(地理编码接口返回经纬度) |
网络依赖 |
无需网络 |
必须联网 |
成本 |
免费 |
免费额度有限,超量需付费(0.3元/次) |
适用场景 |
离线、小批量标准化地址 |
在线、高精度、复杂场景 |
chinese-address-parser不支持直接获取经纬度,
因此为了解析出标准地址和经度纬度,这里主要使用的是高德API。
方法与步骤
(1)准备地图API KEY
申请高德地图KEY + 百度地图AK(免费版一般够用)→ 高德和百度双API验证。
(2)密钥循环器
个人开发者key日限额5000次(免费),如果超出5000次的数据量 就要用到多个key(借同学同事的),可使用intertools.cycle创建密钥循环器。
(3)地址及辅助信息做拼接
根据需要调整ADDRESS_COLS
地址拼接列,例如我需要用到“所在地”+“医疗机构名称”+“详细地址”拼接出原始地址,这样可以避免“详细地址”字段为空的情况。
(4)获取经纬度(地理编码)
-
使用地图API的地理编码功能,获取:经度 | 纬度
-
通过地图API获取:省 | 市 | 区 + 标准地址
(5)置信度检测与交叉验证
-
API置信度
-
同时调用百度/腾讯API,对比经纬度偏差
(6)导出结果
-
运行过程每10条显示进度信息
-
导出EXCEL,保留了所有原始字段
-
颜色标注关键状态列,对于偏差较大的结果可进行人工核验
代码
确保安装相关包:
pip install pandas requests geopy openpyxl
-
适用于≤5000条数据的代码,单独高德API版 + 无交叉验证
import pandas as pd
import requests
from geopy.distance import geodesic
from openpyxl import load_workbook
from openpyxl.styles import PatternFill
import time
# 配置参数
GAODE_KEY = '替换高德key' # 替换为你的高德密钥
INPUT_FILE = r'C:\Users\User\Desktop\新建文件夹\副本.xlsx' #输入文件
OUTPUT_FILE = r'C:\Users\User\Desktop\新建文件夹\TEST.xlsx' #输出文件
SHEET_NAME = 'Sheet1'
ADDRESS_COLS = ['所在地', '医疗机构名称', '详细地址'] #拼接字段
RATE_LIMIT = 0.1 # 请求间隔(秒)
def gaode_geocode(address, api_key):
"""高德地理编码"""
url = f"https://restapi.amap.com/v3/geocode/geo?address={address}&key={api_key}"
try:
response = requests.get(url, timeout=5)
data = response.json()
if data.get('status') == '1' and data.get('count') != '0':
geo = data['geocodes'][0]
province = geo.get('province', '')
city = geo.get('city', province) # 处理直辖市
return {
'gaode_省份': province,
'gaode_城市': city,
'gaode_区县': geo.get('district', ''),
'gaode_标准地址': geo.get('formatted_address', ''),
'gaode_经度': geo.get('location', '').split(',')[0] if geo.get('location') else '',
'gaode_纬度': geo.get('location', '').split(',')[1] if geo.get('location') else '',
'gaode_解析状态': '成功',
'gaode_置信度': geo.get('level', '')
}
return {
'gaode_省份': '',
'gaode_城市': '',
'gaode_区县': '',
'gaode_标准地址': '',
'gaode_经度': '',
'gaode_纬度': '',
'gaode_解析状态': f"失败: {data.get('info', '未知错误')}",
'gaode_置信度': ''
}
except Exception as e:
return {
'gaode_省份': '',
'gaode_城市': '',
'gaode_区县': '',
'gaode_标准地址': '',
'gaode_经度': '',
'gaode_纬度': '',
'gaode_解析状态': f"异常: {str(e)}",
'gaode_置信度': ''
}
def validate_with_district_center(row):
"""行政区划中心验证"""
if row['gaode_解析状态'] != '成功' or not row['gaode_经度']:
return '无法验证'
try:
district = row['gaode_区县'] or row['gaode_城市'] or row['gaode_省份']
url = f"https://restapi.amap.com/v3/config/district?keywords={district}&key={GAODE_KEY}"
resp = requests.get(url, timeout=5)
data = resp.json()
if data['status'] == '1' and data['districts']:
center = data['districts'][0]['center'].split(',')
center_lng, center_lat = float(center[0]), float(center[1])
target_lng = float(row['gaode_经度'])
target_lat = float(row['gaode_纬度'])
distance = geodesic((center_lat, center_lng), (target_lat, target_lng)).km
if distance < 3:
return f'准确(距中心{distance:.1f}km)'
return f'偏差较大(距中心{distance:.1f}km)'
return '获取中心失败'
except:
return '验证异常'
def process_excel(input_file, output_file, sheet_name, address_cols):
"""处理Excel主流程"""
df = pd.read_excel(input_file, sheet_name=sheet_name)
# 校验地址列
missing_cols = [col for col in address_cols if col not in df.columns]
if missing_cols:
raise ValueError(f"缺少必要列: {missing_cols}")
print(f"开始处理 {len(df)} 条记录...")
results = []
for index, row in df.iterrows():
# 拼接地址
address = ''.join(str(row[col]).strip() for col in address_cols if pd.