Python与Pandas新手:调用邮编API获取经纬度并写入DataFrame时遭遇NotImplementedError问题求助
解决Pandas处理邮编API时的NotImplementedError问题
首先,咱们来拆解你遇到的问题:
错误原因分析
你看到的NotImplementedError是因为**pd.json_normalize()用错了场景**。这个函数是用来把嵌套的JSON结构(比如包含字典的列表)转换成DataFrame的,但parse_json['data']['latitude']是一个单个的数值(字符串或数字类型),不是可迭代的JSON结构,所以用json_normalize处理单个值就会触发这个错误。
另外,你的代码还有一个隐藏问题:在for循环里直接给df_cust["Lat"]和df_cust["Long"]赋值,会导致每次循环都覆盖整列的数据,最后所有行的坐标都会变成最后一个邮编的结果,而不是对应各自的邮编。
修复后的代码方案
下面是修正后的代码,同时加入了异常处理(避免API请求失败导致程序崩溃),并且保证每个邮编对应自己的坐标:
import pandas as pd import requests import json # 假设你的con_str已经正确定义 query_cust = "select custMasterID,Full_Name,POSTCODE from DMON.BANK_CUSTOMERS" df_cust = pd.read_sql(query_cust, con=con_str) df_cust["URL"] = "https://api.getthedata.com/postcode/" + df_cust['POSTCODE'].str.replace(" ", "") # 先初始化Lat和Long列,避免KeyError df_cust["Lat"] = None df_cust["Long"] = None # 遍历每一行,用索引定位赋值 for idx, row in df_cust.iterrows(): url = row["URL"] try: response = requests.get(url) response.raise_for_status() # 检查请求是否成功(比如404、500错误) parse_json = response.json() # 直接用response.json()代替json.loads(response.text)更简洁 # 直接赋值单个数值,不需要json_normalize df_cust.loc[idx, "Lat"] = parse_json['data']['latitude'] df_cust.loc[idx, "Long"] = parse_json['data']['longitude'] except Exception as e: print(f"处理邮编{row['POSTCODE']}时出错: {str(e)}") # 出错时可以选择保留None,或者赋值默认值 df_cust.loc[idx, "Lat"] = None df_cust.loc[idx, "Long"] = None print(df_cust)
关键优化点说明
- 替换json_normalize为直接赋值:因为
latitude和longitude都是单个值,直接提取后赋值给对应行的列即可。 - 用iterrows()遍历行+loc定位:这样能保证每个邮编的坐标对应到自己的行,不会覆盖整列。
- 异常处理:加入
try-except块和response.raise_for_status(),处理API请求失败的情况(比如无效邮编、网络波动),让程序更健壮。 - 简化JSON解析:用
response.json()代替json.loads(response.text),这是requests库提供的更简洁的JSON解析方法。
更高效的Pandas风格写法(可选)
如果你的数据量较大,iterrows()的效率可能不高,可以用apply方法来替代循环:
def get_coords(row): url = row["URL"] try: response = requests.get(url) response.raise_for_status() data = response.json()['data'] return pd.Series([data['latitude'], data['longitude']]) except Exception as e: print(f"处理邮编{row['POSTCODE']}时出错: {str(e)}") return pd.Series([None, None]) # 同时生成Lat和Long列 df_cust[["Lat", "Long"]] = df_cust.apply(get_coords, axis=1)
这种写法更符合Pandas的向量化操作思路,代码也更简洁。
内容的提问来源于stack exchange,提问作者Ujwal Shah
相关产品推荐
相关产品推荐

