You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用pd.json_normalize处理嵌套JSON转DataFrame遇KeyError问题求助

问题描述

尝试将URL返回的JSON响应转换为Pandas DataFrame时,在提取嵌套数据环节出错。

现有代码

import requests
import json
import numpy as np
from pandas import json_normalize 

series = 'f1'
season = 2022
ssnround = '1'
laps = 3
url = "http://ergast.com/api/f1/2011/5/laps/1.json"
record_path = ['Races']
meta = ['driverId', 'position', 'time']

r = requests.get(url = url)

data = json.loads(r.content)

df = pd.json_normalize(data)
df

目标是生成包含所有driverId、车手位置(position)和单圈用时(time)的表格,但调用df = pd.json_normalize(data, record_path, meta)时触发KeyError:Key 'Record_Path' not found. If specifying a record_path, all elements of data should have the path.,问题出在哪里?

返回的JSON结构

{
  "MRData": {
    "xmlns": "http://ergast.com/mrd/1.5",
    "series": "f1",
    "url": "http://ergast.com/api/f1/2011/5/laps/1.json",
    "limit": "30",
    "offset": "0",
    "total": "24",
    "RaceTable": {
      "season": "2011",
      "round": "5",
      "Races": [
        {
          "season": "2011",
          "round": "5",
          "url": "http://en.wikipedia.org/wiki/2011_Spanish_Grand_Prix",
          "raceName": "Spanish Grand Prix",
          "Circuit": {
            "circuitId": "catalunya",
            "url": "http://en.wikipedia.org/wiki/Circuit_de_Barcelona-Catalunya",
            "circuitName": "Circuit de Barcelona-Catalunya",
            "Location": {
              "lat": "41.57",
              "long": "2.26111",
              "locality": "Montmeló",
              "country": "Spain"
            }
          },
          "date": "2011-05-22",
          "time": "12:00:00Z",
          "Laps": [
            {
              "number": "1",
              "Timings": [
                {
                  "driverId": "alonso",
                  "position": "1",
                  "time": "1:34.494"
                },
                {"driverId": "vettel","position": "2","time": "1:35.274"},
                {"driverId": "webber","position": "3","time": "1:36.329"},
                {"driverId": "hamilton","position": "4","time": "1:36.991"},
                {"driverId": "petrov","position": "5","time": "1:38.084"},
                {"driverId": "michael_schumacher","position": "6","time": "1:38.633"},
                {"driverId": "rosberg","position": "7","time": "1:39.139"},
                {"driverId": "massa","position": "8","time": "1:39.979"},
                {"driverId": "buemi","position": "9","time": "1:40.611"},
                {"driverId": "button","position": "10","time": "1:40.998"},
                {"driverId": "perez","position": "11","time": "1:41.433"},
                {"driverId": "alguersuari","position": "12","time": "1:41.876"},
                {"driverId": "maldonado","position": "13","time": "1:42.255"},
                {"driverId": "resta","position": "14","time": "1:42.808"},
                {"driverId": "trulli","position": "15","time": "1:43.553"},
                {"driverId": "kovalainen","position": "16","time": "1:44.276"},
                {"driverId": "heidfeld","position": "17","time": "1:45.164"},
                {"driverId": "sutil","position": "18","time": "1:46.107"},
                {"driverId": "liuzzi","position": "19","time": "1:46.737"},
                {"driverId": "barrichello","position": "20","time": "1:47.077"},
                {"driverId": "glock","position": "21","time": "1:47.556"},
                {"driverId": "karthikeyan","position": "22","time": "1:48.183"},
                {"driverId": "ambrosio","position": "23","time": "1:48.573"},
                {"driverId": "kobayashi","position": "24","time": "1:57.590"}
              ]
            }
          ]
        }
      ]
    }
  }
}

解决方案

问题根源

  1. 路径定位错误:传入json_normalize的data是完整JSON对象,但Races字段不在顶层,而是嵌套在MRData -> RaceTable下;同时你要提取的目标字段(driverId/position/time)实际在Races -> Laps -> Timings数组中,并非Races的直接子元素。
  2. 参数用法混淆:meta参数用于保留父层级的额外字段,而非指定要提取的目标字段,你完全搞反了这个参数的用途。

修正代码

基础版本(仅提取目标字段)

import requests
import pandas as pd
from pandas import json_normalize

url = "http://ergast.com/api/f1/2011/5/laps/1.json"

r = requests.get(url=url)
data = r.json()  # 直接用r.json()简化操作,无需手动解析

# 指定完整嵌套路径到Timings数组
df = json_normalize(
    data,
    record_path=['MRData', 'RaceTable', 'Races', 'Laps', 'Timings']
)

print(df)

运行后会得到包含driverId、position、time三列的DataFrame,每条车手单圈数据对应一行。

进阶版本(保留父级字段)

如果需要同时显示赛季、轮次、圈数等信息,可通过meta参数添加父层级字段,并自定义列名:

df = json_normalize(
    data,
    record_path=['MRData', 'RaceTable', 'Races', 'Laps', 'Timings'],
    meta=[
        ['MRData', 'RaceTable', 'season'],
        ['MRData', 'RaceTable', 'round'],
        ['MRData', 'RaceTable', 'Races', 'Laps', 'number']
    ]
)

# 重命名列名提升可读性
df.rename(columns={
    'MRData.RaceTable.season': '赛季',
    'MRData.RaceTable.round': '轮次',
    'MRData.RaceTable.Races.Laps.number': '圈数'
}, inplace=True)

内容的提问来源于stack exchange,提问作者Doug Sack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:01:20