JSON mit Python analysieren?

18

Ich habe eine JSON-Datei members.jsonwie unten.

{
   "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"
            }
         }
      ]
   }
}

Ich möchte es mit bashSkript analysieren, um nur die Liste der Felder zu erhalten memberId.

Die erwartete Ausgabe ist:

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

Ich habe versucht, folgenden Bash + Python-Code hinzuzufügen .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'"]';
}

Und dann genannt:

$ cat members.json | getJsonVal "memberId"

Aber es wirft:

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

Referenz

/programming//a/21595107/432903

Gebet
quelle
2
Warum müssen Sie dies in Bash tun? Sie verwenden hier eindeutig Python. Warum also nicht einfach ein Python-Skript erstellen, das die Arbeit erledigt? Möglicherweise erhalten Sie keine konkreten Antworten auf die Vorgehensweise mit bash, da Sie eine andere Sprache verwenden, wenn Sie so viel tun müssen.
DavidG
Ich habe Ihren Titel von "using bash script" in "using python" geändert, da Sie mit json pythonnicht bashanalysieren. ZB ist dieser Fehler sicherlich ein Python-Fehler, kein Bash-Fehler.
Goldlöckchen
@ Goldilocks nur, weil sein Versuch verwendet python, bedeutet nicht, sein Ziel ist es zu verwendenpython
Jordan
@DavidG siehe meine Antwort. Es ist keine reine Shell, sondern ein externer Befehl, der sich aber gut in Shell-Skripte einfügt.
Jordanien
Kann ich vorschlagen, dass Sie die meisten irrelevanten Felder im json entfernen. Es reicht aus, 2-3 Elemente in _source zu haben, um einen Überblick über das zu bekommen, was Sie versuchen. Der Rest lenkt nur ab
Anthon

Antworten:

25

Wenn Sie verwenden würden:

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

Sie können die Struktur des verschachtelten Diktonals überprüfen objund sehen, dass Ihre ursprüngliche Zeile lauten sollte:

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

zu dem Element "memberId". Auf diese Weise können Sie den Python als Oneliner behalten.

Wenn das verschachtelte "hits" -Element mehrere Elemente enthält, können Sie Folgendes tun:

$ 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
'

Die Lösung von Chris Down ist besser, um einen einzelnen Wert für (eindeutige) Schlüssel auf jeder Ebene zu finden.

Mit meinem zweiten Beispiel, das mehrere Werte ausgibt, stoßen Sie an die Grenzen dessen, was Sie mit einem Einzeiler versuchen sollten. An diesem Punkt sehe ich keinen Grund, die Hälfte der Verarbeitung in bash durchzuführen, und würde zu einer vollständigen Python-Lösung übergehen .

Anthon
quelle
8

Eine andere Möglichkeit, dies in bash zu tun, ist die Verwendung von jshon . Hier ist eine Lösung für Ihr Problem mit jshon:

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

Die -eOptionen extrahieren Werte aus dem json. Der -aiteriert über das Array und -udecodiert die endgültige Zeichenfolge.

Jordanien
quelle
Lassen Sie mich jshon
prayagupd
6

Nun, Ihr Schlüssel ist ganz klar nicht an der Wurzel des Objekts. Versuchen Sie so etwas:

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)' "$@"
}

Dies hat den Vorteil, dass nicht nur Syntax in Python eingefügt wird, was zu Fehlern führen kann (oder schlimmer noch, die Ausführung von willkürlichem Code).

Sie können es dann so nennen:

json_key hits hits 0 _source memberId < members.json
Chris Down
quelle
1
Hinweis: Dadurch werden nicht alle Elemente in "Treffern" durchlaufen. Wenn Sie das möchten, sollten Sie einen bestimmten Python-Code für diese Instanz schreiben.
Chris Down
Es wird jedoch nur eine memberId angezeigt.
Gebet
4

Eine andere Alternative ist jq :

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

Versuche dies:

$ cat json.txt | python -c 'import sys; import simplejson as json; \
print "\n".join( [i["_source"]["memberId"] for i in json.loads( sys.stdin.read() )["hits"]["hits"]] )'


Wenn Sie bereits pretty printedjson haben, warum machen Sie grepes dann nicht einfach so?

$ cat json.txt | grep memberId
               "memberId": "0x7b93910446f91928e23e1043dfdf5bcf",
               "memberId": "0x7b93910446f91928e23e1043dfdf5bcG",

Sie können immer ein hübsches gedrucktes Format mit SimpleJson Python erhalten grep.

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

Verwenden Sie Dumps:

# cat json_raw.txt | python -c 'import sys; import simplejson as json; \
print json.dumps( json.loads( sys.stdin.read() ), sort_keys=True, indent=4); '

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

Danach führen Sie einfach grepdas Muster 'memberId' aus.

Um genau zu sein:

#!/bin/bash

filename="$1"
cat $filename | python -c 'import sys; import simplejson as json; \
print json.dumps( json.loads( sys.stdin.read() ), sort_keys=True, indent=4)' | \
grep memberId | awk '{print $2}' | sed -e 's/^"//g' | sed -e 's/",$//g'

Verwendung:

$ bash bash.sh json_raw.txt 
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
user2496
quelle
0

Nach diesem Thread würde ich json.tool in Python verwenden:

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

Superk
quelle
0

Bei Verwendung von deepdiff müssen Sie die genauen Schlüssel nicht kennen:

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

Hier ist eine Bash-Lösung.

  1. erstelle Datei find_members.sh
  2. Füge die folgende Zeile zu file + save hinzu

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

Führen Sie es jetzt aus:

$ ./find_members.sh

memberIds
----------------
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
Mike
quelle