在循环中跳过JSON输出

0 投票
2 回答
681 浏览
提问于 2025-04-18 02:54

我正在用Python从Steam的API提取数据。我有一个随机生成的Steam ID列表。问题是,并不是所有这些ID都指向有效的账户。当我尝试访问一个没有对象值的账户时,程序会报“KeyError”的错误。Steam的API会为每个请求输出一个['response']层级的对象,所以当我打印这个最上层的内容时,我会得到每个请求的响应。然而,如果我再深入一层(比如['response']['game_count']),当程序遇到一个没有['game_count']值的账户时,就会出错。请问我该如何告诉Python跳过这些账户呢?

示例输出:

有游戏的账户(为了更清晰,去掉了多余的换行)

{
"response": {
    "game_count": 1,
    "games": [
        {
            "appid": 205790,
            "playtime_forever": 0
        }
    ]
}

没有游戏的账户

{
    "response": {
    }
}

我现在的代码:

import urllib2, random, sys, json

list = open('d:\python\SteamUserIDs.txt').read().splitlines()
SteamID = str(list)


for SteamID in list[0:10:1]:
    request = urllib2.Request('http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=05475AE5A8410CE01236A8A29E1DEE8E&steamid=%s&format=json' %SteamID, headers={"User-Agent": "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36"})
    response = json.load(urllib2.urlopen(request))
    request2 = urllib2.Request('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0001/?key=05475AE5A8410CE01236A8A29E1DEE8E&steamids=%s&format=json' %SteamID, headers={"User-Agent": "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36"})
    response2 = json.load(urllib2.urlopen(request2))

2 个回答

0

像这样吗?

你遇到的这个“键错误”是因为 game_count 这个键不存在。在进行其他操作之前(比如打印),先检查一下这个键是否存在。

for response in steam_id_responses:
    if response.get('game_count', None):
        print response
2

这里有几个选择。

  • 第一个选择是使用 innot in。需要注意的是,如果你看到有人建议使用 has_key(),千万不要用。这个方法在 Python 2.x 中已经不推荐使用,在 Python 3.x 中被移除了。你应该使用 in 操作符。

如果字典 d 中有键 key,就返回 True,否则返回 False。

if 'game_count' in response:
    # Do something

或者,使用 not 的版本:

if 'game_count' not in response:
    # skip/pass on this record
else:
    # Do something
  • 下一个选择,正如其他回答中提到的,是 get 方法。

如果键 key 在字典中,就返回这个键对应的值,否则返回默认值。如果没有提供默认值,默认值是 None,这样这个方法就不会抛出 KeyError 错误。

if response.get('game_count', None):
    # Do something
else:
    # skip/pass on this record

更新: 你对响应没有做任何处理。这就是为什么看起来没有任何变化。

你的代码还有一些需要修正的地方:

  • 你对 API 的调用有些多余。你可以在一次调用中传递最多 100 个 SteamID。你不需要为每个 ID 一次调用一次。
  • 不要把你的变量命名为 list
  • SteamID = str(list) 是没有意义的,因为你在循环中重新使用了 SteamID 变量。

这是你代码的一个稍微修改过的版本。

steam_ids = open('d:\python\SteamUserIDs.txt').read().splitlines()
steam_str = ','.join(steam_ids)    # This make a comma separated string that we will use in our API calls 

owned_games = {}

for s in steam_ids:
    request = urllib2.Request('http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=<<YOURKEY>>&steamid=%s&format=json' % s,headers={"User-Agent": "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36"})
    response = json.load(urllib2.urlopen(request))['response']
    if response.get('game_count', None):
        owned_games[s] = response['game_count']
    else:
        owned_games[s] = None

# This call will only work if you have less than 100 steam ids. If you have more, you
# will need to build steam_str differently for batches of 100
request2 = urllib2.Request('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0001/?key=<<YOURKEY>>&steamids=%s&format=json' %steam_str, headers={"User-Agent": "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36"})
response2 = json.load(urllib2.urlopen(request2))

最后,你会得到一个 owned_games 字典,内容大致如下(示例中的个人资料 ID 不准确)。

{'76561197992702437': 63,
 '76561197992702438': 0,
 '76561197992702439': 0,
 '76561197995066524': 62,
 '76561197995066525': 0,
 '76561197995066526': 0,
 '76561197995066527': 0}

这个字典显示了每个个人资料拥有多少游戏。然后,在你的 response2 对象中,你可以遍历 response2['response']['players'] 中的每个项目来进行比较。或者,你可以把 players 列表重建成一个字典(或者和 games_owned 合并,这样你就不需要每次都遍历列表来找到合适的个人资料。不过,这两个练习超出了你最初问题的范围)。

现在,你需要查看 responseresponse2 中的数据,以便进行解析。

撰写回答