有没有一种方法可以从Python中执行jq?

16

我希望从我的Python脚本中执行一个jq命令。目前当我在终端(MacOs)上执行这个jq命令时它是正常工作的。

cat filename.json |jq '{Name:.name, address:.address[0][1].street}'

基本上我正在尝试使用 jq 从 JSON 中提取数据。由于 JSON 包含嵌套的数组,因此我必须使用变量循环。

我的问题是 -

  • 我能否从 python 脚本中执行此命令
  • 如果可以执行,那么如何循环嵌套数组中的元素(例如给定示例数据中的 address [][].street)

我不想使用除 Python 以外的任何语言,因为这会导致兼容性问题。


1- 你可以像启动其他外部程序一样启动 jq(使用 subprocess 模块)。 2- 要从 JSON 中提取数据,请在 Python 中使用 json 模块(无需运行任何 shell 命令)。提供示例 JSON 输入和所需输出以及实际得到的输出。 - jfs
1
由于JSON包含嵌套数组,我必须使用变量进行循环。这是什么意思?jq可以很好地对嵌套数组执行操作。您能提供一个示例输入和预期输出吗? - user3899165
6个回答

20

1
无法同时安装它们,你能帮我安装一下吗? - devanathan
1
我使用Python3和jq库解析JSON数据。安装方面有什么问题? - Vishal Kanaujia
不确定这个在Windows环境下是否兼容:https://pypi.org/project/jq/ - lordofmax
2
我不太清楚jqpyjq之间的区别,有人可以帮忙解释一下吗? - Ced
请注意,pyjq在Windows上无法工作,需要Linux工具来构建它。 - NaturalBornCamper
显示剩余2条评论

10
我认为被接受的答案应该是peak的,因为在Python中使用C API的正确方式是通过Python绑定库,https://pypi.python.org/pypi/jqhttps://pypi.python.org/pypi/pyjq 都能正常工作。
但话说回来,既然我们谈论的是Python,我想提供一种更加Pythonic的替代方案:glompip install glomhttps://glom.readthedocs.io/)。
使用glom不像jq那样使用DSL,而是使用纯Python声明所需的输出格式(这个输出格式称为spec)。在这种情况下,您需要一个简单的dict
spec = {'Name': 'name',
        'street': 'address.0.1.street'}

然后只需在您的数据上调用 glom:

output_data = glom(input_data, spec)

就像jq一样,您也可以在命令行上使用glom

cat filename.json | glom "{'Name': 'name', 'street': 'address.0.1.street'}"

一个完整的Python示例:

import json
from pprint import pprint
from glom import glom


with open('filename.json', 'rt') as f:
    input_data = json.load(f)

spec = {'Name': 'name',
        'street': 'address.0.1.street'}

output_data = glom(input_data, spec)

pprint(output_data)

如果我想在使用像 -n--stream 这样的选项时,将这些 jq 绑定与仅能从命令传递行 jq 程序的其他选项一起使用怎么办?在这种情况下,使用 subprocess 是唯一的方法。还是不是? - Tytire Recubans

9

我很喜欢jq,但似乎你所做的事情在Python中也很容易实现。考虑以下代码:

import json

with open("filename.json", "r") as f:
    data = json.load(f)

{"Name": data["name"], "address": data["address"][0][1]["street"]}

1
这个答案从技术上来说并不是直接回答 OP 的问题,但是如果 OP 所声称的确实要使用 Python,那么放弃 jq 并使用 json 模块是正确的选择。 - Buzz Moschetti
在使用Python处理JSON字段时,对于流字符(stream character)有什么建议吗? - undefined

5

sh模块使得从Python中调用jq子进程变得容易。例如:

import sh
cmd = sh.jq('-M', '{Name:.name, address:.address[0][1].street}', 'filename.json')
print "cmd returned >>%s<<" % cmd.stdout

此外,要在字符串中运行jq:print(jq("-M", ".", _in='{ "a": 3 }').stdout.decode())(这是Python 3) - tobych
@tobych - 应该是 sh.jq(...) - peak

2
  1. 我可以在Python脚本中执行这个命令吗

可以,使用subprocess。示例:

jsonFile = '/path/to/your/filename.json'
jq_cmd = "/bin/jq '{Name:.name, address:.address[0][1].street}' " + jsonFile
jq_proc = subprocess.Popen(jq_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

# read JSON object, convert to string, store as a dictionary

jDict = json.loads(jq_proc.stdout.read())
jq_proc.stdout.close()
  1. 如果可以实现,那么如何循环遍历上面给出的样本数据中嵌套数组元素(address[][].street)?

看到几个记录的JSON数据集会有所帮助。在Python中使用jq循环遍历JSON集合时,很容易获得对象的计数,然后进行迭代。这会增加一些开销,但使代码易于理解。

# count number of JSON records from the root level

jq_cmd = "/bin/jq '. | length' " + jsonFile
jq_proc = subprocess.Popen(jq_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

jObjCount = int(jq_proc.stdout.read())
jq_proc.stdout.close()

# iterate over each root level JSON record

for ix in range(jObjCount):

  jq_cmd = "jq '. | .[" + str(ix) + "]' " + jsonFile 
  jq_proc = subprocess.Popen(jq_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

  # read object, convert to string, store as a python dictionary

  jDict = json.loads(jq_proc.stdout.read())

  # iterate over nested objects within a root level object    
  # as before, count number items but here for each root level JSON object

  jq_cmd = "/bin/jq '. | .[" + str(ix) + "].sub_Item_Key | length' " + jsonFile
  jq_proc = subprocess.Popen(jq_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  jItemCount = int(jq_proc.stdout.read())
  jq_proc.stdout.close()

  for jx in range(jItemCount):

     jq_cmd = "/bin/jq '. | .[" + str(ix) + "].sub_Item_Key[" + str(jx) + "]' " + jsonFile
     jq_proc = subprocess.Popen(jq_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

     # read JSON item, convert to string, store as a python dictionary

     jItemDict = json.loads(jq_proc.stdout.read())

享受吧!


1
是的。使用 plumbum
from plumbum.cmd import jq, cat

(cat["filename.json"] | jq ["{Name:.name, address:.address[0][1].street}"])()

上述命令的结果是一个 JSON 对象,可以使用 json.loads 将其解析为 Python 对象。
你可能还对 jello 感兴趣,它类似于 jq,但使用 Python 作为查询语言。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接