如何使用包含双引号 (") 的字符串加载 json 文件

How to load a json file with strings including double quotes (")

我收到了 JSON 文件的负载,我正在尝试将这些文件加载​​到 python 3.5

我已经不得不做一些清理工作,删除双反斜杠和额外的引号,但是我 运行 遇到了一个我不知道如何解决的问题。

我正在运行宁以下代码:

with open(filepath,'r') as json_file:
    reader = json_file.readlines()
    for row in reader:
        row = row.replace('\', '')
        row = row.replace('"{', '{')
        row = row.replace('}"', '}')
        response = json.loads(row)
        for i in response:
                responselist.append(i['ActionName']) 

但是它抛出了错误:

JSONDecodeError: Expecting ',' delimiter: line 1 column 388833 (char 388832)

导致问题的 JSON 部分是下面的状态文本条目:

"StatusId":8,
"StatusIdString":"UnknownServiceError",
"StatusText":"u003cCompany docTypeu003d"Mobile.Tile" statusIdu003d"421" statusTextu003d"Start time of 11/30/2015 12:15:00 PM is more than 5 minutes in the past relative to the current time of 12/1/2015 12:27:01 AM." copyrightu003d"Copyright Company Inc." versionNumberu003d"7.3" createdDateu003d"2015-12-01T00:27:01Z" responseIdu003d"e74710c0-dc7c-42db-b608-bf905d95d153" /u003e",
"ActionName":"GetTrafficTile"

我添加了换行符来说明我的观点,看起来 python 对字符串包含双引号不满意。

我感觉这可能与我用 '' 替换 '\ \' 弄乱了字符串中的 unicode 字符有关。有什么办法可以修复这些嵌套的字符串吗?我不介意 StatusText 字段是否被完全删除,我所需要的只是一个 ActionName 字段的列表。

编辑: 我在这里托管了一个示例文件:

https://www.dropbox.com/s/1oanrneg3aqandz/2015-12-01T00%253A00%253A42.527Z_2015-12-01T00%253A01%253A17.478Z?dl=0

这与我收到的完全一样,在我替换多余的反斜杠和引号之前

这是示例的简化版本,其中有一个错误条目

["{\"apiServerType\":0,\"RequestId\":\"52a65260-1637-4653-a496-7555a2386340\",\"StatusId\":0,\"StatusIdString\":\"Ok\",\"StatusText\":null,\"ActionName\":\"GetCameraImage\",\"Url\":\"http://mosi-prod.cloudapp.net/api/v1/GetCameraImage?AuthToken=vo*AB57XLptsKXf0AzKjf1MOgQ1hZ4BKipKgYl3uGew%7C&CameraId=13782\",\"Lat\":0.0,\"Lon\":0.0,\"iVendorId\":12561,\"iConsumerId\":2986897,\"iSliverId\":51846,\"UserId\":\"2986897\",\"HardwareId\":null,\"AuthToken\":\"vo*AB57XLptsKXf0AzKjf1MOgQ1hZ4BKipKgYl3uGew|\",\"RequestTime\":\"2015-12-01T00:00:42.5278699Z\",\"ResponseTime\":\"2015-12-01T00:01:02.5926127Z\",\"AppId\":null,\"HttpMethod\":\"GET\",\"RequestHeaders\":\"{\\"Connection\\":[\\"keep-alive\\"],\\"Via\\":[\\"HTTP/1.1 nycnz01msp1ts10.wnsnet.attws.com\\"],\\"Accept\\":[\\"application/json\\"],\\"Accept-Encoding\\":[\\"gzip\\",\\"deflate\\"],\\"Accept-Language\\":[\\"en-us\\"],\\"Host\\":[\\"mosi-prod.cloudapp.net\\"],\\"User-Agent\\":[\\"Traffic/5.4.0\\",\\"CFNetwork/758.1.6\\",\\"Darwin/15.0.0\\"]}\",\"RequestContentHeaders\":\"{}\",\"RequestContentBody\":\"\",\"ResponseBody\":null,\"ResponseContentHeaders\":\"{\\"Content-Type\\":[\\"image/jpeg\\"]}\",\"ResponseHeaders\":\"{}\",\"MiniProfilerJson\":null}"]

问题和你想的有点不一样。无论使用什么程序构建这些文件,都使用已经 json 编码的数据,并最终对某些信息进行双重甚至三重编码。我在 shell 会话中将其剥离并获得了可用的 python 数据。你可以 (1) 对编写构建这堆热气腾腾的程序的程序的人进行一记重击......嗯......天哪? (2) 手动扫描并解码内部 json 字符串。

我解码了数据,它是一个字符串列表,但这些字符串看起来很像 json

>>> data = json.load(open('test.json'))
>>> type(data)
<class 'list'>
>>> d0 = data[0]
>>> type(d0)
<class 'str'>
>>> d0[:70]
'{"apiServerType":0,"RequestId":"52a65260-1637-4653-a496-7555a2386340",'

果然可以解码

>>> d0_1 = json.loads(d0)
>>> type(d0_1)
<class 'dict'>
>>> d0_1
{'ResponseBody': None, 'StatusText': None, 'AppId': None, 'ResponseTime': '2015-12-01T00:01:02.5926127Z', 'HardwareId': None, 'RequestTime': '2015-12-01T00:00:42.5278699Z', 'StatusId': 0, 'Lon': 0.0, 'Url': 'http://mosi-prod.cloudapp.net/api/v1/GetCameraImage?AuthToken=vo*AB57XLptsKXf0AzKjf1MOgQ1hZ4BKipKgYl3uGew%7C&CameraId=13782', 'RequestContentBody': '', 'RequestId': '52a65260-1637-4653-a496-7555a2386340', 'MiniProfilerJson': None, 'RequestContentHeaders': '{}', 'ActionName': 'GetCameraImage', 'StatusIdString': 'Ok', 'HttpMethod': 'GET', 'iSliverId': 51846, 'ResponseHeaders': '{}', 'ResponseContentHeaders': '{"Content-Type":["image/jpeg"]}', 'apiServerType': 0, 'AuthToken': 'vo*AB57XLptsKXf0AzKjf1MOgQ1hZ4BKipKgYl3uGew|', 'iConsumerId': 2986897, 'RequestHeaders': '{"Connection":["keep-alive"],"Via":["HTTP/1.1 nycnz01msp1ts10.wnsnet.attws.com"],"Accept":["application/json"],"Accept-Encoding":["gzip","deflate"],"Accept-Language":["en-us"],"Host":["mosi-prod.cloudapp.net"],"User-Agent":["Traffic/5.4.0","CFNetwork/758.1.6","Darwin/15.0.0"]}', 'iVendorId': 12561, 'Lat': 0.0, 'UserId': '2986897'}

选择其中一项,看起来更像 json

>>> hdrs = d0_1['RequestHeaders']
>>> type(hdrs)
<class 'str'>

是的,它解码成我想要的

>>> hdrs_0 = json.loads(hdrs)
>>> type(hdrs_0)
<class 'dict'>
>>> 
>>> hdrs_0["Via"]
['HTTP/1.1 nycnz01msp1ts10.wnsnet.attws.com']
>>> 
>>> type(hdrs_0["Via"])
<class 'list'>

给你 :) :

responselist = []
with open('dataFile.json','r') as json_file:
    reader = json_file.readlines()
    for row in reader:
        strActNm = 'ActionName":"'; lenActNm = len(strActNm)
        actionAt = row.find(strActNm)
        while actionAt > 0:
            nxtQuotAt = row.find('"',actionAt+lenActNm+2)
            responselist.append( row[actionAt-1: nxtQuotAt+1] )
            actionAt = row.find('ActionName":"', nxtQuotAt)
print(responselist)

给出:

>python3.6 -u "dataFile.py"
['"ActionName":"GetTrafficTile"']
>Exit code: 0

其中 dataFile.json 是包含您提供的行的文件,dataFile.py 是上面提供的代码。

这是艰难的旅程,但如果文件格式不正确,您必须找到解决方法,并且在任何情况下都可以使用简单的模式匹配。对于更复杂的情况,您将需要 regex(正则表达式),但在这种情况下,一个简单的 .find() 就足以完成这项工作。

该代码还在该行中找到多个 "actions"(如果该行包含多个操作)。

这里是您在 link 中提供的文件的结果,同时对上面的代码进行了以下小修改:

responselist = []
with open('dataFile1.json','r') as json_file:
    reader = json_file.readlines()
    for row in reader:
        strActNm='\"ActionName\":\"'
        # strActNm = 'ActionName":"'
        lenActNm = len(strActNm)
        actionAt = row.find(strActNm)
        while actionAt > 0:
            nxtQuotAt = row.find('"',actionAt+lenActNm+2)
            responselist.append( row[actionAt: nxtQuotAt+1].replace('\','') )
            actionAt = row.find('ActionName":"', nxtQuotAt)
print(responselist)

给出:

>python3.6 -u "dataFile.py"
['"ActionName":"GetCameraImage"']
>Exit code: 0

其中 dataFile1.json 是您在 link 中提供的文件。