escape string in mysql insert query - python

am inserting a list of dictionaries in a mysql table with the code below, but having issues on how to escape ',' and other potential error...
data=[{'index': 1, 'kite_size': u'5', 'source': 'spainkiters', 'type': 'kite', 'brand': u'rrd', 'title': u'RRD Religion 2014 10\xb45m usada solo 1 vez', 'id': u'112506', 'kite_model': u'religion', 'location': u' santa pola', 'year': u'2014', 'date_added': u' Lun Ene 27, 2014 9:52 am', 'quality': 5, 'price': None}, {'index': 1, 'kite_size': u'10', 'source': 'spainkiters', 'quality': 5, 'price': u'750', 'title': u'Vendo Kite completo Nobile Fifty 10M 2013', 'id': u'112762', 'kite_model': u'fifty', 'location': u'', 'year': u'2013', 'date_added': u' Mar Feb 11, 2014 5:38 pm', 'type': 'kite', 'brand': u'nobile'}, {'index': 1, 'kite_size': u'7', 'source': 'spainkiters', 'quality': 5, 'price': None, 'title': u'NORTH EVO 7m 2013 !!!!!!!!!!!!!', 'id': u'112789', 'kite_model': u'evo', 'location': u'', 'year': u'2013', 'date_added': u' Mie Feb 12, 2014 9:08 pm', 'type': 'kite', 'brand': u'north'}, {'index': 1, 'kite_size': u'5', 'source': 'spainkiters', 'quality': 4, 'price': u'350', 'title': u'cabrinha convers 2012 5m y tabla slingshot lunaci 1,28cm', 'id': u'112767', 'kite_model': None, 'location': u' pais vasco', 'year': u'2012', 'date_added': u' Mar Feb 11, 2014 6:41 pm', 'type': 'kite', 'brand': u'cabrinha'}, {'index': 1, 'kite_size': u'5', 'source': 'spainkiters', 'quality': 4, 'price': u'350', 'title': u'cabrinha convers 2012 5m y tabla slingshot lunaci 1,28cm', 'id': u'112766', 'kite_model': None, 'location': u' pais vasco', 'year': u'2012', 'date_added': u' Mar Feb 11, 2014 6:33 pm', 'type': 'kite', 'brand': u'cabrinha'}, {'index': 1, 'kite_size': u'8', 'source': 'spainkiters', 'type': 'kite', 'brand': u'flexifoil', 'title': u'flexifoil HADLOW ID 8 metros precio negociable', 'id': u'112512', 'kite_model': u'hadlow', 'location': u' Gran Canaria', 'year': None, 'date_added': u' Lun Ene 27, 2014 5:08 pm', 'quality': 5, 'price': None}, {'index': 1, 'kite_size': u'11', 'source': 'spainkiters', 'quality': 5, 'price': u'500', 'title': u'VENDO SWITCH COMBAT 11M A\xd1O 2013...500E ENVIO INCLUIDO!!', 'id': u'112773', 'kite_model': u'combat', 'location': u'', 'year': u'2013', 'date_added': u' Mar Feb 11, 2014 9:11 pm', 'type': 'kite', 'brand': u'switch'}]
cursor.executemany("INSERT INTO search_kite_products_4 (brand, kite_model, kite_size, year, source, id, location, title, date_added, quality, price, link_id) VALUES (%(brand)s, %(kite_model), %(kite_size)s, %(year)s, %(source)s, %(id)s, %(location)s, %%(title)s%, %%(date_added)s%, %(quality)s, %(price)s, %(id)s)", data)
db.commit()
db.close()
I tried to add an additional % before the fields which could have such characters but it did not work...
Traceback (most recent call last):
File "C:\Program Files (x86)\JetBrains\PyCharm Community Edition 3.1.1\helpers\pydev\pydevd.py", line 1534, in <module>
debugger.run(setup['file'], None, None)
File "C:\Program Files (x86)\JetBrains\PyCharm Community Edition 3.1.1\helpers\pydev\pydevd.py", line 1145, in run
pydev_imports.execfile(file, globals, locals) #execute the script
File "C:/Users/Joao/PycharmProjects/Olympia/olympiaspt/scripts/test_sql.py", line 30, in <module>
cursor.executemany("INSERT INTO search_kite_products_4 (brand, kite_model, kite_size, year, source, id, location, title, date_added, quality, price, link_id) VALUES (%(brand)s, %(kite_model), %(kite_size)s, %(year)s, %(source)s, %(id)s, %(location)s, %%(title)s%, %%(date_added)s%, %(quality)s, %(price)s, %(id)s)", data)
File "C:\Python27\lib\site-packages\MySQLdb\cursors.py", line 252, in executemany
self.errorhandler(self, exc, value)
File "C:\Python27\lib\site-packages\MySQLdb\connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
ValueError: unsupported format character ',' (0x2c) at index 25

You missed out an s:
%(kite_model),
should be
%(kite_model)s,
You also added % characters too many here:
%%(title)s%, %%(date_added)s%
that should be just:
%(title)s, %(date_added)s
If you need to insert literal % characters around your column data, add these to your Python strings or use SQL functions to explicitly concatenate these server side.

Related

having trouble passing multiple dictionaries for the argument record_path in json_normalize

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.

Iterating over JSON data and printing. (or creating Pandas DataFrame from JSON file)

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

Iterating through JSON array and appending values to pandas df based on condition

I have two datasets - one as a dataframe and the other as an array of JSON files.
Each line in the df has a string (folio number) that identifies a piece of land (Ex: '0101000000030'), and a date (in datetime) a permit was applied for.
Every JSON file in the array has a corresponding number identifying that land. It also has dates the property was sold, to whom it was sold, and the seller.
I need to take the folio number and the date the permit was applied for and run it through the array of JSON files until it finds the matching folio.
Then, it needs to extract the property's owner information by finding who owned the property when the permit was applied for and append it to the corresponding row in the df.
Desired Output
FirstSubmissionDate Folio PropertyOwner
05/17/2018 '0101000000030' blahblah
Input DF
FirstSubmissionDate Folio
05/17/2018 '0101000000030'
Input JSON
{'Additionals': {'AddtionalInfo': [{'Key': 'LAND USE AND RESTRICTIONS',
'Value': [{'InfoName': 'Community Development District',
'InfoValue': 'COUNTYGIS',
'Message': ''},
{'InfoName': 'Community Redevelopment Area',
'InfoValue': 'COUNTYGIS',
'Message': ''},
{'InfoName': 'Empowerment Zone', 'InfoValue': 'COUNTYGIS', 'Message': ''},
{'InfoName': 'Enterprise Zone', 'InfoValue': 'COUNTYGIS', 'Message': ''},
{'InfoName': 'Urban Development',
'InfoValue': 'COUNTYGIS',
'Message': ''},
{'InfoName': 'Zoning Code', 'InfoValue': 'COUNTYGIS', 'Message': ''},
{'InfoName': 'Existing Land Use',
'InfoValue': 'COUNTYGIS',
'Message': ''},
{'InfoName': 'Government Agencies and Community Services',
'InfoValue': 'http://gisweb.miamidade.gov/communityservices/CommunityServicesAll.html?x=&y=&bufferDistance=5&address=60 SE 2 ST',
'Message': ''}]},
{'Key': 'OTHER GOVERNMENTAL JURISDICTIONS',
'Value': [{'InfoName': 'Business Incentives',
'InfoValue': 'https://gisweb.miamidade.gov/businessincentive/default.aspx?searchtype=address&paramvalue=',
'Message': ''},
{'InfoName': 'Childrens Trust',
'InfoValue': 'https://www.thechildrenstrust.org/',
'Message': ''},
{'InfoName': 'City of Miami',
'InfoValue': 'http://www.miamigov.com/home/',
'Message': ''},
{'InfoName': 'Environmental Considerations',
'InfoValue': 'https://gisweb.miamidade.gov/environmentalconsiderations/default.aspx?searchtype=address&paramvalue=60 SE 2 ST',
'Message': ''},
{'InfoName': 'Florida Inland Navigation District',
'InfoValue': 'http://www.aicw.org',
'Message': ''},
{'InfoName': 'PA Bulletin Board',
'InfoValue': 'http://bbs.miamidade.gov/',
'Message': ''},
{'InfoName': 'Special Taxing District and Other Non-Ad valorem Assessment',
'InfoValue': 'http://www.miamidade.gov/Apps/PA/PAOnlineTools/Taxes/NonAdvalorem.aspx?folio=0101000000030',
'Message': ''},
{'InfoName': 'School Board',
'InfoValue': 'http://www.dadeschools.net/',
'Message': ''},
{'InfoName': 'South Florida Water Mgmt District',
'InfoValue': 'http://www.sfwmd.gov/portal/page/portal/sfwmdmain/home%20page',
'Message': ''},
{'InfoName': 'Tax Collector',
'InfoValue': 'http://www.miamidade.gov/taxcollector/',
'Message': ''}]}],
'FooterMessage': '',
'HeaderMessage': "* The information listed below is not derived from the Property Appraiser's Office records. It is provided for convenience and is derived from other government agencies."},
'Assessment': {'AssessmentInfos': [{'AssessedValue': 5587359,
'BuildingOnlyValue': 0,
'ExtraFeatureValue': 0,
'LandValue': 7618560,
'Message': None,
'TotalValue': 7618560,
'Year': 2021},
{'AssessedValue': 5079418,
'BuildingOnlyValue': 0,
'ExtraFeatureValue': 0,
'LandValue': 6963200,
'Message': None,
'TotalValue': 6963200,
'Year': 2020},
{'AssessedValue': 4617653,
'BuildingOnlyValue': 0,
'ExtraFeatureValue': 0,
'LandValue': 6963200,
'Message': None,
'TotalValue': 6963200,
'Year': 2019}],
'Messages': [{'Message': '', 'Year': 2021},
{'Message': '', 'Year': 2020},
{'Message': '', 'Year': 2019}]},
'Benefit': {'BenefitInfos': [{'Description': 'Non-Homestead Cap',
'Message': None,
'Seq': '5',
'TaxYear': 2021,
'Type': 'Assessment Reduction',
'Url': 'http://www.miamidade.gov/pa/property_value_cap.asp',
'Value': 2031201},
{'Description': 'Non-Homestead Cap',
'Message': None,
'Seq': '5',
'TaxYear': 2020,
'Type': 'Assessment Reduction',
'Url': 'http://www.miamidade.gov/pa/property_value_cap.asp',
'Value': 1883782},
{'Description': 'Non-Homestead Cap',
'Message': None,
'Seq': '5',
'TaxYear': 2019,
'Type': 'Assessment Reduction',
'Url': 'http://www.miamidade.gov/pa/property_value_cap.asp',
'Value': 2345547}],
'Messages': []},
'Building': {'BuildingInfos': [], 'Messages': []},
'ClassifiedAgInfo': {'Acreage': 0,
'CalculatedValue': 0,
'LandCode': None,
'LandUse': None,
'Message': None,
'UnitPrice': 0},
'Completed': True,
'District': 6,
'ExtraFeature': {'ExtraFeatureInfos': [], 'Messages': []},
'GeoParcel': None,
'Land': {'Landlines': [{'AdjustedUnitPrice': 465,
'CalculatedValue': 7618560,
'Depth': 0,
'FrontFeet': 0,
'LandUse': 'GENERAL',
'LandlineType': 'C',
'Message': None,
'MuniZone': 'T6-80-O',
'MuniZoneDescription': None,
'PAZoneDescription': 'COMMERCIAL',
'PercentCondition': 1,
'RollYear': 2021,
'TotalAdjustments': 1,
'UnitType': 'Square Ft.',
'Units': 16384,
'UseCode': '00',
'Zone': '6401'},
{'AdjustedUnitPrice': -1,
'CalculatedValue': -1,
'Depth': 0,
'FrontFeet': 0,
'LandUse': 'GENERAL',
'LandlineType': 'C',
'Message': None,
'MuniZone': 'T6-80-O',
'MuniZoneDescription': None,
'PAZoneDescription': 'COMMERCIAL',
'PercentCondition': 1,
'RollYear': 2020,
'TotalAdjustments': 1,
'UnitType': 'Square Ft.',
'Units': 16384,
'UseCode': '00',
'Zone': '6401'},
{'AdjustedUnitPrice': -1,
'CalculatedValue': -1,
'Depth': 0,
'FrontFeet': 0,
'LandUse': 'GENERAL',
'LandlineType': 'C',
'Message': None,
'MuniZone': 'T6-80-O',
'MuniZoneDescription': None,
'PAZoneDescription': 'COMMERCIAL',
'PercentCondition': 1,
'RollYear': 2019,
'TotalAdjustments': 1,
'UnitType': 'Square Ft.',
'Units': 16384,
'UseCode': '00',
'Zone': '6401'}],
'Messages': [{'Message': '', 'Year': 2021},
{'Message': 'The calculated values for this property have been overridden. Please refer to the Land, Building, and XF Values in the Assessment Section, in order to obtain the most accurate values.',
'Year': 2020},
{'Message': 'The calculated values for this property have been overridden. Please refer to the Land, Building, and XF Values in the Assessment Section, in order to obtain the most accurate values.',
'Year': 2019}]},
'LegalDescription': {'Description': 'MIAMI NORTH PB B-41|BEG 12.2FT W OF X OF S/L OF SE 2|ST & W/L OF SE 1 AVE TH S11.85FT|SWLY A/D 72.55FT S52.71FT|W108.69FT N10FT W4.6FT N123.52FT|E137.4FT TO POB|LOT SIZE 16384 SQ FT|COC 25843-0025 26307-3840 0707 6',
'Message': None,
'Number': None},
'MailingAddress': {'Address1': '1000 BRICKELL AVE STE 400',
'Address2': '',
'Address3': '',
'City': 'MIAMI',
'Country': 'USA',
'Message': None,
'State': 'FL',
'ZipCode': '33131'},
'Message': '',
'OwnerInfos': [{'Description': 'Sole Owner',
'MarriedFlag': '0',
'Message': None,
'Name': '16 SE 2ND STREET DOWNTOWN',
'PercentageOwn': 1,
'Role': None,
'ShortDescription': 'Sole Owner',
'TenancyCd': 'S'},
{'Description': 'Sole Owner',
'MarriedFlag': '0',
'Message': None,
'Name': 'INVESTMENT LLC',
'PercentageOwn': 1,
'Role': None,
'ShortDescription': 'Sole Owner',
'TenancyCd': 'S'}],
'PropertyInfo': {'BathroomCount': 0,
'BedroomCount': 0,
'BuildingActualArea': 0,
'BuildingBaseArea': 0,
'BuildingEffectiveArea': 0,
'BuildingGrossArea': 0,
'BuildingHeatedArea': 0,
'DORCode': '1081',
'DORDescription': 'VACANT LAND - COMMERCIAL : VACANT LAND',
'DORDescriptionCurrent': None,
'EncodedFolioAndTaxYear': 'J1COeydnmm%2fHHVEoyromqjt3GPqH8da%2fsulgVBOgI7w%3d',
'FloorCount': 0,
'FolioNumber': '01-0100-000-0030',
'HalfBathroomCount': 0,
'HxBaseYear': 0,
'LotSize': 16384,
'Message': None,
'Municipality': 'Miami',
'Neighborhood': 69010,
'NeighborhoodDescription': 'Miami CBD',
'ParentFolio': '',
'PercentHomesteadCapped': 0,
'PlatBook': 'B',
'PlatPage': '41',
'PrimaryZone': '6401',
'PrimaryZoneDescription': 'COMMERCIAL',
'ShowCurrentValuesFlag': 'N',
'Status': 'AC Active',
'Subdivision': '010100000',
'SubdivisionDescription': '353017046',
'UnitCount': 0,
'YearBuilt': '0'},
'RollYear1': 2021,
'SalesInfos': [{'DateOfSale': '6/23/2021',
'DocumentStamps': 276000,
'EncodedRecordBookAndPage': 'lHVlhHQhIZoJRUYKiXnhi4goVgjenckUAcgPekALEZ8LlG%2bmH%2bycTA%3d%3d',
'GranteeName1': '16 SE 2ND STREET DOWNTOWN',
'GranteeName2': 'INVESTMENT LLC',
'GrantorName1': '16 SE 2ND STREET LLC',
'GrantorName2': '',
'Message': None,
'OfficialRecordBook': '32602',
'OfficialRecordPage': '3521',
'QualificationDescription': 'Qual on DOS, multi-parcel sale',
'QualifiedFlag': 'Q',
'QualifiedSYear': None,
'QualifiedSourceCode': '',
'ReasonCode': '05',
'ReviewCode': None,
'SaleId': 5,
'SaleInstrument': 'WDE',
'SalePrice': 46000000,
'VacantFlag': '\x00',
'ValidCode': None,
'VerifyCode': None},
{'DateOfSale': '5/24/2013',
'DocumentStamps': 0,
'EncodedRecordBookAndPage': 'lHVlhHQhIZoJRUYKiXnhiyo2fiU6Ad2Yj6ROwqxBp26vA0B1JkALuQ%3d%3d',
'GranteeName1': '16 SE 2ND STREET LLC',
'GranteeName2': '',
'GrantorName1': 'BURDINES 1225 LLC',
'GrantorName2': '',
'Message': None,
'OfficialRecordBook': '28688',
'OfficialRecordPage': '1169',
'QualificationDescription': 'Financial inst or "In Lieu of Forclosure" stated',
'QualifiedFlag': 'U',
'QualifiedSYear': None,
'QualifiedSourceCode': '',
'ReasonCode': '12',
'ReviewCode': None,
'SaleId': 4,
'SaleInstrument': 'DEE',
'SalePrice': 32620638,
'VacantFlag': '\x00',
'ValidCode': None,
'VerifyCode': None},
{'DateOfSale': '8/1/1989',
'DocumentStamps': 0,
'EncodedRecordBookAndPage': 'lHVlhHQhIZoJRUYKiXnhi9bvfovmAqmTIZ5uJf3HEgtQChvRqiPQDw%3d%3d',
'GranteeName1': '',
'GranteeName2': '',
'GrantorName1': '',
'GrantorName2': '',
'Message': None,
'OfficialRecordBook': '14202',
'OfficialRecordPage': '2339',
'QualificationDescription': 'Deeds that include more than one parcel',
'QualifiedFlag': 'Q',
'QualifiedSYear': None,
'QualifiedSourceCode': '',
'ReasonCode': '02',
'ReviewCode': None,
'SaleId': 3,
'SaleInstrument': '',
'SalePrice': 6200000,
'VacantFlag': '\x00',
'ValidCode': None,
'VerifyCode': None},
{'DateOfSale': '9/1/2003',
'DocumentStamps': 0,
'EncodedRecordBookAndPage': 'lHVlhHQhIZoJRUYKiXnhi5pTmn2bXcBBM42%2bwPcIyhry9UhcpSwX4g%3d%3d',
'GranteeName1': '',
'GranteeName2': '',
'GrantorName1': '',
'GrantorName2': '',
'Message': None,
'OfficialRecordBook': '21695',
'OfficialRecordPage': '3500',
'QualificationDescription': 'Deeds that include more than one parcel',
'QualifiedFlag': 'Q',
'QualifiedSYear': None,
'QualifiedSourceCode': '',
'ReasonCode': '02',
'ReviewCode': None,
'SaleId': 2,
'SaleInstrument': '',
'SalePrice': 8800000,
'VacantFlag': '\x00',
'ValidCode': None,
'VerifyCode': None},
{'DateOfSale': '7/1/2007',
'DocumentStamps': 0,
'EncodedRecordBookAndPage': 'lHVlhHQhIZoJRUYKiXnhi5bVa6yEIUa%2bSDngqM2N5YUM89ag%2fj8HOA%3d%3d',
'GranteeName1': '',
'GranteeName2': '',
'GrantorName1': '',
'GrantorName2': '',
'Message': None,
'OfficialRecordBook': '25843',
'OfficialRecordPage': '0025',
'QualificationDescription': 'Other disqualified',
'QualifiedFlag': 'U',
'QualifiedSYear': None,
'QualifiedSourceCode': '',
'ReasonCode': '03',
'ReviewCode': None,
'SaleId': 1,
'SaleInstrument': '',
'SalePrice': 21500000,
'VacantFlag': '\x00',
'ValidCode': None,
'VerifyCode': None}],
'SiteAddress': [{'Address': '60 SE 2 ST, Miami, FL 33131-2103',
'BuildingNumber': 1,
'City': 'Miami',
'HouseNumberSuffix': '',
'Message': None,
'StreetName': '2',
'StreetNumber': 60,
'StreetPrefix': 'SE',
'StreetSuffix': 'ST',
'StreetSuffixDirection': '',
'Unit': '',
'Zip': '33131-2103'}],
'Taxable': {'Messages': [],
'TaxableInfos': [{'CityExemptionValue': 0,
'CityTaxableValue': 5587359,
'CountyExemptionValue': 0,
'CountyTaxableValue': 5587359,
'Message': None,
'RegionalExemptionValue': 0,
'RegionalTaxableValue': 5587359,
'SchoolExemptionValue': 0,
'SchoolTaxableValue': 7618560,
'Year': 2021},
{'CityExemptionValue': 0,
'CityTaxableValue': 5079418,
'CountyExemptionValue': 0,
'CountyTaxableValue': 5079418,
'Message': None,
'RegionalExemptionValue': 0,
'RegionalTaxableValue': 5079418,
'SchoolExemptionValue': 0,
'SchoolTaxableValue': 6963200,
'Year': 2020},
{'CityExemptionValue': 0,
'CityTaxableValue': 4617653,
'CountyExemptionValue': 0,
'CountyTaxableValue': 4617653,
'Message': None,
'RegionalExemptionValue': 0,
'RegionalTaxableValue': 4617653,
'SchoolExemptionValue': 0,
'SchoolTaxableValue': 6963200,
'Year': 2019}]}}
I can distill down to the sales info:
for y in variable_name[1]['SalesInfos']:
y = y['DateOfSale']
y = datetime.strptime(y, '%m/%d/%Y')
print(y)

How to sort lists of dictionaries according to values of ONE key type? [duplicate]

This question already has answers here:
How do I sort a list of dictionaries by a value of the dictionary?
(20 answers)
Closed 11 months ago.
I have the following list of dictionaries:
[{'title': 'Shrek the Musical', 'year': 2013, 'genres': ['Comedy', 'Family', 'Fantasy'], 'duration': 130, 'directors': ['Michael John Warren'], 'actors': ["Brian d'Arcy James", 'Sutton Foster', 'Christopher Sieber'], 'rating': 7.0},
{'title': 'Shrek Retold', 'year': 2018, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 90, 'directors': ['Grant Duffrin'], 'actors': ['Harry Antonucci', 'Russell Bailey'], 'rating': 7.5},
{'title': 'Shrek 2', 'year': 2004, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 93, 'directors': ['Andrew Adamson', 'Kelly Asbury'], 'actors': ['Mike Myers', 'Eddie Murphy'], 'rating': 7.2},
{'title': 'Shrek the Third', 'year': 2007, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 93, 'directors': ['Chris Miller', 'Raman Hui'], 'actors': ['Mike Myers', 'Eddie Murphy', 'Cameron Diaz', 'Antonio Banderas'], 'rating': 6.1},
{'title': 'Shrek Forever After', 'year': 2010, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 93, 'directors': ['Mike Mitchell'], 'actors': ['Mike Myers', 'Eddie Murphy', 'Cameron Diaz', 'Antonio Banderas'], 'rating': 6.3},
{'title': 'Shrek', 'year': 2001, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 90, 'directors': ['Andrew Adamson', 'Vicky Jenson'], 'actors': ['Mike Myers', 'Eddie Murphy'], 'rating': 7.8}]
I want to produce a list of movies sorted in increasing order of their year of release. That is, the sorting should just depend on one value, ignoring all other keys.
I tried using the sorted function, but I don't know how to specify that the dictionaries should be sorted based on a single value.
You can pass a key parameter to sorted() to tell it which key to sort on:
result = sorted(data, key=lambda x: x['year'])
print(result)
This outputs:
[{'title': 'Shrek', 'year': 2001, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 90, 'directors': ['Andrew Adamson', 'Vicky Jenson'], 'actors': ['Mike Myers', 'Eddie Murphy'], 'rating': 7.8},
{'title': 'Shrek 2', 'year': 2004, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 93, 'directors': ['Andrew Adamson', 'Kelly Asbury'], 'actors': ['Mike Myers', 'Eddie Murphy'], 'rating': 7.2},
{'title': 'Shrek the Third', 'year': 2007, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 93, 'directors': ['Chris Miller', 'Raman Hui'], 'actors': ['Mike Myers', 'Eddie Murphy', 'Cameron Diaz', 'Antonio Banderas'], 'rating': 6.1},
{'title': 'Shrek Forever After', 'year': 2010, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 93, 'directors': ['Mike Mitchell'], 'actors': ['Mike Myers', 'Eddie Murphy', 'Cameron Diaz', 'Antonio Banderas'], 'rating': 6.3},
{'title': 'Shrek the Musical', 'year': 2013, 'genres': ['Comedy', 'Family', 'Fantasy'], 'duration': 130, 'directors': ['Michael John Warren'], 'actors': ["Brian d'Arcy James", 'Sutton Foster', 'Christopher Sieber'], 'rating': 7.0},
{'title': 'Shrek Retold', 'year': 2018, 'genres': ['Animation', 'Adventure', 'Comedy'], 'duration': 90, 'directors': ['Grant Duffrin'], 'actors': ['Harry Antonucci', 'Russell Bailey'], 'rating': 7.5}]

How to do error-handling of JSON Parser Loop

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}

Categories

Resources