I'm making requests to FB API, retriving data from a FB page.
I have a dict with params like this, just get data from 08-01 to 08-20:
data_test = {
'page_likes' : {'page_id': '111',
'metric': 'page_fans',
'since': datetime(2019, 8, 1, 0, 0, 0),
'until': datetime(2019, 8, 20, 0, 0, 0),
'date_preset' : 'yesterday',
'period': 'day'},
'page_impressions' : {'page_id': '111',
'metric': 'page_impressions',
'since': datetime(2019, 8, 1, 0, 0, 0),
'until': datetime(2019, 8, 20, 0, 0, 0),
'date_preset' : 'yesterday',
'period': 'day'}
}
And run a loop through it, collecting raw data to a list, then checking for additional pages, and adding to the list.
responses_time_balanced = [] # list for responses
# loop through data_test
for k, v in data_test.items():
sample_request = graph.get_connections(id = v['page_id'],
connection_name='insights',
metric = v['metric'],
since = v['since'],
until = v['until'],
#date_preset = v['date_preset'],
period = v['period'])
# add responses to the responses_time_balanced
responses_time_balanced.append(sample_request)
# check for additinal pages and add data from them to the list
for request in responses_time_balanced:
if 'next' in request['paging'].keys():
request = requests.get(request['paging']['next']).json()
responses_time_balanced.append(request)
But for some reasons, which I can't get, data from the second page duplicates.
So the final list looks like this:
Data:
page_fans from 2019-08-02 to 2019-08-19
page_fans from 2019-08-20 to 2019-09-06
page_impressions from 2019-08-02 to 2019-08-19
page_impressions from 2019-08-20 to 2019-09-06
and again
page_fans from 2019-08-20 to 2019-09-06
page_impressions from 2019-08-20 to 2019-09-06
There is some stupid mistake in the code, but i can't get it
The whole response:
the access token is not valid
[{'data': [{'name': 'page_fans',
'period': 'day',
'values': [{'value': 113264, 'end_time': '2019-08-02T07:00:00+0000'},
{'value': 113246, 'end_time': '2019-08-03T07:00:00+0000'},
{'value': 113231, 'end_time': '2019-08-04T07:00:00+0000'},
{'value': 113219, 'end_time': '2019-08-05T07:00:00+0000'},
{'value': 113195, 'end_time': '2019-08-06T07:00:00+0000'},
{'value': 113177, 'end_time': '2019-08-07T07:00:00+0000'},
{'value': 113166, 'end_time': '2019-08-08T07:00:00+0000'},
{'value': 113147, 'end_time': '2019-08-09T07:00:00+0000'},
{'value': 113138, 'end_time': '2019-08-10T07:00:00+0000'},
{'value': 113132, 'end_time': '2019-08-11T07:00:00+0000'},
{'value': 113124, 'end_time': '2019-08-12T07:00:00+0000'},
{'value': 113118, 'end_time': '2019-08-13T07:00:00+0000'},
{'value': 113109, 'end_time': '2019-08-14T07:00:00+0000'},
{'value': 113097, 'end_time': '2019-08-15T07:00:00+0000'},
{'value': 113091, 'end_time': '2019-08-16T07:00:00+0000'},
{'value': 113082, 'end_time': '2019-08-17T07:00:00+0000'},
{'value': 113071, 'end_time': '2019-08-18T07:00:00+0000'},
{'value': 113066, 'end_time': '2019-08-19T07:00:00+0000'}],
'title': 'Lifetime Total Likes',
'description': 'Lifetime: The total number of people who have liked your Page. (Unique Users)',
'id': '571653679838052/insights/page_fans/day'}],
'paging': {'previous': 'https://graph.facebook.com/v4.0/571653679838052/insights?access_token=EAAHzAoOZCOJQBALIh8wCto7ZCsRMTvs4ybK8I0pH1xQ4YKgfbdsOeLwxgFcJZAYDqGxgofdZBlzmqZBH1tHY5QgAH7KHUAhAjVg5lw9psgOysZAzGEVZBZBE1cVPdqZCJneS1ousyt0xZCx1kPexvSvVQ9tK783bpp9PtJZACvjgqUCRL5LC0IuhmB1&since=1563087600&until=1564642800&metric=page_fans&period=day',
'next': 'https://graph.facebook.com/v4.0/571653679838052/insights?access_token=EAAHzAoOZCOJQBALIh8wCto7ZCsRMTvs4ybK8I0pH1xQ4YKgfbdsOeLwxgFcJZAYDqGxgofdZBlzmqZBH1tHY5QgAH7KHUAhAjVg5lw9psgOysZAzGEVZBZBE1cVPdqZCJneS1ousyt0xZCx1kPexvSvVQ9tK783bpp9PtJZACvjgqUCRL5LC0IuhmB1&since=1566198000&until=1567753200&metric=page_fans&period=day'}},
{'data': [{'name': 'page_fans',
'period': 'day',
'values': [{'value': 113209, 'end_time': '2019-08-20T07:00:00+0000'},
{'value': 113299, 'end_time': '2019-08-21T07:00:00+0000'},
{'value': 113352, 'end_time': '2019-08-22T07:00:00+0000'},
{'value': 113409, 'end_time': '2019-08-23T07:00:00+0000'},
{'value': 113469, 'end_time': '2019-08-24T07:00:00+0000'},
{'value': 113517, 'end_time': '2019-08-25T07:00:00+0000'},
{'value': 113578, 'end_time': '2019-08-26T07:00:00+0000'},
{'value': 113622, 'end_time': '2019-08-27T07:00:00+0000'},
{'value': 113652, 'end_time': '2019-08-28T07:00:00+0000'},
{'value': 113700, 'end_time': '2019-08-29T07:00:00+0000'},
{'value': 113723, 'end_time': '2019-08-30T07:00:00+0000'},
{'value': 113756, 'end_time': '2019-08-31T07:00:00+0000'},
{'value': 113792, 'end_time': '2019-09-01T07:00:00+0000'},
{'value': 113839, 'end_time': '2019-09-02T07:00:00+0000'},
{'value': 113873, 'end_time': '2019-09-03T07:00:00+0000'},
{'value': 113911, 'end_time': '2019-09-04T07:00:00+0000'},
{'value': 113913, 'end_time': '2019-09-05T07:00:00+0000'},
{'value': 113913, 'end_time': '2019-09-06T07:00:00+0000'}],
'title': 'Lifetime Total Likes',
'description': 'Lifetime: The total number of people who have liked your Page. (Unique Users)',
'id': '571653679838052/insights/page_fans/day'}],
'paging': {'previous': 'https://graph.facebook.com/v4.0/571653679838052/insights?access_token=EAAHzAoOZCOJQBALIh8wCto7ZCsRMTvs4ybK8I0pH1xQ4YKgfbdsOeLwxgFcJZAYDqGxgofdZBlzmqZBH1tHY5QgAH7KHUAhAjVg5lw9psgOysZAzGEVZBZBE1cVPdqZCJneS1ousyt0xZCx1kPexvSvVQ9tK783bpp9PtJZACvjgqUCRL5LC0IuhmB1&since=1564642800&until=1566198000&metric=page_fans&period=day'}},
{'data': [{'name': 'page_impressions',
'period': 'day',
'values': [{'value': 1467, 'end_time': '2019-08-02T07:00:00+0000'},
{'value': 421, 'end_time': '2019-08-03T07:00:00+0000'},
{'value': 271, 'end_time': '2019-08-04T07:00:00+0000'},
{'value': 260, 'end_time': '2019-08-05T07:00:00+0000'},
{'value': 1584, 'end_time': '2019-08-06T07:00:00+0000'},
{'value': 484, 'end_time': '2019-08-07T07:00:00+0000'},
{'value': 269, 'end_time': '2019-08-08T07:00:00+0000'},
{'value': 1290, 'end_time': '2019-08-09T07:00:00+0000'},
{'value': 487, 'end_time': '2019-08-10T07:00:00+0000'},
{'value': 205, 'end_time': '2019-08-11T07:00:00+0000'},
{'value': 267, 'end_time': '2019-08-12T07:00:00+0000'},
{'value': 267, 'end_time': '2019-08-13T07:00:00+0000'},
{'value': 233, 'end_time': '2019-08-14T07:00:00+0000'},
{'value': 388, 'end_time': '2019-08-15T07:00:00+0000'},
{'value': 1383, 'end_time': '2019-08-16T07:00:00+0000'},
{'value': 583, 'end_time': '2019-08-17T07:00:00+0000'},
{'value': 12554, 'end_time': '2019-08-18T07:00:00+0000'},
{'value': 258, 'end_time': '2019-08-19T07:00:00+0000'}],
'title': 'Daily Total Impressions',
'description': "Daily: The number of times any content from your Page or about your Page entered a person's screen. This includes posts, stories, check-ins, ads, social information from people who interact with your Page and more. (Total Count)",
'id': '571653679838052/insights/page_impressions/day'}],
'paging': {'previous': 'https://graph.facebook.com/v4.0/571653679838052/insights?access_token=EAAHzAoOZCOJQBALIh8wCto7ZCsRMTvs4ybK8I0pH1xQ4YKgfbdsOeLwxgFcJZAYDqGxgofdZBlzmqZBH1tHY5QgAH7KHUAhAjVg5lw9psgOysZAzGEVZBZBE1cVPdqZCJneS1ousyt0xZCx1kPexvSvVQ9tK783bpp9PtJZACvjgqUCRL5LC0IuhmB1&since=1563087600&until=1564642800&metric=page_impressions&period=day',
'next': 'https://graph.facebook.com/v4.0/571653679838052/insights?access_token=EAAHzAoOZCOJQBALIh8wCto7ZCsRMTvs4ybK8I0pH1xQ4YKgfbdsOeLwxgFcJZAYDqGxgofdZBlzmqZBH1tHY5QgAH7KHUAhAjVg5lw9psgOysZAzGEVZBZBE1cVPdqZCJneS1ousyt0xZCx1kPexvSvVQ9tK783bpp9PtJZACvjgqUCRL5LC0IuhmB1&since=1566198000&until=1567753200&metric=page_impressions&period=day'}},
{'data': [{'name': 'page_fans',
'period': 'day',
'values': [{'value': 113209, 'end_time': '2019-08-20T07:00:00+0000'},
{'value': 113299, 'end_time': '2019-08-21T07:00:00+0000'},
{'value': 113352, 'end_time': '2019-08-22T07:00:00+0000'},
{'value': 113409, 'end_time': '2019-08-23T07:00:00+0000'},
{'value': 113469, 'end_time': '2019-08-24T07:00:00+0000'},
{'value': 113517, 'end_time': '2019-08-25T07:00:00+0000'},
{'value': 113578, 'end_time': '2019-08-26T07:00:00+0000'},
{'value': 113622, 'end_time': '2019-08-27T07:00:00+0000'},
{'value': 113652, 'end_time': '2019-08-28T07:00:00+0000'},
{'value': 113700, 'end_time': '2019-08-29T07:00:00+0000'},
{'value': 113723, 'end_time': '2019-08-30T07:00:00+0000'},
{'value': 113756, 'end_time': '2019-08-31T07:00:00+0000'},
{'value': 113792, 'end_time': '2019-09-01T07:00:00+0000'},
{'value': 113839, 'end_time': '2019-09-02T07:00:00+0000'},
{'value': 113873, 'end_time': '2019-09-03T07:00:00+0000'},
{'value': 113911, 'end_time': '2019-09-04T07:00:00+0000'},
{'value': 113913, 'end_time': '2019-09-05T07:00:00+0000'},
{'value': 113913, 'end_time': '2019-09-06T07:00:00+0000'}],
'title': 'Lifetime Total Likes',
'description': 'Lifetime: The total number of people who have liked your Page. (Unique Users)',
'id': '571653679838052/insights/page_fans/day'}],
'paging': {'previous': 'https://graph.facebook.com/v4.0/571653679838052/insights?access_token=EAAHzAoOZCOJQBALIh8wCto7ZCsRMTvs4ybK8I0pH1xQ4YKgfbdsOeLwxgFcJZAYDqGxgofdZBlzmqZBH1tHY5QgAH7KHUAhAjVg5lw9psgOysZAzGEVZBZBE1cVPdqZCJneS1ousyt0xZCx1kPexvSvVQ9tK783bpp9PtJZACvjgqUCRL5LC0IuhmB1&since=1564642800&until=1566198000&metric=page_fans&period=day'}},
{'data': [{'name': 'page_impressions',
'period': 'day',
'values': [{'value': 53579, 'end_time': '2019-08-20T07:00:00+0000'},
{'value': 36032, 'end_time': '2019-08-21T07:00:00+0000'},
{'value': 33509, 'end_time': '2019-08-22T07:00:00+0000'},
{'value': 41100, 'end_time': '2019-08-23T07:00:00+0000'},
{'value': 39801, 'end_time': '2019-08-24T07:00:00+0000'},
{'value': 38691, 'end_time': '2019-08-25T07:00:00+0000'},
{'value': 37131, 'end_time': '2019-08-26T07:00:00+0000'},
{'value': 28139, 'end_time': '2019-08-27T07:00:00+0000'},
{'value': 17064, 'end_time': '2019-08-28T07:00:00+0000'},
{'value': 16537, 'end_time': '2019-08-29T07:00:00+0000'},
{'value': 20000, 'end_time': '2019-08-30T07:00:00+0000'},
{'value': 18023, 'end_time': '2019-08-31T07:00:00+0000'},
{'value': 15622, 'end_time': '2019-09-01T07:00:00+0000'},
{'value': 27015, 'end_time': '2019-09-02T07:00:00+0000'},
{'value': 25329, 'end_time': '2019-09-03T07:00:00+0000'},
{'value': 18049, 'end_time': '2019-09-04T07:00:00+0000'},
{'value': 1124, 'end_time': '2019-09-05T07:00:00+0000'},
{'value': 0, 'end_time': '2019-09-06T07:00:00+0000'}],
'title': 'Daily Total Impressions',
'description': "Daily: The number of times any content from your Page or about your Page entered a person's screen. This includes posts, stories, check-ins, ads, social information from people who interact with your Page and more. (Total Count)",
'id': '571653679838052/insights/page_impressions/day'}],
'paging': {'previous': 'https://graph.facebook.com/v4.0/571653679838052/insights?access_token=EAAHzAoOZCOJQBALIh8wCto7ZCsRMTvs4ybK8I0pH1xQ4YKgfbdsOeLwxgFcJZAYDqGxgofdZBlzmqZBH1tHY5QgAH7KHUAhAjVg5lw9psgOysZAzGEVZBZBE1cVPdqZCJneS1ousyt0xZCx1kPexvSvVQ9tK783bpp9PtJZACvjgqUCRL5LC0IuhmB1&since=1564642800&until=1566198000&metric=page_impressions&period=day'}}]
update
checked with the Graph API Explorer, there is everything ok
Related
I'm having troubles completely unnesting this json from an Api.
[{'id': 1,
'name': 'Buzz',
'tagline': 'A Real Bitter Experience.',
'first_brewed': '09/2007',
'description': 'A light, crisp and bitter IPA brewed with English and American hops. A small batch brewed only once.',
'image_url': 'https://images.punkapi.com/v2/keg.png',
'abv': 4.5,
'ibu': 60,
'target_fg': 1010,
'target_og': 1044,
'ebc': 20,
'srm': 10,
'ph': 4.4,
'attenuation_level': 75,
'volume': {'value': 20, 'unit': 'litres'},
'boil_volume': {'value': 25, 'unit': 'litres'},
'method': {'mash_temp': [{'temp': {'value': 64, 'unit': 'celsius'},
'duration': 75}],
'fermentation': {'temp': {'value': 19, 'unit': 'celsius'}},
'twist': None},
'ingredients': {'malt': [{'name': 'Maris Otter Extra Pale',
'amount': {'value': 3.3, 'unit': 'kilograms'}},
{'name': 'Caramalt', 'amount': {'value': 0.2, 'unit': 'kilograms'}},
{'name': 'Munich', 'amount': {'value': 0.4, 'unit': 'kilograms'}}],
'hops': [{'name': 'Fuggles',
'amount': {'value': 25, 'unit': 'grams'},
'add': 'start',
'attribute': 'bitter'},
{'name': 'First Gold',
'amount': {'value': 25, 'unit': 'grams'},
'add': 'start',
'attribute': 'bitter'},
{'name': 'Fuggles',
'amount': {'value': 37.5, 'unit': 'grams'},
'add': 'middle',
'attribute': 'flavour'},
{'name': 'First Gold',
'amount': {'value': 37.5, 'unit': 'grams'},
'add': 'middle',
'attribute': 'flavour'},
{'name': 'Cascade',
'amount': {'value': 37.5, 'unit': 'grams'},
'add': 'end',
'attribute': 'flavour'}],
'yeast': 'Wyeast 1056 - American Ale™'},
'food_pairing': ['Spicy chicken tikka masala',
'Grilled chicken quesadilla',
'Caramel toffee cake'],
'brewers_tips': 'The earthy and floral aromas from the hops can be overpowering. Drop a little Cascade in at the end of the boil to lift the profile with a bit of citrus.',
'contributed_by': 'Sam Mason <samjbmason>'},
{'id': 2,
'name': 'Trashy Blonde',
'tagline': "You Know You Shouldn't",
'first_brewed': '04/2008',
'description': 'A titillating, neurotic, peroxide punk of a Pale Ale. Combining attitude, style, substance, and a little bit of low self esteem for good measure; what would your mother say? The seductive lure of the sassy passion fruit hop proves too much to resist. All that is even before we get onto the fact that there are no additives, preservatives, pasteurization or strings attached. All wrapped up with the customary BrewDog bite and imaginative twist.',
'image_url': 'https://images.punkapi.com/v2/2.png',
'abv': 4.1,
'ibu': 41.5,
'target_fg': 1010,
'target_og': 1041.7,
'ebc': 15,
'srm': 15,
'ph': 4.4,
'attenuation_level': 76,
'volume': {'value': 20, 'unit': 'litres'},
'boil_volume': {'value': 25, 'unit': 'litres'},
'method': {'mash_temp': [{'temp': {'value': 69, 'unit': 'celsius'},
'duration': None}],
'fermentation': {'temp': {'value': 18, 'unit': 'celsius'}},
'twist': None},
'ingredients': {'malt': [{'name': 'Maris Otter Extra Pale',
'amount': {'value': 3.25, 'unit': 'kilograms'}},
{'name': 'Caramalt', 'amount': {'value': 0.2, 'unit': 'kilograms'}},
{'name': 'Munich', 'amount': {'value': 0.4, 'unit': 'kilograms'}}],
'hops': [{'name': 'Amarillo',
'amount': {'value': 13.8, 'unit': 'grams'},
'add': 'start',
'attribute': 'bitter'},
{'name': 'Simcoe',
'amount': {'value': 13.8, 'unit': 'grams'},
'add': 'start',
'attribute': 'bitter'},
{'name': 'Amarillo',
'amount': {'value': 26.3, 'unit': 'grams'},
'add': 'end',
'attribute': 'flavour'},
{'name': 'Motueka',
'amount': {'value': 18.8, 'unit': 'grams'},
'add': 'end',
'attribute': 'flavour'}],
'yeast': 'Wyeast 1056 - American Ale™'},
'food_pairing': ['Fresh crab with lemon',
'Garlic butter dipping sauce',
'Goats cheese salad',
'Creamy lemon bar doused in powdered sugar'],
'brewers_tips': 'Be careful not to collect too much wort from the mash. Once the sugars are all washed out there are some very unpleasant grainy tasting compounds that can be extracted into the wort.',
'contributed_by': 'Sam Mason <samjbmason>'}]
I was able to unnest it to a level using json_normalize
import requests
import pandas as pd
url = "https://api.punkapi.com/v2/beers"
requests.get(url).json()
data = requests.get(url).json()
pd.json_normalize(data)
this is an image of the output after using json_normalize
now to unnest the column 'method.mash_temp' I included record_path
pd.json_normalize(
data,
record_path =['method', 'mash_temp'],
meta=['id', 'name']
)
but I am having troubles adding the other columns('ingredients.malt', 'ingredients.hops') with list of dictionaries in the record_path argument.
I’m trying to use Python print specific values from a JSON file that I pulled from an API. From what I understand, I am pulling it as a JSON file that has a list of dictionaries of players, with a nested dictionary for each player containing their data (i.e. name, team, etc.).
I’m running into issues printing the values within the JSON file, as each character is printing on a separate line.
The end result I am trying to get to is a Pandas DataFrame containing all the values from the JSON file, but I can’t even seem to iterate through the JSON file correctly.
Here is my code:
url = "https://api-football-v1.p.rapidapi.com/v3/players"
querystring = {"league":"39","season":"2020", "page":"2"}
headers = {
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
"X-RapidAPI-Key": "xxxxxkeyxxxxx"
}
response = requests.request("GET", url, headers=headers, params=querystring).json()
response_dump = json.dumps(response)
for item in response_dump:
for player_item in item:
print(player_item)
This is the output when I print the JSON response (first two items):
{'get': 'players', 'parameters': {'league': '39', 'page': '2', 'season': '2020'}, 'errors': [], 'results': 20, 'paging': {'current': 2, 'total': 37}, 'response': [{'player': {'id': 301, 'name': 'Benjamin Luke Woodburn', 'firstname': 'Benjamin Luke', 'lastname': 'Woodburn', 'age': 23, 'birth': {'date': '1999-10-15', 'place': 'Nottingham', 'country': 'England'}, 'nationality': 'Wales', 'height': '174 cm', 'weight': '72 kg', 'injured': False, 'photo': 'https://media.api-sports.io/football/players/301.png'}, 'statistics': [{'team': {'id': 40, 'name': 'Liverpool', 'logo': 'https://media.api-sports.io/football/teams/40.png'}, 'league': {'id': 39, 'name': 'Premier League', 'country': 'England', 'logo': 'https://media.api-sports.io/football/leagues/39.png', 'flag': 'https://media.api-sports.io/flags/gb.svg', 'season': 2020}, 'games': {'appearences': 0, 'lineups': 0, 'minutes': 0, 'number': None, 'position': 'Attacker', 'rating': None, 'captain': False}, 'substitutes': {'in': 0, 'out': 0, 'bench': 3}, 'shots': {'total': None, 'on': None}, 'goals': {'total': 0, 'conceded': 0, 'assists': None, 'saves': None}, 'passes': {'total': None, 'key': None, 'accuracy': None}, 'tackles': {'total': None, 'blocks': None, 'interceptions': None}, 'duels': {'total': None, 'won': None}, 'dribbles': {'attempts': None, 'success': None, 'past': None}, 'fouls': {'drawn': None, 'committed': None}, 'cards': {'yellow': 0, 'yellowred': 0, 'red': 0}, 'penalty': {'won': None, 'commited': None, 'scored': 0, 'missed': 0, 'saved': None}}]}, {'player': {'id': 518, 'name': 'Meritan Shabani', 'firstname': 'Meritan', 'lastname': 'Shabani', 'age': 23, 'birth': {'date': '1999-03-15', 'place': 'München', 'country': 'Germany'}, 'nationality': 'Germany', 'height': '185 cm', 'weight': '78 kg', 'injured': False, 'photo': 'https://media.api-sports.io/football/players/518.png'}, 'statistics': [{'team': {'id': 39, 'name': 'Wolves', 'logo': 'https://media.api-sports.io/football/teams/39.png'}, 'league': {'id': 39, 'name': 'Premier League', 'country': 'England', 'logo': 'https://media.api-sports.io/football/leagues/39.png', 'flag': 'https://media.api-sports.io/flags/gb.svg', 'season': 2020}, 'games': {'appearences': 0, 'lineups': 0, 'minutes': 0, 'number': None, 'position': 'Midfielder', 'rating': None, 'captain': False}, 'substitutes': {'in': 0, 'out': 0, 'bench': 3}, 'shots': {'total': None, 'on': None}, 'goals': {'total': 0, 'conceded': 0, 'assists': None, 'saves': None}, 'passes': {'total': None, 'key': None, 'accuracy': None}, 'tackles': {'total': None, 'blocks': None, 'interceptions': None}, 'duels': {'total': None, 'won': None}, 'dribbles': {'attempts': None, 'success': None, 'past': None}, 'fouls': {'drawn': None, 'committed': None}, 'cards': {'yellow': 0, 'yellowred': 0, 'red': 0}, 'penalty': {'won': None, 'commited': None, 'scored': 0, 'missed': 0, 'saved': None}}]},
This is the data type of each layer of the JSON file, from when I iterated through it with a For loop:
print(type(response)) <class 'dict'>
print(type(response_dump)) <class 'str'>
print(type(item)) <class 'str'>
print(type(player_item)) <class 'str'>
You do not have to json.dumps() in my opinion, just use the JSON from response to iterate:
for player in response['response']:
print(player)
{'player': {'id': 301, 'name': 'Benjamin Luke Woodburn', 'firstname': 'Benjamin Luke', 'lastname': 'Woodburn', 'age': 23, 'birth': {'date': '1999-10-15', 'place': 'Nottingham', 'country': 'England'}, 'nationality': 'Wales', 'height': '174 cm', 'weight': '72 kg', 'injured': False, 'photo': 'https://media.api-sports.io/football/players/301.png'}, 'statistics': [{'team': {'id': 40, 'name': 'Liverpool', 'logo': 'https://media.api-sports.io/football/teams/40.png'}, 'league': {'id': 39, 'name': 'Premier League', 'country': 'England', 'logo': 'https://media.api-sports.io/football/leagues/39.png', 'flag': 'https://media.api-sports.io/flags/gb.svg', 'season': 2020}, 'games': {'appearences': 0, 'lineups': 0, 'minutes': 0, 'number': None, 'position': 'Attacker', 'rating': None, 'captain': False}, 'substitutes': {'in': 0, 'out': 0, 'bench': 3}, 'shots': {'total': None, 'on': None}, 'goals': {'total': 0, 'conceded': 0, 'assists': None, 'saves': None}, 'passes': {'total': None, 'key': None, 'accuracy': None}, 'tackles': {'total': None, 'blocks': None, 'interceptions': None}, 'duels': {'total': None, 'won': None}, 'dribbles': {'attempts': None, 'success': None, 'past': None}, 'fouls': {'drawn': None, 'committed': None}, 'cards': {'yellow': 0, 'yellowred': 0, 'red': 0}, 'penalty': {'won': None, 'commited': None, 'scored': 0, 'missed': 0, 'saved': None}}]}
{'player': {'id': 518, 'name': 'Meritan Shabani', 'firstname': 'Meritan', 'lastname': 'Shabani', 'age': 23, 'birth': {'date': '1999-03-15', 'place': 'München', 'country': 'Germany'}, 'nationality': 'Germany', 'height': '185 cm', 'weight': '78 kg', 'injured': False, 'photo': 'https://media.api-sports.io/football/players/518.png'}, 'statistics': [{'team': {'id': 39, 'name': 'Wolves', 'logo': 'https://media.api-sports.io/football/teams/39.png'}, 'league': {'id': 39, 'name': 'Premier League', 'country': 'England', 'logo': 'https://media.api-sports.io/football/leagues/39.png', 'flag': 'https://media.api-sports.io/flags/gb.svg', 'season': 2020}, 'games': {'appearences': 0, 'lineups': 0, 'minutes': 0, 'number': None, 'position': 'Midfielder', 'rating': None, 'captain': False}, 'substitutes': {'in': 0, 'out': 0, 'bench': 3}, 'shots': {'total': None, 'on': None}, 'goals': {'total': 0, 'conceded': 0, 'assists': None, 'saves': None}, 'passes': {'total': None, 'key': None, 'accuracy': None}, 'tackles': {'total': None, 'blocks': None, 'interceptions': None}, 'duels': {'total': None, 'won': None}, 'dribbles': {'attempts': None, 'success': None, 'past': None}, 'fouls': {'drawn': None, 'committed': None}, 'cards': {'yellow': 0, 'yellowred': 0, 'red': 0}, 'penalty': {'won': None, 'commited': None, 'scored': 0, 'missed': 0, 'saved': None}}]}
or
for player in response['response']:
print(player['player'])
{'id': 301, 'name': 'Benjamin Luke Woodburn', 'firstname': 'Benjamin Luke', 'lastname': 'Woodburn', 'age': 23, 'birth': {'date': '1999-10-15', 'place': 'Nottingham', 'country': 'England'}, 'nationality': 'Wales', 'height': '174 cm', 'weight': '72 kg', 'injured': False, 'photo': 'https://media.api-sports.io/football/players/301.png'}
{'id': 518, 'name': 'Meritan Shabani', 'firstname': 'Meritan', 'lastname': 'Shabani', 'age': 23, 'birth': {'date': '1999-03-15', 'place': 'München', 'country': 'Germany'}, 'nationality': 'Germany', 'height': '185 cm', 'weight': '78 kg', 'injured': False, 'photo': 'https://media.api-sports.io/football/players/518.png'}
To get a DataFrame simply call pd.json_normalize() - Cause your question is not that clear I am not sure wiche information is needed and how to displayed. This is predestinated to ask a new question with exact that focus.:
pd.json_normalize(response['response'])
EDIT
Based on your comment and improvment:
pd.concat([pd.json_normalize(response,['response'])\
,pd.json_normalize(response,['response','statistics'])], axis=1)\
.drop(['statistics'], axis=1)
player.id
player.name
player.firstname
player.lastname
player.age
player.birth.date
player.birth.place
player.birth.country
player.nationality
player.height
player.weight
player.injured
player.photo
team.id
team.name
team.logo
league.id
league.name
league.country
league.logo
league.flag
league.season
games.appearences
games.lineups
games.minutes
games.number
games.position
games.rating
games.captain
substitutes.in
substitutes.out
substitutes.bench
shots.total
shots.on
goals.total
goals.conceded
goals.assists
goals.saves
passes.total
passes.key
passes.accuracy
tackles.total
tackles.blocks
tackles.interceptions
duels.total
duels.won
dribbles.attempts
dribbles.success
dribbles.past
fouls.drawn
fouls.committed
cards.yellow
cards.yellowred
cards.red
penalty.won
penalty.commited
penalty.scored
penalty.missed
penalty.saved
0
301
Benjamin Luke Woodburn
Benjamin Luke
Woodburn
23
1999-10-15
Nottingham
England
Wales
174 cm
72 kg
False
https://media.api-sports.io/football/players/301.png
40
Liverpool
https://media.api-sports.io/football/teams/40.png
39
Premier League
England
https://media.api-sports.io/football/leagues/39.png
https://media.api-sports.io/flags/gb.svg
2020
0
0
0
Attacker
False
0
0
3
0
0
0
0
0
0
0
1
518
Meritan Shabani
Meritan
Shabani
23
1999-03-15
München
Germany
Germany
185 cm
78 kg
False
https://media.api-sports.io/football/players/518.png
39
Wolves
https://media.api-sports.io/football/teams/39.png
39
Premier League
England
https://media.api-sports.io/football/leagues/39.png
https://media.api-sports.io/flags/gb.svg
2020
0
0
0
Midfielder
False
0
0
3
0
0
0
0
0
0
0
I found some elegant code that builds a list by iterating through each element of another JSON list:
results = [
(
t["vintage"]["wine"]["winery"]["name"],
t["vintage"]["year"],
t["vintage"]["wine"]["id"],
f'{t["vintage"]["wine"]["name"]} {t["vintage"]["year"]}',
t["vintage"]["wine"]["statistics"]["ratings_average"],
t["vintage"]["wine"]["statistics"]["ratings_count"],
t["price"]["amount"],
t["vintage"]["wine"]["region"]["name"],
t["vintage"]["wine"]["style"]["name"], #<--------------issue here
)
for t in r.json()["explore_vintage"]["matches"]
]
The problem is that sometimes the JSON doesn't have a "name" element because the "style" is null (or None in JSON world). See the second-last line below for the JSON sample.
Is there a simple way to handle this error?
Error:
matches[23]["vintage"]["wine"]["style"]["name"]
Traceback (most recent call last):
File "<ipython-input-94-59447d0d4859>", line 1, in <module>
matches[23]["vintage"]["wine"]["style"]["name"]
TypeError: 'NoneType' object is not subscriptable
Perhaps something like:
iferror(t["vintage"]["wine"]["style"]["name"], "DoesNotExist")
JSON:
{'id': 4026076,
'name': 'Shiraz - Petit Verdot',
'seo_name': 'shiraz-petit-verdot',
'type_id': 1,
'vintage_type': 0,
'is_natural': False,
'region': {'id': 685,
'name': 'South Eastern Australia',
'name_en': '',
'seo_name': 'south-eastern',
'country': {'code': 'au',
'name': 'Australia',
'native_name': 'Australia',
'seo_name': 'australia',
'sponsored': False,
'currency': {'code': 'AUD',
'name': 'Australian Dollars',
'prefix': '$',
'suffix': None},
'regions_count': 120,
'users_count': 867353,
'wines_count': 108099,
'wineries_count': 13375,
'most_used_grapes': [{'id': 1,
'name': 'Shiraz/Syrah',
'seo_name': 'shiraz-syrah',
'has_detailed_info': True,
'wines_count': 536370},
{'id': 2,
'name': 'Cabernet Sauvignon',
'seo_name': 'cabernet-sauvignon',
'has_detailed_info': True,
'wines_count': 780931},
{'id': 5,
'name': 'Chardonnay',
'seo_name': 'chardonnay',
'has_detailed_info': True,
'wines_count': 586874}],
'background_video': None},
'class': {'typecast_map': {'background_image': {}, 'class': {}}},
'background_image': {'location': '//images.vivino.com/regions/backgrounds/0iT8wuQXRWaAmEGpPjZckg.jpg',
'variations': {'large': '//thumbs.vivino.com/region_backgrounds/0iT8wuQXRWaAmEGpPjZckg_1280x760.jpg',
'medium': '//thumbs.vivino.com/region_backgrounds/0iT8wuQXRWaAmEGpPjZckg_600x356.jpg'}}},
'winery': {'id': 74363,
'name': 'Barramundi',
'seo_name': 'barramundi',
'status': 0,
'background_image': None},
'taste': {'structure': None,
'flavor': [{'group': 'black_fruit', 'stats': {'count': 16, 'score': 2987}},
{'group': 'oak', 'stats': {'count': 11, 'score': 1329}},
{'group': 'red_fruit', 'stats': {'count': 10, 'score': 1413}},
{'group': 'spices', 'stats': {'count': 6, 'score': 430}},
{'group': 'non_oak', 'stats': {'count': 5, 'score': 126}},
{'group': 'floral', 'stats': {'count': 3, 'score': 300}},
{'group': 'earth', 'stats': {'count': 3, 'score': 249}},
{'group': 'microbio', 'stats': {'count': 2, 'score': 66}},
{'group': 'vegetal', 'stats': {'count': 1, 'score': 100}},
{'group': 'dried_fruit', 'stats': {'count': 1, 'score': 100}}]},
'statistics': {'status': 'Normal',
'ratings_count': 1002,
'ratings_average': 3.5,
'labels_count': 11180,
'vintages_count': 25},
'style': None,
'has_valid_ratings': True}
I am trying to create dataframe from the json which I fetched from Quickbooks APAgingSummary API, but I am getting an error "TypeError: object of type 'float' has no len()", when I am inserting json_normalize data in the form of list to pandas. I used the same code for creating Dataframe from Quickbooks AccountListDetail API Json and it was working fine.
This code was used for fetching data:
base_url = 'https://sandbox-quickbooks.api.intuit.com'
url = f"{base_url}/v3/company/{auth_client.realm_id}/reports/AgedPayables?&minorversion=62"
auth_header = f'Bearer {auth_client.access_token}'
headers = {
'Authorization': auth_header,
'Accept': 'application/json'
}
response = requests.get(url, headers=headers)
responseJson = response.json()
responseJson
This is the responseJson:
{'Header': {'Time': '2021-10-05T04:33:02-07:00',
'ReportName': 'AgedPayables',
'DateMacro': 'today',
'StartPeriod': '2021-10-05',
'EndPeriod': '2021-10-05',
'SummarizeColumnsBy': 'Total',
'Currency': 'USD',
'Option': [{'Name': 'report_date', 'Value': '2021-10-05'},
{'Name': 'NoReportData', 'Value': 'false'}]},
'Columns': {'Column': [{'ColTitle': '', 'ColType': 'Vendor'},
{'ColTitle': 'Current',
'ColType': 'Money',
'MetaData': [{'Name': 'ColKey', 'Value': 'current'}]},
{'ColTitle': '1 - 30',
'ColType': 'Money',
'MetaData': [{'Name': 'ColKey', 'Value': '0'}]},
{'ColTitle': '31 - 60',
'ColType': 'Money',
'MetaData': [{'Name': 'ColKey', 'Value': '1'}]},
{'ColTitle': '61 - 90',
'ColType': 'Money',
'MetaData': [{'Name': 'ColKey', 'Value': '2'}]},
{'ColTitle': '91 and over',
'ColType': 'Money',
'MetaData': [{'Name': 'ColKey', 'Value': '3'}]},
{'ColTitle': 'Total',
'ColType': 'Money',
'MetaData': [{'Name': 'ColKey', 'Value': 'total'}]}]},
'Rows': {'Row': [{'ColData': [{'value': 'Brosnahan Insurance Agency',
'id': '31'},
{'value': ''},
{'value': '241.23'},
{'value': ''},
{'value': ''},
{'value': ''},
{'value': '241.23'}]},
{'ColData': [{'value': "Diego's Road Warrior Bodyshop", 'id': '36'},
{'value': '755.00'},
{'value': ''},
{'value': ''},
{'value': ''},
{'value': ''},
{'value': '755.00'}]},
{'ColData': [{'value': 'Norton Lumber and Building Materials', 'id': '46'},
{'value': ''},
{'value': '205.00'},
{'value': ''},
{'value': ''},
{'value': ''},
{'value': '205.00'}]},
{'ColData': [{'value': 'PG&E', 'id': '48'},
{'value': ''},
{'value': ''},
{'value': '86.44'},
{'value': ''},
{'value': ''},
{'value': '86.44'}]},
{'ColData': [{'value': 'Robertson & Associates', 'id': '49'},
{'value': ''},
{'value': '315.00'},
{'value': ''},
{'value': ''},
{'value': ''},
{'value': '315.00'}]},
{'Summary': {'ColData': [{'value': 'TOTAL'},
{'value': '755.00'},
{'value': '761.23'},
{'value': '86.44'},
{'value': '0.00'},
{'value': '0.00'},
{'value': '1602.67'}]},
'type': 'Section',
'group': 'GrandTotal'}]}}
this is the code where I am getting the error:
colHeaders = []
for i in responseJson['Columns']['Column']:
colHeaders.append(i['ColTitle'])
responseDf = pd.json_normalize(responseJson["Rows"]["Row"])
responseDf[colHeaders] = pd.DataFrame(responseDf.ColData.tolist(), index= responseDf.index)
this is the responseDf after json_normalize:
ColData type group Summary.ColData
0 [{'value': 'Brosnahan Insurance Agency', 'id':... NaN NaN NaN
1 [{'value': 'Diego's Road Warrior Bodyshop', 'i... NaN NaN NaN
2 [{'value': 'Norton Lumber and Building Materia... NaN NaN NaN
3 [{'value': 'PG&E', 'id': '48'}, {'value': ''},... NaN NaN NaN
4 [{'value': 'Robertson & Associates', 'id': '49... NaN NaN NaN
5 NaN Section GrandTotal [{'value': 'TOTAL'}, {'value': '755.00'}, {'va...
each element of ColData contains list of dictionaries.
and This is the error:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-215-6ce65ce2ac94> in <module>
6
7 responseDf = pd.json_normalize(responseJson["Rows"]["Row"])
----> 8 responseDf[colHeaders] = pd.DataFrame(responseDf.ColData.tolist(), index= responseDf.index)
9 responseDf
10
C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\frame.py in __init__(self, data, index, columns, dtype, copy)
507 if is_named_tuple(data[0]) and columns is None:
508 columns = data[0]._fields
--> 509 arrays, columns = to_arrays(data, columns, dtype=dtype)
510 columns = ensure_index(columns)
511
C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\internals\construction.py in to_arrays(data, columns, coerce_float, dtype)
522 return [], [] # columns if columns is not None else []
523 if isinstance(data[0], (list, tuple)):
--> 524 return _list_to_arrays(data, columns, coerce_float=coerce_float, dtype=dtype)
525 elif isinstance(data[0], abc.Mapping):
526 return _list_of_dict_to_arrays(
C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\internals\construction.py in _list_to_arrays(data, columns, coerce_float, dtype)
559 else:
560 # list of lists
--> 561 content = list(lib.to_object_array(data).T)
562 # gh-26429 do not raise user-facing AssertionError
563 try:
pandas\_libs\lib.pyx in pandas._libs.lib.to_object_array()
TypeError: object of type 'float' has no len()
Any help will be really appreciated.
You got the error because there is NaN value on the ColData column in responseDf. NaN is considered float type and has no len(), hence the error.
To solve the problem, you can init the NaN with list of empty dict with .fillna(), as follows:
responseDf['ColData'] = responseDf['ColData'].fillna({i: [{}] for i in responseDf.index})
Put the codes immediately after the line with pd.json_normalize
The full set of codes will be:
colHeaders = []
for i in responseJson['Columns']['Column']:
colHeaders.append(i['ColTitle'])
responseDf = pd.json_normalize(responseJson["Rows"]["Row"])
## Add the code here
responseDf['ColData'] = responseDf['ColData'].fillna({i: [{}] for i in responseDf.index})
responseDf[colHeaders] = pd.DataFrame(responseDf.ColData.tolist(), index= responseDf.index)
Then, you will get through the error and get the result of responseDf, as follows:
print(responseDf)
ColData type group Summary.ColData Current 1 - 30 31 - 60 61 - 90 91 and over Total
0 [{'value': 'Brosnahan Insurance Agency', 'id': '31'}, {'value': ''}, {'value': '241.23'}, {'value': ''}, {'value': ''}, {'value': ''}, {'value': '241.23'}] NaN NaN NaN {'value': 'Brosnahan Insurance Agency', 'id': '31'} {'value': ''} {'value': '241.23'} {'value': ''} {'value': ''} {'value': ''} {'value': '241.23'}
1 [{'value': 'Diego's Road Warrior Bodyshop', 'id': '36'}, {'value': '755.00'}, {'value': ''}, {'value': ''}, {'value': ''}, {'value': ''}, {'value': '755.00'}] NaN NaN NaN {'value': 'Diego's Road Warrior Bodyshop', 'id': '36'} {'value': '755.00'} {'value': ''} {'value': ''} {'value': ''} {'value': ''} {'value': '755.00'}
2 [{'value': 'Norton Lumber and Building Materials', 'id': '46'}, {'value': ''}, {'value': '205.00'}, {'value': ''}, {'value': ''}, {'value': ''}, {'value': '205.00'}] NaN NaN NaN {'value': 'Norton Lumber and Building Materials', 'id': '46'} {'value': ''} {'value': '205.00'} {'value': ''} {'value': ''} {'value': ''} {'value': '205.00'}
3 [{'value': 'PG&E', 'id': '48'}, {'value': ''}, {'value': ''}, {'value': '86.44'}, {'value': ''}, {'value': ''}, {'value': '86.44'}] NaN NaN NaN {'value': 'PG&E', 'id': '48'} {'value': ''} {'value': ''} {'value': '86.44'} {'value': ''} {'value': ''} {'value': '86.44'}
4 [{'value': 'Robertson & Associates', 'id': '49'}, {'value': ''}, {'value': '315.00'}, {'value': ''}, {'value': ''}, {'value': ''}, {'value': '315.00'}] NaN NaN NaN {'value': 'Robertson & Associates', 'id': '49'} {'value': ''} {'value': '315.00'} {'value': ''} {'value': ''} {'value': ''} {'value': '315.00'}
5 [{}] Section GrandTotal [{'value': 'TOTAL'}, {'value': '755.00'}, {'value': '761.23'}, {'value': '86.44'}, {'value': '0.00'}, {'value': '0.00'}, {'value': '1602.67'}] {} None None None None None None
I have the following two lists:
retrieved_sessions = [
{'start_time': '2020-01-17T08:30:00.000Z', 'availability': '5'},
{'start_time': '2020-01-17T09:30:00.000Z', 'availability': '7'},
{'start_time': '2020-01-17T10:30:00.000Z', 'availability': '6'},
{'start_time': '2020-01-17T11:30:00.000Z', 'availability': '5'},
{'start_time': '2020-01-17T12:30:00.000Z', 'availability': '0'},
{'start_time': '2020-01-17T13:30:00.000Z', 'availability': '2'},
{'start_time': '2020-01-17T14:30:00.000Z', 'availability': '13'}
]
all_sessions = [
{'start_time': '2020-01-17T09:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T09:30:00.000Z', 'availability': None},
{'start_time': '2020-01-17T10:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T10:30:00.000Z', 'availability': None},
{'start_time': '2020-01-17T11:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T11:30:00.000Z', 'availability': None},
{'start_time': '2020-01-17T12:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T12:30:00.000Z', 'availability': None},
{'start_time': '2020-01-17T13:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T13:30:00.000Z', 'availability': None},
{'start_time': '2020-01-17T14:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T14:30:00.000Z', 'availability': None},
{'start_time': '2020-01-17T15:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T15:30:00.000Z', 'availability': None}
]
I was wondering, what would be the best way to update the dictionary in all_sessions with the availability from the corresponding retrieved_sessions dictinary, using the start_time as the primary key lookup/matching field?
Expected output:
all_sessions = [
{'start_time': '2020-01-17T09:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T09:30:00.000Z', 'availability': '7'},
{'start_time': '2020-01-17T10:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T10:30:00.000Z', 'availability': '6'},
{'start_time': '2020-01-17T11:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T11:30:00.000Z', 'availability': '5'},
{'start_time': '2020-01-17T12:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T12:30:00.000Z', 'availability': '0'},
{'start_time': '2020-01-17T13:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T13:30:00.000Z', 'availability': '2'},
{'start_time': '2020-01-17T14:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T14:30:00.000Z', 'availability': '13'},
{'start_time': '2020-01-17T15:00:00.000Z', 'availability': None},
{'start_time': '2020-01-17T15:30:00.000Z', 'availability': None}
]
I have tried the following loop within a loop:
for available in availability:
for session in sessions:
if session['start_time'] == available['start_time']:
session['availability'] = available['availability']
N.B. Data is coming from a SOAP API, hence the wierd '1'/'2' instead of e.g., 1, 2. etc
You can make helper dict where the key is start_time and value is availability and then replace correspondent values in all_sessions
d = {s['start_time']: s['availability'] for s in retrieved_sessions}
for s in all_sessions:
s['availability'] = d.get(s['start_time'])
from pprint import pprint
pprint(all_sessions)
Prints:
[{'availability': None, 'start_time': '2020-01-17T09:00:00.000Z'},
{'availability': '7', 'start_time': '2020-01-17T09:30:00.000Z'},
{'availability': None, 'start_time': '2020-01-17T10:00:00.000Z'},
{'availability': '6', 'start_time': '2020-01-17T10:30:00.000Z'},
{'availability': None, 'start_time': '2020-01-17T11:00:00.000Z'},
{'availability': '5', 'start_time': '2020-01-17T11:30:00.000Z'},
{'availability': None, 'start_time': '2020-01-17T12:00:00.000Z'},
{'availability': '0', 'start_time': '2020-01-17T12:30:00.000Z'},
{'availability': None, 'start_time': '2020-01-17T13:00:00.000Z'},
{'availability': '2', 'start_time': '2020-01-17T13:30:00.000Z'},
{'availability': None, 'start_time': '2020-01-17T14:00:00.000Z'},
{'availability': '13', 'start_time': '2020-01-17T14:30:00.000Z'},
{'availability': None, 'start_time': '2020-01-17T15:00:00.000Z'},
{'availability': None, 'start_time': '2020-01-17T15:30:00.000Z'}]
Create a new dict with start_time as keys and availability as values.
Then iterate over copy.deepcopy(all_sessions).items(), matching on start_time and adding to the original all_sessions as you go. The deepcopy is because you can't iterate over a dict and modify it in the same pass.
The two nested for loops in your example are O(n*m) - IOW it's slow. Introducing a dict this way will speed things up to O(n+m).
Note that keying on times is prone to problems from duplicate times.