9万条地址调用Google Geocoder API:iterrows/itertuples失效求助
问题根源拆解
- IndexError:和
iterrows()无关,核心是Google Geocoder API返回的response['results']为空列表——要么是单条地址格式无效无法解析,要么是9万条请求触发了API的速率/配额限制,导致API返回空结果。 - itertuples()的ValueError:
itertuples()返回的是namedtuple实例,不是(i, row)的二元组,强行拆成两个变量必然报错。正确用法是遍历每个tuple,通过属性访问字段。 - itertuples()的KeyError:你大概率还是用了
df.at[i, ...]的写法,但itertuples()的元素不是索引值,用它当键访问DataFrame自然会触发KeyError。
修复后的完整代码方案
import requests import pandas as pd import time from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # 初始化带重试机制的会话,应对API限流/服务器错误 session = requests.Session() retry = Retry( total=5, # 最多重试5次 backoff_factor=1, # 重试间隔:1s→2s→4s... status_forcelist=[429, 500, 502, 503, 504] # 遇到这些状态码自动重试 ) adapter = HTTPAdapter(max_retries=retry) session.mount("https://", adapter) session.mount("http://", adapter) API_KEY = "你的API密钥" base_url = "https://maps.googleapis.com/maps/api/geocode/json" # 读取数据集 df = pd.read_excel("你的地址文件.xlsx") # 提前初始化坐标列,避免循环中动态添加的性能开销 df['Geo_Lat_New'] = None df['Geo_Lng_New'] = None # 使用itertuples遍历,性能远高于iterrows for row in df.itertuples(index=True): # index=True保留行索引 idx = row.Index # 拼接地址,自动过滤空值,避免生成",,城市"这类无效格式 address_parts = [ str(row.adresse1) if pd.notna(row.adresse1) else "", str(row.postnr) if pd.notna(row.postnr) else "", str(row.By) if pd.notna(row.By) else "" ] apiAddress = ",".join(part for part in address_parts if part.strip()) # 跳过空地址 if not apiAddress.strip(): print(f"行{idx}地址为空,跳过") continue parameters = { 'key': API_KEY, 'address': apiAddress } try: response = session.get(base_url, params=parameters).json() # 先检查API返回状态,避免直接取results[0]报错 if response.get('status') != 'OK': print(f"行{idx}处理失败,状态:{response.get('status')},地址:{apiAddress}") continue # 提取坐标 geometry = response['results'][0]['geometry'] lat = geometry['location']['lat'] lng = geometry['location']['lng'] # 写入数据 df.at[idx, 'Geo_Lat_New'] = lat df.at[idx, 'Geo_Lng_New'] = lng # 速率控制:免费版配额是每秒5次,付费版可提至每秒50次,按需调整 time.sleep(0.2) except Exception as e: print(f"行{idx}发生异常:{str(e)},地址:{apiAddress}") continue # 保存结果 df.to_excel("带坐标的地址文件.xlsx", index=False) print(df.head(10))
关键优化说明
- 异常防护:
- 检查API返回的
status字段(比如ZERO_RESULTS表示地址无法解析,OVER_QUERY_LIMIT表示配额耗尽),避免直接访问空列表报错。 - 全局异常捕获,单个地址处理失败不会中断整个批量任务,同时记录错误信息方便后续排查。
- 检查API返回的
- itertuples正确用法:
- 开启
index=True获取行索引,用df.at[idx, ...]写入数据,避免KeyError。 - 通过
tuple属性名(如row.adresse1)访问字段,比df.at访问效率更高。
- 开启
- API请求稳定性:
- 带重试的会话:遇到限流、服务器错误时自动重试,减少请求失败率。
- 速率控制:
time.sleep(0.2)确保不超过API的请求频率限制,付费用户可缩短间隔。
- 数据预处理:
- 过滤空地址字段,避免生成无效的API请求参数。
- 提前初始化坐标列,降低循环中的性能开销。
额外注意事项
- 检查Google Cloud配额:Geocoder API免费版每天仅2500次请求,9万条数据必须升级付费配额,否则会触发
OVER_QUERY_LIMIT。 - 考虑批量请求:API支持最多50个地址/批量请求,能大幅减少总请求次数,提升处理效率(需调整请求格式为
batch模式)。 - 缓存重复地址:如果数据中有大量重复地址,可先缓存已解析的坐标,避免重复请求浪费配额。
内容的提问来源于stack exchange,提问作者Mathijs Blekkenhorst
相关产品推荐
相关产品推荐

