【问题标题】:Parsing JSON output efficiently in Python?在 Python 中有效地解析 JSON 输出?
【发布时间】:2026-02-11 07:40:01
【问题描述】:

下面的代码块可以工作,但是由于我对使用 JSON 的理解有限,我不满意它是非常理想的,但我似乎无法找到更有效的方法。

steam_game_db 是这样的:

{
    "applist": {
        "apps": [
            {
                "appid": 5,
                "name": "Dedicated Server"
            },
            {
                "appid": 7,
                "name": "Steam Client"
            },
            {
                "appid": 8,
                "name": "winui2"
            },
            {
                "appid": 10,
                "name": "Counter-Strike"
            }
        ]
    }
}

到目前为止,我的 Python 代码是

i = 0
x = 570

req_name_from_id = requests.get(steam_game_db)
j = req_name_from_id.json()

while j["applist"]["apps"][i]["appid"] != x:
    i+=1
returned_game = j["applist"]["apps"][i]["name"]
print(returned_game)

有没有更聪明的方法来搜索它,而不是遍历整个应用列表?理想情况下,数据结构中具有“appid”和“name”的元素的编号与其对应的“appid”相同

即 列表中的appid 570是Dota2 但是appid 5069和Red Faction中数据结构中的元素570

还有,这是什么类型的数据结构?也许它已经限制了我对这个答案的搜索能力。 (即,对于我来说,每个元素都像是一本包含“appid”和“元素”的字典?)

编辑:按照建议更改为 for 循环

# returned_id string for appid from another query

req_name_from_id = requests.get(steam_game_db)
j_2 = req_name_from_id.json()

for app in j_2["applist"]["apps"]:
    if app["appid"] == int(returned_id):
        returned_game = app["name"]

print(returned_game)

【问题讨论】:

  • 这是一个哈希结构,但最快的方法是将所有内容放入字典中,然后立即进行查找。
  • @user1767754 如果他们只查找一件事,则将整个列表转换为字典平均比只遍历他们想要的内容要慢,尽管随后的查找会很快。
  • 你应该考虑你的代码的intentfor app in j["applist"]["apps"]: 比搞乱i 要清楚得多,例如,如果 ID(当前名为 x,这也没有帮助 - 为什么不 app_id?)不存在 IndexError 的风险没有找到。
  • @jonrsharpe x 对我的坏事没有帮助,我将其更改为一个平淡无奇的变量名以免引起混淆(因为我正在将我的字符串从其他地方转换为 int,它可能看起来位随机/冗余)。我已按照您的建议将其更改为 for ,并且看起来更清晰。找到所需的值后,for循环会继续吗?正如我假设的那样,while循环一旦达到正确的X值就不会继续,从而使用更少的资源?也知道为什么我实际上不需要j 前面的j["applist"]["apps"] 并且它仍然有效吗?
  • 您可以return(如果在函数中)或break在适当的时候结束循环。

标签: python python-3.x python-requests steam steam-web-api


【解决方案1】:

最好将 JSON 文件保存在磁盘上,您可以直接将其转储到字典中并开始构建您的 lookup table。例如,我尝试在使用 dict 进行查找时维护您的逻辑。不要忘记对 JSON 进行编码,它里面有特殊字符。

设置:

import json

f = open('bigJson.json')

apps = {}
with open('bigJson.json', encoding="utf-8") as handle:
    dictdump = json.loads(handle.read())

    for item in dictdump['applist']['apps']:
        apps.setdefault(item['appid'], item['name'])

用法一: 这就是你使用它的方式

for appid in range(0, 570):
    if appid in apps:
        print(appid, apps[appid].encode("utf-8"))

用法 2:这就是查询键的方式,如果未记录 appid,则使用 get 而不是 [] 将防止出现 KeyError 异常。

print(apps.get(570, 0))

【讨论】:

  • 谢谢你,由于我的知识非常有限,我将不得不玩一点。 (特别是编码)
  • 让 JSON 库处理文件加载更容易 (docs)。 data = json.load('bigJson.json')
  • 但是 json.load 期望 file 类似对象?
  • 这很奇怪,我在3.6.3 上,当我在data = json.load('bigJson.json') 上时,我得到str obj has no attribute read
【解决方案2】:

通过键(如此处的应用 ID)访问事物的最便捷方法是使用字典。

您预先支付一点额外的性能成本来填充字典,但之后按 ID 提取值基本上是免费的。

但是,这是一种权衡。如果您只想在 Python 程序的生命周期内进行一次查找,那么与您已经做过的简单循环相比,支付额外的性能成本来构建字典将无益。但是,如果您想进行多次查找,那将是有益的。

# build dictionary
app_by_id = {}
for app in j["applist"]["apps"]:
  app_by_id[app["appid"]] = app["name"]

# use it
print(app_by_id["570"])

还可以考虑在磁盘上缓存 JSON 文件。这将在您的程序启动期间节省时间。

【讨论】:

  • 嗨 Tomalak,我会测试一下。我确实希望重用它,该程序会不断检查他们正在玩的 Steam id 列表,但是随着新游戏的发布,valve 会偶尔更新 api,所以也许从它查询是最好的选择,或者可能是定期的?
  • 嗯,通过网络获取文件需要一段时间。从磁盘加载它会更快。您记得上次刷新它的变量并在它变旧时重新下载它。不幸的是,Steam 服务器似乎不支持 conditional HTTP 这个文件,所以你必须手动跟踪它的年龄。
  • 谢谢,如果只是为了学习新东西,我一定会尝试一下!考虑到每 5 秒循环一次,我想即使每隔几个小时刷新一次也会更有效
  • 当然。而且你也只需要在 HTTP 下载后重新构建字典。
  • P.S.除了变量,您还可以简单地查看文件的最后写入时间,以确定它是否足够旧以证明重新下载的合理性。