drichards765
drichards765

Reputation: 21

JSON with Multiple Keys and Multiple Attributes to Class

I am currently trying to figure out how to parse JSON information in Python and am having a harder time than I think I should.

Below is a sample of the information I am trying to parse.

{
  "2019-05-09": {
    "1. open": "124.2900",
    "2. high": "125.7800",
    "3. low": "123.5700",
    "4. close": "125.5000",
    "5. volume": "23491093"
  },
  "2019-05-08": {
    "1. open": "125.4400",
    "2. high": "126.3700",
    "3. low": "124.7500",
    "4. close": "125.5100",
    "5. volume": "25775583"
  },
  "2019-05-07": {
    "1. open": "126.4600",
    "2. high": "127.1800",
    "3. low": "124.2200",
    "4. close": "125.5200",
    "5. volume": "36017661"
  }
}

I am trying to store each day into a class so that I can parse the information.

In the below example, I am only trying to print the opening for these records. According to the simple examples I've looked at, this should work but always comes up with the error 'string indices must be integers.'

from alpha_vantage.timeseries import TimeSeries
import json

class day_history:
    def __init__(self, date, open, high, low, close, volume):
        self.date = date
        self.open = open
        self.high = high
        self.low = low
        self.close = close
        self.volume = volume

alpha_adv_key = "aaaaaaaaaaa"

ts = TimeSeries(key=alpha_adv_key)
data, meta_data = ts.get_daily(symbol='MSFT')

results = json.dumps(data)

for day in results:
    print(day["1. open"])

What is the correct way to parse this JSON data so that I can store it in the class?

Upvotes: 2

Views: 734

Answers (1)

If you want to turn it into a class see my code below.

That being said I think the issue you are having is for day in results:. This is going to return each key (i.e. a string). I think you meant to do for day in results.values(): which will return all the dictionaries.

Turning the json into a class.

You can just use the magic of unpacking using **. I used your input as a parameter d.

days = []
for day, info in d.items():
    temp = info.copy() # A copy because we don't want to change the original
    keys = list(temp.keys()) # List of all keys (Ex: 1. open)

    # We want to remove the beginning number so we just have
    # the wanted attribute name(Ex: open instead of 1. open)
    for key in keys:
        temp[key[3:]] = temp.pop(key)
    temp['date'] = day # Add our date to the temp dictionary

    # note the ** notation. This unpacks a dictionary to keyword arguments
    # so it would be like passing: (date=day, open=..., close=..., ...)
    # that is why I had to remove the numbers before the variable name.
    days.append(day_history(**temp)) # Pass this new dict to our constructor

# This will print out all the days
print(days)

I added a __repr__ method to your class to print them:

    def __repr__(self):
        return str(self.date) + str(self.high)

If you don't need more class methods you may just want to consider using a namedtuple:

from collections import namedtuple

Day_History = namedtuple("Day_History", "date open high low close volume")
days = []

for day, info in d.items():
    temp = info.copy()
    keys = list(temp.keys())
    for key in keys:
        temp[key[3:]] = temp.pop(key)
    temp['date'] = day
    days.append(Day_History(**temp))

for day in days:
    print(day)

Output:

Day_History(date='2019-05-09', open='124.2900', high='125.7800', low='123.5700', close='125.5000', volume='23491093')
Day_History(date='2019-05-08', open='125.4400', high='126.3700', low='124.7500', close='125.5100', volume='25775583')
Day_History(date='2019-05-07', open='126.4600', high='127.1800', low='124.2200', close='125.5200', volume='36017661')

and you cant print namedtuple parameters by doing something like:

for day in days:
    print(day.open)

Upvotes: 1

Related Questions