使用Python解析JSON?


18

我有一个JSON文件members.json,如下所示。

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

我想使用bash脚本来解析它,仅获取字段列表memberId

预期的输出是:

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

我尝试将以下bash + python代码添加到.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'"]';
}

然后调用:

$ cat members.json | getJsonVal "memberId"

但是它抛出:

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

参考

/programming//a/21595107/432903


2
为什么您需要使用bash进行此操作?您显然在这里使用python,为什么不创建一个可以完成此任务的python脚本呢?您可能无法获得有关如何使用bash的实际答案,因为当您需要做很多事情时,您会使用另一种语言。
DavidG 2014年

我将标题从“使用bash脚本”更改为“使用python”,因为python而不是bash解析JSON时使用的标题。例如,该错误肯定是python错误,而不是bash错误。
goldilocks 2014年

@goldilocks仅仅是因为他尝试过python,并不意味着他的目标是使用python
jordanm 2014年

@DavidG看到我的答案。它不是纯shell,它是一个外部命令,但是可以很好地集成到shell脚本中。
jordanm 2014年

我可以建议您删除json中大多数不相关的字段吗?_source中包含2-3个元素足以了解您尝试执行的操作。其余的只是分散注意力
Anthon 2014年

Answers:


25

如果您使用:

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

您可以检查嵌套字典的结构,obj并看到原始行应显示为:

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

到该“ memberId”元素的位置。这样,您可以将Python保留为一体。

如果嵌套的“ hits”元素中有多个元素,则可以执行以下操作:

$ 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)的解决方案更适合于在任何级别为(唯一)键找到单个值。

在我的第二个示例中,该示例输出了多个值,您已经达到了使用单一衬板尝试的极限,此时,我几乎没有理由在bash中进行一半的处理,而将其转向一个完整的Python解决方案。


8

在bash中执行此操作的另一种方法是使用jshon。这是使用以下方法解决您的问题的方法jshon

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

这些-e选项从json中提取值。在-a迭代的阵列上方和-u最终串进行解码。


让我安装jshon
祈祷

6

好吧,您的密钥很明显不是对象的根。尝试这样的事情:

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

这样做的好处是,不仅将语法简单地注入到Python中,这可能会导致损坏(或更糟糕的是,任意代码执行)。

然后可以这样称呼它:

json_key hits hits 0 _source memberId < members.json

1
注意:这不会循环播放“匹配”中的每个项目。如果需要,应该为该实例编写特定的Python代码。
克里斯·

但是它只显示一个memberId。
祈祷

4

另一个选择是jq

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

2

尝试这个:

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


如果您已经有了pretty printedjson,为什么不只是grep它呢?

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

您总是可以使用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}

使用转储:

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

之后,只需 grep使用“ memberId”模式生成结果。

确切地说:

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

用法:

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


0

使用deepdiff,您不需要知道确切的键:

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

0

这是一个bash解决方案。

  1. 建立档案 find_members.sh
  2. 将以下行添加到文件+保存

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

现在运行它:

$ ./find_members.sh

memberIds
----------------
0x7b93910446f91928e23e1043dfdf5bcf
0x7b93910446f91928e23e1043dfdf5bcG
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.