【问题标题】:How to extract values from nested JSON array using pandas如何使用 pandas 从嵌套的 JSON 数组中提取值
【发布时间】:2019-07-06 10:58:06
【问题描述】:

我有一个大的 JSON 文件(40 万行)。我正在尝试隔离以下内容:

政策-“描述”

策略项 - “用户”和“数据库值”

JSON 文件 - https://pastebin.com/hv8mLfgx

Pandas 的预期输出:https://imgur.com/a/FVcNGsZ

“Policy Items”之后的所有内容在整个文件中都以完全相同的方式重新迭代。我试过下面的代码来隔离“用户”。它似乎不起作用,我正在尝试将所有这些转储到 CSV 中。

Edit* 这是我尝试尝试的解决方案,但无法使其正常工作 - Deeply nested JSON response to pandas dataframe

from pandas.io.json import json_normalize as Jnormal
import json
import pprint, csv
import re

with open("Ranger_Policies_20190204_195010.json") as file:
    jsonDF = json.load(file)
    for item in jsonDF['policies'][0]['policyItems'][0]:
        print ('{} - {} - {}'.format(jsonDF['users']))

编辑 2:我有一些工作代码能够获取一些用户,但它不能获取所有用户。 25 个中只有 11 个。

from pandas.io.json import json_normalize as Jnormal
import json
import pprint, csv
import re

with open("Ranger_Policies_20190204_195010.json") as file:
    jsonDF = json.load(file)
    pNode = Jnormal(jsonDF['policies'][0]['policyItems'], record_path='users')
    print(pNode.head(500))

编辑 3:这是最终的工作副本,但是我仍然没有复制所有 TABLE 数据。我设置了一个循环来简单地忽略所有内容。捕获所有内容,我会在 Excel 中对其进行排序,有人知道为什么我无法捕获所有 TABLE 值吗?

    json_data = json.load(file)
    with open("test.csv", 'w', newline='') as fd:
        wr = csv.writer(fd)
        wr.writerow(('Database name', 'Users', 'Description', 'Table'))
        for policy in json_data['policies']:
            desc = policy['description']
            db_values = policy['resources']['database']['values']
            db_tables = policy['resources']['table']['values']
            for item in policy['policyItems']:
                users = item['users']
                for dbT in db_tables:
                    for user in users:
                        for db in db_values:
                            _ = wr.writerow((db, user, desc, dbT))```

【问题讨论】:

  • 我考虑过使用映射构建一些递归。我个人什至不知道从哪里开始,因为我是 Python 的初学者。任何建议或指导将不胜感激。
  • 所以您想要将描述映射到用户的东西?并且策略只是一个大列表,您想对该列表中的每个字典执行该操作吗?
  • @aws_apprentice 是的,就是这样。描述实际上是一个“数据库”描述。我的目标是将描述映射到数据库,然后在所述数据库下列出用户。很抱歉最初的混乱
  • 你能展示一个预期输出的小例子吗?谢谢
  • @ChrisLarson 我明白,这是较大 JSON 文件的 sn-p。当我剪掉它时没有意识到底部的错字

标签: python json pandas csv dataframe


【解决方案1】:

Pandas 在这里太过分了:csv 标准模块就足够了。您只需迭代策略以提取数据库值的描述,然后在 policyItems 上提取用户:

with open("Ranger_Policies_20190204_195010.json") as file:
    jsonDF = json.load(file)
with open("outputfile.csv", newline='') as fd:
    wr = csv.writer(fd)
    _ = wr.writerow(('Database name', 'Users', 'Description'))
    for policy in js['policies']:
        desc = policy['description']
        db_values = policy['resources']['database']['values']
        for item in policy['policyItems']:
            users = item['users']
            for user in users:
                for db in db_values:
                    if db != '*':
                        _ = wr.writerow((db, user, desc))

【讨论】:

  • 这行得通!需要一些修改它并不能捕获所有内容。我将慢慢需要更好地理解逻辑以根据需要进行修改。谢谢谢尔盖
  • 我在数据库值之后添加了一行:db_tables = policy['resources']['table']['values'] 这给了我一个 KeyError,但它在 Resource 类中,不知道为什么?
  • 发现错误,是格式不正确的 JSON。 resources 类中还有多个表。我正在尝试将其纳入您的循环中,但遇到了困难。
  • 发现这个凌乱的 JSON 存在问题,有时 usersdatabase values 可能是 []" "。我需要围绕它编写一个逻辑代码。感谢您奠定了基础,只是想弄清楚逻辑,证明有点困难
【解决方案2】:

这是一种方法,假设您的 json 数据位于名为 json_data 的变量中

from itertools import product

def make_dfs(data):
    cols = ['db_name', 'user', 'description']

    for item in data.get('policies'):
        description = item.get('description')
        users = item.get('policyItems', [{}])[0].get('users', [None])
        db_name = item.get('resources', {}).get('database', {}).get('values', [None])
        db_name = [name for name in db_name if name != '*']
        prods = product(db_name, users, [description])
        yield pd.DataFrame.from_records(prods, columns=cols)

df = pd.concat(make_dfs(json_data), ignore_index=True)

print(df)

   db_name          user                               description
0    m2_db          hive  Policy for all - database, table, column
1    m2_db  rangerlookup  Policy for all - database, table, column
2    m2_db     ambari-qa  Policy for all - database, table, column
3    m2_db          af34  Policy for all - database, table, column
4    m2_db          g748  Policy for all - database, table, column
5    m2_db          hdfs  Policy for all - database, table, column
6    m2_db          dh10  Policy for all - database, table, column
7    m2_db          gs22  Policy for all - database, table, column
8    m2_db          dh27  Policy for all - database, table, column
9    m2_db          ct52  Policy for all - database, table, column
10   m2_db  livy_pyspark  Policy for all - database, table, column

Python 3.5.1pandas==0.23.4 上测试

【讨论】:

  • 在用户之后db_name 的第一行遇到了无效的语法错误。这确实有助于理解如何更好地映射它
  • 指向名称并在此行上说“无效语法”db_name = item.get('resources', {}).get('database', {}).get('values', [None])
  • 可能是你复制过来的方式,我运行这段代码没有问题
  • 这很奇怪,我什至创建了一个新包并尝试运行它。
  • 检查缩进并确保制表符和空格一致。这里没有我可以看到的语法错误
猜你喜欢
  • 1970-01-01
  • 2023-03-11
  • 2019-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-20
  • 1970-01-01
相关资源
最近更新 更多