Parsing deeply (multiple) nested JSON blocks with Python 3.6.8

Viewed 133

I've seen several related "nested json in Python" questions but the syntax for this Corona virus JSON data is giving me problems. Here's a sample:

{"recovered":524855,"list":[
    {"countrycode":"US","country":"United States of America","state":"South Carolina","latitude":"34.22333378","longitude":"-82.46170658","confirmed":15228,"deaths":568},
    {"countrycode":"US","country":"United States of America","state":"Louisiana","latitude":"30.2950649","longitude":"-92.41419698","confirmed":43612,"deaths":2957}
]}

If I just want to get to Louisiana, here's what I was trying:

import json
import requests

url = "https://covid19-data.p.api.com/us"

headers = {
    'x-api-key': "<api-key>",
    'x-api-host': "covid19-data.p.api.com"
    }

response = requests.request("GET", url, headers=headers)

coronastats = json.loads(response.text)

la_deaths = coronastats["list"][0]["countrycode"]["US"]["country"]["United States of America"]["state"]["Louisiana"]["deaths"]

print("Value: %s" % la_deaths)

I get: "TypeError: string indices must be integers"

This is obviously a list (I'm a detective and deduced that a variable named "list" might be a list) but the long key-value list is throwing me off (I think).

2 Answers

The problem is that once you get the first element of the list, you're left with only a depth-one dictionary. The data isn't as nested as you think it is. You're getting to a string quickly, and then trying to indice it using the US string, which raises the exception.

In [2]: data
Out[2]: 
{'recovered': 524855,
 'list': [{'countrycode': 'US',
   'country': 'United States of America',
   'state': 'South Carolina',
   'latitude': '34.22333378',
   'longitude': '-82.46170658',
   'confirmed': 15228,
   'deaths': 568},
  {'countrycode': 'US',
   'country': 'United States of America',
   'state': 'Louisiana',
   'latitude': '30.2950649',
   'longitude': '-92.41419698',
   'confirmed': 43612,
   'deaths': 2957}]}

In [3]: data["list"][0]
Out[3]: 
{'countrycode': 'US',
 'country': 'United States of America',
 'state': 'South Carolina',
 'latitude': '34.22333378',
 'longitude': '-82.46170658',
 'confirmed': 15228,
 'deaths': 568}

In [7]: data["list"][0]["countrycode"]
Out[7]: 'US'

In [8]: type(data["list"][0]["countrycode"])
Out[8]: str

In [9]: data["list"][0]["countrycode"]["asdf"]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-cb9dbc39ef82> in <module>
----> 1 data["list"][0]["countrycode"]["asdf"]

TypeError: string indices must be integers

To get to a specific country what you want to do is to FIND the state in the list, for example with code:

In [14]: [f"{row['state']}: {row['deaths']} deaths. Wear a mask!" for row in data["list"] if row["state"] == "Louisiana"]
Out[14]: ['Louisiana: 2957 deaths. Wear a mask!']

You can also use filter, pandas, and a million other solutions to sort through a table.

Try this:

coronastats = json.loads(response.text)
[coronastats["list"][i]["deaths"] for i in range(len(coronastats["list"])) if coronastats["list"][i]["state"] == "Louisiana"]
Related