8

Python で JSON 配列をクエリする方法を理解しようとしています。簡単な検索を行い、かなり複雑な配列を印刷する方法を教えてください。

私が使用している例は次のとおりです: http://eu.battle.net/api/wow/realm/status

たとえば、「Silvermoon」サーバーを見つけて、その「人口」を出力し、次に「Wintergrasp」配列内の「controlling-faction」を出力する方法を知りたいです。

現在、配列スニペットは次のようになっています。

{"type":"pve","population":"high","queue":false,"wintergrasp":{"area":1,"controlling-faction":0,"status":0,"next":1382350068792},"tol-barad":{"area":21,"controlling-faction":0,"status":0,"next":1382349141932},"status":true,"name":"Silvermoon","slug":"silvermoon","battlegroup":"Cyclone / Wirbelsturm","locale":"en_GB","timezone":"Europe/Paris"}

現時点では、メイン配列にアクセスできますが、無駄に見える別の新しい変数にすべてをコピーしないと、サブ配列にアクセスできないようです。次のようなことができるようになりたいです

import urllib2
import json

req = urllib2.Request("http://eu.battle.net/api/wow/realm/status", None, {})
opener = urllib2.build_opener()
f = opener.open(req)

x = json.load(f)  # open the file and read into a variable

# search and find the Silvermoon server
silvermoon_array = ????

# print the population
print silvermoon_array.????

# access the Wintergrasp sub-array
wintergrasp_sub = ????
print wintergrasp_sub.????  # print the controlling-faction variable

これは、他のものにアクセスする方法を理解するのに本当に役立ちます。

4

3 に答える 3

13

Python のインタラクティブ モードは、構造化データを段階的に探索する優れた方法です。たとえば、silvermoon サーバー データにアクセスする方法を見つけるのは簡単です。

>>> data=json.load(urllib2.urlopen("http://eu.battle.net/api/wow/realm/status"))
>>> type(data)
<type 'dict'>
>>> data.keys()
[u'realms']
>>> type(data['realms'])
<type 'list'>
>>> type(data['realms'][0])
<type 'dict'>
>>> data['realms'][0].keys()
[u'status', u'wintergrasp', u'battlegroup', u'name', u'tol-barad', u'locale', u'queue', u'timezone', u'type', u'slug', u'population']
>>> data['realms'][0]['name']
u'Aegwynn'
>>> [realm['name'] for realm in data['realms']].index('Silvermoon')
212
>>> silvermoon= data['realms'][212]
>>> silvermoon['population']
u'high'
>>> type(silvermoon['wintergrasp'])
<type 'dict'>
>>> silvermoon['wintergrasp'].keys()
[u'status', u'next', u'controlling-faction', u'area']
>>> silvermoon['wintergrasp']['controlling-faction']
>>> silvermoon['population']
u'high'

それらについてまだ知らない場合は、何が起こっているのかを理解するために、 Dictionary.keys 、list.index、およびリストの内包表記を読む必要があります。

データの構造を理解したら、最終的にデータ アクセスを書き直して、もう少し読みやすく効率的にすることができます。

realms= data['realms']
realm_from_name= dict( [(realm['name'], realm) for realm in realms])
print realm_from_name['Silvermoon']['population']
print realm_from_name['Silvermoon']['wintergrasp']['controlling-faction']

配列を別の変数にコピーするのは無駄なので、Python は値を参照渡しすることを知っておく必要があります。つまり、新しい変数に何かを代入するときに、コピーは必要ありません。値渡しと参照渡しの簡単な説明を次に示します。

最後に、あなたはパフォーマンスを過度に心配しているようです。Python の哲学は、まず正しく取得し、後で最適化することです。これが正しく機能していて、より良いパフォーマンスが必要な場合は、時間をかける価値がある場合は最適化してください。

于 2013-10-21T10:14:37.550 に答える
1

これはあなたが望むことをします:

# -*- coding: utf-8 -*-
import json
import urllib2

def searchListOfDicts(listOfDicts, attr, value):
    """
    Loops through a list of dictionaries and returns matching attribute value pair
    You can also pass it slug, silvermoon or type, pve
    returns a list containing all matching dictionaries 
    """
    matches = [record for record in listOfDicts if attr in record and record[attr] == value]
    return matches

def myjsonDict():
    """
    Opens url, grabs json and puts it inside a dictionary
    """
    req = urllib2.Request("http://eu.battle.net/api/wow/realm/status", None, {})
    opener = urllib2.build_opener()
    f = opener.open(req)
    json_dict = json.load(f)
    return json_dict

jsonDict = myjsonDict()
#we want to search inside realms list
silverMoonServers = searchListOfDicts(jsonDict["realms"], "name", "Silvermoon")
#access first dictionary that matched "name, Silvermoon" query
print silverMoonServers[0]
print silverMoonServers[0]["wintergrasp"]
print silverMoonServers[0]["wintergrasp"]["controlling-faction"]
于 2013-10-21T10:05:49.800 に答える
0

Python では、json.loadsjson オブジェクトを python 辞書およびArraysにマップするlistため、通常の pythondictおよびlist構造体と同様に、さらなる操作が行われます。

requestsとでそれを行う方法は次のlamdbasとおりです。

    import json
    import requests

    response = requests.get("http://eu.battle.net/api/wow/realm/status")
    json_data = json.loads(response.text)

    # loop through the list of realms to find the one you need (realm_name)
    get_realm = lambda realm_name, jd: [r for r in jd['realms'] 
                                        if r['name'] == realm_name]

    # extract data you need, if there is a match in the list of realms,
    # return None otherwise
    get_your_data = lambda realm: (
        realm[0]['name'],
        realm[0]['wintergrasp']['controlling-faction']
    ) if realm else None

    print get_your_data(get_realm('Silvermoon', json_data))
于 2013-10-21T09:48:52.440 に答える