web-dev-qa-db-ja.com

Pythonを使用してJSONを解析しますか?

以下のようなJSONファイルmembers.jsonがあります。

{
   "took": 670,
   "timed_out": false,
   "_shards": {
      "total": 8,
      "successful": 8,
      "failed": 0
   },
   "hits": {
      "total": 74,
      "max_score": 1,
      "hits": [
         {
            "_index": "2000_270_0",
            "_type": "Medical",
            "_id": "02:17447847049147026174478:174159",
            "_score": 1,
            "_source": {
               "memberId": "0x7b93910446f91928e23e1043dfdf5bcf",
               "memberFirstName": "Uri",
               "memberMiddleName": "Prayag",
               "memberLastName": "Dubofsky"
            }
         }, 
         {
            "_index": "2000_270_0",
            "_type": "Medical",
            "_id": "02:17447847049147026174478:174159",
            "_score": 1,
            "_source": {
               "memberId": "0x7b93910446f91928e23e1043dfdf5bcG",
               "memberFirstName": "Uri",
               "memberMiddleName": "Prayag",
               "memberLastName": "Dubofsky"
            }
         }
      ]
   }
}

bashスクリプトを使用して解析したいのですが、フィールドmemberIdのリストのみを取得します。

予想される出力は次のとおりです。

memberIds
----------- 
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG

次のbash + pythonコードを.bashrcに追加してみました:

function getJsonVal() {
   if [ \( $# -ne 1 \) -o \( -t 0 \) ]; then
       echo "Usage: getJsonVal 'key' < /tmp/file";
       echo "   -- or -- ";
       echo " cat /tmp/input | getJsonVal 'key'";
       return;
   fi;
   cat | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["'$1'"]';
}

そして呼ばれる:

$ cat members.json | getJsonVal "memberId"

しかし、それは投げます:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
KeyError: 'memberId'

参照

https://stackoverflow.com/a/21595107/4329

18
prayagupd

使用する場合:

 $ cat members.json | \
     python -c 'import json,sys;obj=json.load(sys.stdin);print obj;'

ネストされた辞書objの構造を調べて、元の行が次のようになることを確認できます。

$ cat members.json | \
    python -c 'import json,sys;obj=json.load(sys.stdin);print obj["hits"]["hits"][0]["_source"]["'$1'"]';

その「memberId」要素に。このようにして、Pythonをワンライナーとして維持できます。

ネストされた「ヒット」要素に複数の要素がある場合は、次のようにすることができます。

$ cat members.json | \
python -c '
import json, sys
obj=json.load(sys.stdin)
for y in [x["_source"]["'$1'"] for x in obj["hits"]["hits"]]:
    print y
'

Chris Downのソリューションは、任意のレベルで(一意の)キーの単一の値を見つけるのに適しています。

複数の値を出力する2番目の例では、1つのライナーで何を試すべきかという限界に達しています。その時点で、bashで処理の半分を行う理由はほとんどなく、完全なPythonソリューション。

27
Anthon

Bashでこれを行う別の方法は、 jshon を使用することです。 jshonを使用した問題の解決策は次のとおりです:

$ jshon -e hits -e hits -a -e _source -e memberId -u < foo.json
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG

-eオプションは、jsonから値を抽出します。 -aは配列と-uは、最終的な文字列をデコードします。

8
jordanm

まあ、あなたのキーはオブジェクトのルートにないことは明らかです。このようなものを試してください:

json_key() {
    python -c '
import json
import sys

data = json.load(sys.stdin)

for key in sys.argv[1:]:
    try:
        data = data[key]
    except TypeError:  # This is a list index
        data = data[int(key)]

print(data)' "$@"
}

これには、単に構文をPythonに挿入するだけでなく、破損(またはさらに悪いことに、任意のコード実行)を引き起こす可能性があるという利点があります。

その後、次のように呼び出すことができます。

json_key hits hits 0 _source memberId < members.json
6
Chris Down

別の選択肢は jq です:

$ cat members.json | jq -r '.hits|.hits|.[]|._source|.memberId'
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
4
hudolejev

これがbashソリューションです。

  1. ファイルを作成find_members.sh
  2. 次の行をファイルに追加して保存します

    #!/bin/bash
    
    echo -e "\nmemberIds\n---------"
    cat members.json | grep -E 'memberId'|awk '{print$2}' | cut -d '"' -f2
    
  3. chmod +x find_members.sh

今それを実行します:

$ ./find_members.sh

memberIds
----------------
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
0
mike

以下 このスレッド Pythonでjson.toolを使用します。

python -m json.tool members.json | awk -F'"' '/memberId/{print $4}'

0
superk

deepdiff を使用すると、正確なキーを知る必要はありません。

import json
from deepdiff import DeepSearch
DeepSearch(json.load(open("members.json", "r")), 'memberId', verbose_level=2)['matched_paths'].values()
0
serv-inc