Parse JSON menggunakan Python?

18

Saya memiliki file JSON members.jsonseperti di bawah ini.

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

Saya ingin menguraikannya menggunakan bashskrip dapatkan hanya daftar bidang memberId.

Output yang diharapkan adalah:

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

Saya mencoba menambahkan kode bash + python berikut ke .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'"]';
}

Dan kemudian memanggil:

$ cat members.json | getJsonVal "memberId"

Tapi itu melempar:

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

Referensi

/programming//a/21595107/432903

prayagupd
sumber
2
Mengapa Anda perlu melakukan ini di bash? Anda jelas menggunakan python di sini jadi mengapa tidak membuat skrip python yang melakukan pekerjaan? Anda mungkin tidak mendapatkan jawaban aktual tentang cara melakukannya dengan bash karena ketika Anda harus melakukan itu banyak, Anda menggunakan bahasa lain.
DavidG
Saya mengubah judul Anda dari "menggunakan skrip bash" menjadi "using python" karena python, dan tidak bash, adalah apa yang Anda gunakan untuk mengurai json. Misalnya, kesalahan itu tentu saja kesalahan python, bukan kesalahan bash.
goldilocks
@goldilocks hanya karena usahanya digunakan python, tidak berarti tujuannya adalah untuk menggunakanpython
jordanm
@ DavidG melihat jawaban saya. Ini bukan shell murni, ini adalah perintah eksternal tetapi terintegrasi dengan skrip shell dengan cukup baik.
jordanm
Bisakah saya menyarankan Anda mengambil sebagian besar bidang yang tidak relevan di json. Cukup memiliki 2-3 elemen di _source untuk mendapatkan intisari dari apa yang Anda coba lakukan. Sisanya hanya mengalihkan perhatian
Anthon

Jawaban:

25

Jika Anda akan menggunakan:

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

Anda dapat memeriksa struktur kamus bersarang objdan memastikan bahwa baris asli Anda harus dibaca:

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

ke elemen "memberId" itu. Dengan cara ini Anda dapat menjaga Python sebagai oneliner.

Jika ada beberapa elemen dalam elemen "hit" bersarang, maka Anda dapat melakukan sesuatu seperti:

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

Solusi Chris Down lebih baik untuk menemukan nilai tunggal untuk kunci (unik) di tingkat mana pun.

Dengan contoh kedua saya yang mencetak beberapa nilai, Anda mencapai batas apa yang harus Anda coba dengan satu liner, pada saat itu saya melihat sedikit alasan mengapa melakukan setengah dari pemrosesan dalam bash, dan akan pindah ke solusi Python lengkap .

Anthon
sumber
8

Cara lain untuk melakukan ini di bash adalah menggunakan jshon . Berikut ini solusi untuk masalah Anda menggunakan jshon:

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

The -epilihan ekstrak nilai dari json tersebut. The -aiterates atas array dan -udecode string akhir.

jordanm
sumber
Biarkan saya menginstal jshon
prayagupd
6

Nah, kunci Anda cukup jelas bukan pada akar objek. Coba sesuatu seperti ini:

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

Ini memiliki keuntungan tidak hanya dengan menyuntikkan sintaks ke Python, yang dapat menyebabkan kerusakan (atau lebih buruk, eksekusi kode arbitrer).

Anda dapat menyebutnya seperti ini:

json_key hits hits 0 _source memberId < members.json
Chris Down
sumber
1
Catatan: Ini tidak akan berulang setiap item dalam "hits". Jika Anda menginginkannya, Anda harus menulis kode Python khusus untuk contoh itu.
Chris Down
Tetapi itu hanya menunjukkan satu anggota ID.
prayagupd
4

Alternatif lain adalah jq :

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

Coba ini:

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


Jika Anda sudah memiliki pretty printedjson, mengapa Anda tidak melakukannya saja grep?

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

Anda selalu bisa mendapatkan format yang cukup dicetak dengan python simplejson untuk grepitu.

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

Gunakan kesedihan:

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

Setelah itu, cukup grephasilkan dengan pola 'memberId'.

Untuk sepenuhnya tepat:

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

Pemakaian:

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

Mengikuti utas ini saya akan menggunakan json.tool dengan python:

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

superk
sumber
0

Menggunakan deepdiff Anda tidak perlu tahu kunci yang tepat:

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

Inilah solusi bash.

  1. buat file find_members.sh
  2. tambahkan baris berikut ke file + save

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

Sekarang jalankan:

$ ./find_members.sh

memberIds
----------------
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
mikrofon
sumber