Analizzare JSON usando Python?


18

Ho un file JSON members.jsoncome di seguito.

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

Voglio analizzarlo usando lo bashscript ottenere solo l'elenco dei campi memberId.

L'output previsto è:

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

Ho provato ad aggiungere il seguente codice bash + python a .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'"]';
}

E poi chiamato:

$ cat members.json | getJsonVal "memberId"

Ma genera:

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

Riferimento

/programming//a/21595107/432903


2
Perché hai bisogno di farlo in bash? stai chiaramente usando python qui, quindi perché non creare uno script Python che funzioni? Potresti non ottenere risposte effettive su come farlo con bash perché quando hai bisogno di fare così tanto usi un'altra lingua.
DavidG,

Ho cambiato il tuo titolo da "usando bash script" a "usando python" poiché python, e non bash, è quello che stai usando per analizzare json. Ad esempio, quell'errore è certamente un errore Python, non un errore bash.
Riccioli d'oro,

@goldilocks solo perché il suo tentativo ha usato python, non significa che il suo obiettivo è quello di usarepython
Jordan

@DavidG vedi la mia risposta. Non è pura shell, è un comando esterno ma si integra abbastanza bene negli script di shell.
Giordania,

Posso suggerirti di eliminare la maggior parte dei campi irrilevanti nel json. È sufficiente avere 2-3 elementi in _source per ottenere l'essenza di ciò che si tenta di fare. Il resto distrae solo
Anthon,

Risposte:


25

Se tu volessi usare:

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

puoi ispezionare la struttura del dittonario nidificato obje vedere che la tua riga originale dovrebbe leggere:

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

all'elemento "memberId". In questo modo puoi mantenere il Python come oneliner.

Se ci sono più elementi nell'elemento "hit" nidificato, puoi fare qualcosa del tipo:

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

La soluzione di Chris Down è migliore per trovare un singolo valore in chiavi (univoche) a qualsiasi livello.

Con il mio secondo esempio che stampa più valori, stai raggiungendo i limiti di ciò che dovresti provare con un solo liner, a quel punto vedo pochi motivi per cui eseguire metà dell'elaborazione in bash e passare a una soluzione Python completa .


8

Un altro modo per farlo in bash è usare jshon . Ecco una soluzione al tuo problema usando jshon:

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

Le -eopzioni estraggono i valori dal json. -aEsegue l' iterazione sull'array e -udecodifica la stringa finale.


Lasciami installare jshon
prayagupd il

6

Bene, la tua chiave non è chiaramente alla radice dell'oggetto. Prova qualcosa del genere:

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

Questo ha il vantaggio non solo di iniettare la sintassi in Python, che potrebbe causare la rottura (o peggio, l'esecuzione arbitraria di codice).

Puoi quindi chiamarlo così:

json_key hits hits 0 _source memberId < members.json

1
Nota: questo non scorrerà su ogni elemento in "hit". Se lo desideri, dovresti scrivere un codice Python specifico per quell'istanza.
Chris Down,

Ma mostra solo un membro ID.
prayagupd,

4

Un'altra alternativa è jq :

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

2

Prova questo:

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


Se hai già pretty printedjson, perché non lo fai grep?

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

Puoi sempre ottenere un formato piuttosto stampato con simplejson python 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}

Usa discariche:

# 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
}

Successivamente, semplicemente grep risulta con il modello 'memberId'.

Per essere completamente precisi:

#!/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'

Uso:

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


0

Utilizzando deepdiff non è necessario conoscere i tasti esatti:

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

0

Ecco una soluzione bash.

  1. crea file find_members.sh
  2. aggiungi la seguente riga al file + salva

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

Ora eseguilo:

$ ./find_members.sh

memberIds
----------------
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.