Python kullanarak JSON ayrıştırılsın mı?


18

members.jsonAşağıdaki gibi bir JSON dosyam var .

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

Ben bashsadece alan listesini almak komut dosyası kullanarak ayrıştırmak istiyorum memberId.

Beklenen çıktı:

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

Aşağıdaki bash + python kodunu eklemeyi denedim .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'"]';
}

Sonra çağırdı:

$ cat members.json | getJsonVal "memberId"

Ama atar:

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

Referans

/programming//a/21595107/432903


2
Bunu neden bash'da yapmanız gerekiyor? Burada açıkça python kullanıyorsunuz, neden sadece işi yapan bir python betiği oluşturmuyorsunuz? Bunu bash ile nasıl yapacağınıza dair gerçek cevaplar alamayabilirsiniz, çünkü bu kadarını yapmanız gerektiğinde başka bir dil kullanırsınız.
DavidG

Başlığınızı "bash komut dosyasını kullanarak" olarak "python kullanarak " olarak değiştirdim, çünkü json ayrıştırmak için kullandığınız şey bu pythondeğil bash. Örneğin, bu hata kesinlikle bir python hatasıdır, bash hatası değildir.
goldilocks

@goldilocks sadece girişimi kullanıldığı pythoniçin amacının kullanılması olduğu anlamına gelmiyorpython
jordanm

@ DavidG cevabımı gör. Saf kabuk değil, harici bir komut ama kabuk komut dosyalarına oldukça iyi entegre oluyor.
jordanm

Json'daki alakasız alanların çoğunu çıkarmanızı önerebilir miyim? Yapmaya çalıştığınız şeyin özünü elde etmek için _source içinde 2-3 elemente sahip olmak yeterlidir. Gerisi sadece dikkat dağıtıyor
Anthon

Yanıtlar:


25

Kullanacak olursanız:

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

iç içe diktatörün yapısını inceleyebilir ve objorijinal satırınızın okuması gerektiğini görebilirsiniz:

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

bu "memberId" öğesine. Bu şekilde Python'u bir oneliner olarak tutabilirsiniz.

İç içe "isabetler" öğesinde birden çok öğe varsa, şöyle bir şey yapabilirsiniz:

$ 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'ın çözümü, herhangi bir seviyede (benzersiz) tuşlara tek bir değer bulmak için daha iyidir.

Birden fazla değer basan ikinci örneğimle, tek bir astarla denemeniz gereken şeylerin sınırlarını vuruyorsunuz, bu noktada işlemenin yarısını bash'da neden yapmanın pek az sebebini görüyorum ve tam bir Python çözümüne geçiyorum .


8

Bunu bash'da yapmanın başka bir yolu da jshon kullanmaktır . İşte sorununuzu kullanarak bir çözüm jshon:

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

-eSeçenekleri json değerleri ayıklamak. -aDizinin yineler ve -unihai dize çözümler.


Let me install jshon
prayagupd

6

Anahtarınız, nesnenin kökünde açıkça görülmüyor. Bunun gibi bir şey deneyin:

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

Bunun, sadece Python'a sözdizimini enjekte etmemesinin yanı sıra kırılmaya (veya daha kötüsü, rastgele kod yürütülmesine) neden olabileceği avantajı vardır.

Daha sonra şöyle diyebilirsiniz:

json_key hits hits 0 _source memberId < members.json

1
Not: Bu, "isabet" içindeki her öğenin üzerinden geçmeyecektir. Bunu istiyorsanız, bu örnek için belirli bir Python kodu yazmalısınız.
Chris Down

Ancak yalnızca bir üye gösterir.
prayagupd

4

Başka bir alternatif jq :

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

2

Bunu dene:

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


Zaten pretty printedjson'unuz varsa, neden sadece yapmıyorsunuz grep?

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

Simplejson python ile her zaman oldukça basılı bir format elde edebilirsiniz 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}

Dökümleri kullanın:

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

Daha sonra, sadece grep'memberId' deseniyle sonuçlanır.

Tamamen kesin olmak gerekirse:

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

Kullanımı:

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

0

Bu konuyu takiben python içinde json.tool kullanırdım:

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


0

Deepdiff kullanarak tam anahtarları bilmenize gerek yoktur:

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

0

İşte bir bash çözümü.

  1. dosya oluştur find_members.sh
  2. dosyaya aşağıdaki satırı ekle + kaydet

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

Şimdi çalıştırın:

$ ./find_members.sh

memberIds
----------------
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.