Phân tích cú pháp JSON bằng Python?


18

Tôi có một tệp JSON members.jsonnhư dưới đây.

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

Tôi muốn phân tích cú pháp bằng cách sử dụng bashtập lệnh chỉ lấy danh sách trường memberId.

Sản lượng dự kiến ​​là:

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

Tôi đã thử thêm mã bash + python sau đây vào .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'"]';
}

Và sau đó gọi:

$ cat members.json | getJsonVal "memberId"

Nhưng nó ném:

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

Tài liệu tham khảo

/programming//a/21595107/432903


2
Tại sao bạn cần phải làm điều này trong bash? Bạn rõ ràng đang sử dụng python ở đây, vậy tại sao không tạo một kịch bản python mà thực hiện công việc? Bạn có thể không nhận được câu trả lời thực tế về cách làm điều đó với bash bởi vì khi bạn cần làm điều đó nhiều, bạn sử dụng ngôn ngữ khác.
DavidG

Tôi đã thay đổi tiêu đề của bạn từ "sử dụng kịch bản bash" để "sử dụng python" từ python, chứ không phải bashlà những gì bạn đang sử dụng để phân tích cú pháp JSON. Ví dụ, lỗi đó chắc chắn là lỗi python, không phải lỗi bash.
goldilocks

@goldilocks chỉ vì nỗ lực của anh ta được sử dụng python, không có nghĩa là mục tiêu của anh ta là sử dụngpython
jordanm

@DavidG xem câu trả lời của tôi. Nó không phải là shell thuần, nó là một lệnh bên ngoài nhưng nó tích hợp vào các shell script khá tốt.
jordanm

Tôi có thể đề nghị bạn loại bỏ hầu hết các lĩnh vực không liên quan trong json không. Nó có đủ 2-3 yếu tố trong _source để có được ý chính của những gì bạn cố gắng làm. Phần còn lại chỉ làm mất tập trung
Anthon

Câu trả lời:


25

Nếu bạn sẽ sử dụng:

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

bạn có thể kiểm tra cấu trúc của dictonary lồng nhau objvà thấy rằng dòng ban đầu của bạn nên đọc:

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

đến phần tử "thành viên" đó. Bằng cách này, bạn có thể giữ Python như một oneliner.

Nếu có nhiều phần tử trong phần tử "hit" lồng nhau, thì bạn có thể làm một cái gì đó như:

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

Giải pháp của Chris Down là tốt hơn cho việc tìm một giá trị duy nhất cho các khóa (duy nhất) ở mọi cấp độ.

Với ví dụ thứ hai của tôi in ra nhiều giá trị, bạn đang đạt đến giới hạn của những gì bạn nên thử với một lớp lót, tại thời điểm đó tôi thấy ít lý do tại sao phải thực hiện một nửa quá trình xử lý trong bash và sẽ chuyển sang một giải pháp Python hoàn chỉnh .


8

Một cách khác để làm điều này trong bash là sử dụng jshon . Đây là một giải pháp cho vấn đề của bạn bằng cách sử dụng jshon:

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

Các -etùy chọn trích xuất các giá trị từ json. Các -alặp qua mảng và -ugiải mã chuỗi thức.


Hãy để tôi cài đặt jshon
nguyện

6

Chà, chìa khóa của bạn khá rõ ràng không nằm ở gốc của đối tượng. Hãy thử một cái gì đó như thế này:

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

Điều này có lợi ích không chỉ đơn giản là tiêm cú pháp vào Python, mà có thể gây ra sự cố (hoặc tệ hơn là thực thi mã tùy ý).

Sau đó bạn có thể gọi nó như thế này:

json_key hits hits 0 _source memberId < members.json

1
Lưu ý: Điều này sẽ không lặp qua từng mục trong "lần truy cập". Nếu bạn muốn điều đó, bạn nên viết mã Python cụ thể cho trường hợp đó.
Chris Xuống

Nhưng nó chỉ hiển thị một thành viên.
nguyện

4

Một cách khác là jq :

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

2

Thử đi:

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


Nếu bạn đã có pretty printedjson, tại sao bạn không chỉ grepnó?

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

Bạn luôn có thể có được một định dạng in đẹp với python Simplejson cho grepnó.

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

Sử dụng bãi rác:

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

Sau đó, chỉ cần grepkết quả với mẫu 'thành viên'.

Để hoàn toàn chính xác:

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

Sử dụng:

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


0

Sử dụng deepdiff bạn không cần biết các phím chính xác:

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

0

Đây là một giải pháp bash.

  1. tạo tập tin find_members.sh
  2. thêm dòng sau vào tập tin + lưu

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

Bây giờ chạy nó:

$ ./find_members.sh

memberIds
----------------
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.