在 pandas 中使用 read_json 导入单个记录

Posted

技术标签:

【中文标题】在 pandas 中使用 read_json 导入单个记录【英文标题】:Importing single record using read_json in pandas 【发布时间】:2015-10-17 19:30:12 【问题描述】:

我正在尝试使用函数导入 json 文件:

sku = pandas.read_json('https://cws01.worldstores.co.uk/api/product.php?product_sku=125T:FT0111')

但是,我不断收到以下错误

ValueError: 数组的长度必须相同

我应该怎么做才能将其正确导入数据框?

这是json的结构:


"id": "5",
"sku": "JOSH:BECO-BRN",
"last_updated": "2013-06-10 15:46:22",

...

"propertyType1": [
    "manufacturer_colour"
],
"category": [
    
        "category_id": "10",
        "category_name": "All Products"
    ,

    ...

    
        "category_id": "238",
        "category_name": "All Sofas"
    
],
"root_categories": [
    "516"
],
"url": "/p/Beco Suede Sofa Bed?product_id=5",
"item": [
    "2"
],
"image_names": "[\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/L\\/19\\/Beco_Suede_Sofa_Bed-1.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/P\\/19\\/Beco_Suede_Sofa_Bed-1.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/SP\\/19\\/Beco_Suede_Sofa_Bed-1.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/SS\\/19\\/Beco_Suede_Sofa_Bed-1.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/ST\\/19\\/Beco_Suede_Sofa_Bed-1.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/WP\\/19\\/Beco_Suede_Sofa_Bed-1.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/L\\/19\\/Beco_Suede_Sofa_Bed-2.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/P\\/19\\/Beco_Suede_Sofa_Bed-2.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/SP\\/19\\/Beco_Suede_Sofa_Bed-2.jpg\",\"https:\\/\\/cdn.worldstores.co.uk \\/images\\/products\\/SS\\/19\\/Beco_Suede_Sofa_Bed-2.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/ST\\/19\\/Beco_Suede_Sofa_Bed-2.jpg\",\"https:\\/\\/cdn.worldstores.co.uk\\/images\\/products\\/WP\\/19\\/Beco_Suede_Sofa_Bed-2.jpg\"]"

【问题讨论】:

我需要创建一个自包含的python脚本来处理几个json文件 您能描述一下您设想的结构将如何转换为数据框吗?您想展平嵌套结构吗? 我已经添加了json结构 我遇到了同样的问题。我通过将 '[' ']' 附加到 JSON 的开头和结尾并设置 orient="records" 来解决它。 【参考方案1】:

The pandas.read_json function 采用多种格式。

由于您没有指定 json 文件的格式(orient= 属性),pandas 将默认相信您的数据是列式的。下面讨论了 pandas 期望的不同格式。

试图从https://cws01.worldstores.co.uk/api/product.php?product_sku=125T:FT0111解析的数据 似乎不符合任何受支持的格式,因为它似乎只是一个“记录”。 Pandas 期待某种收藏。

您可能应该尝试将多个条目收集到一个文件中,然后使用read_json 函数对其进行解析。

编辑:

获取多行并使用pandas.read_json 函数解析它的简单方法:

import urllib2
import pandas as pd


url_base = "https://cws01.worldstores.co.uk/api/product.php?product_sku="
products = ["125T:FT0111", "125T:FT0111", "125T:FT0111"]

raw_data_list = []

for sku in products:
    url = url_base.format(sku)
    raw_data_list.append(urllib2.urlopen(url).read())

data = "[" + (",".join(raw_data_list)) + "]"
data = pd.read_json(data, orient='records')
data

/编辑

我对 pandas.read_json 函数格式的看法。

The pandas.read_json function 是 pandas 试图将尽可能多的功能集成到单个函数中的又一个光辉例子。这当然会导致一个非常复杂的函数。

系列

如果您的数据是Series,则pandas.read_json(orient=) 默认为'index'

在解析 Series 时允许的 orient 值是:'split','records','index'

请注意,orient='index' 的系列索引必须是唯一的。

数据帧

如果您的数据是DataFrame,则pandas.read_json(orient=) 默认为'columns'

在解析 DataFrame 时允许的 orient 值是: 'split','records','index','columns','values'

请注意,orient='index'orient='columns' 的 Series 索引必须唯一,orient='index'orient='columns'orient='records' 的 DataFrame 列必须唯一。

格式

无论您的数据是DataFrame 还是Seriesorient= 都会期望数据格式相同:

拆分

期望像 DataFrame 构造函数所采用的 dict 的字符串表示形式:

"index":[1,2,3,4], "columns":["col1","col2"], "data":[[8,7,6,5], [5,6,7,8]]

记录

期望字典列表的字符串表示,例如:

["col1":8,"col2":5,"col1":7,"col2":6,"col1":6,"col2":7,"col1":5,"col2":8]

注意这里没有设置索引。

索引

期望嵌套 dict dict 的字符串表示形式,例如:

"1":"col1":8,"col2":5,"2":"col1":7,"col2":6,"3":"col1":6,"col2":7,"4":"col1":5,"col2":8

值得注意的是,它不接受字符串以外的其他类型的索引。可能会在以后的版本中修复。

期望嵌套字典的字符串表示,例如:

"col1":"1":8,"2":7,"3":6,"4":5,"col2":"1":5,"2":6,"3":7,"4":8

价值观

期望列表的字符串表示形式,如:

[[8, 5],[7, 6],[6, 7],[5, 8]]

结果数据帧

在大多数情况下,你得到的数据框会是这样的,上面有 json 字符串:

   col1  col2
1     8     5
2     7     6
3     6     7
4     5     8

【讨论】:

【参考方案2】:

也许这不是最优雅的解决方案,但给了我我想要的东西,或者至少我相信如此,如果有问题,请随时警告

url = "https://cws01.worldstores.co.uk/api/product.php?product_sku=125T:FT0111"
data = urllib2.urlopen(url).read()
data = json.loads(data)
data = pd.DataFrame(data.items())
data = data.transpose()

【讨论】:

我在回答中改进了这个版本,仍然使用 pd.read_json。【参考方案3】:

另一种解决方案是使用 try except。

json_path='https://cws01.worldstores.co.uk/api/product.php?product_sku=125T:FT0111'
try: a=pd.read_json(json_path)
except ValueError: a=pd.read_json("["+json_path+"]")

【讨论】:

【参考方案4】:

迭代@firelynx 的答案:

#! /usr/bin/env python3

from urllib.request import urlopen
import pandas as pd

products = ["125T:FT0111", "125T:FT0111", "125T:FT0111"]
raw_lines = ""
for sku in products:
    url = f"https://cws01.worldstores.co.uk/api/product.php?product_sku=sku"
    raw_lines += urlopen(url).read() + "\n"

data = pd.read_json(raw_lines, lines=True)

这将支持返回单个 JSON 对象或一堆换行符 ('\n') 分隔的任何源。

或者这个单线(ish)应该是一样的:

#! /usr/bin/env python3

import pandas as pd

products = ["125T:FT0111", "125T:FT0111", "125T:FT0111"]
data = pd.concat(
    pd.read_json(
        f"https://cws01.worldstores.co.uk/api/product.php?product_sku=sku",
        lines=True
    ) for sku in products
)

PS:这里python3只支持fstring,所以你应该使用str.format来兼容python2。

【讨论】:

以上是关于在 pandas 中使用 read_json 导入单个记录的主要内容,如果未能解决你的问题,请参考以下文章

在 Pandas UnicodeDecodeError 中无法使用 pandas.read_json() 解码 JSON 文件中的 Unicode Ascii

Pandas.read_json(JSON_URL)

pandas

使用 pandas.read_json 时出现 ValueError

如何让 pandas.read_json 将此 API 返回识别为有效的 .json?

如何在 ```pandas.read_json(...)` 期间修复 ```ValueError: Trailing data```?