In Geautomatiseerd gegevens downloaden heb je geleerd hoe je met requests data kunt ophalen van een URL. In Een website scrapen met Beautiful Soup leerde je hoe je gegevens van een website zelf kunt verwerken met behulp van Beautiful Soup. In het eerste geval kwam de data als tekstbestand, in het tweede geval als HTML. Maar wat als de data die je wilt ophalen in JSON-formaat is? In deze tutorial leer je hoe je met JSON-data kunt werken in Python.
Het project
Het Centraal Bureau voor de Statistiek (CBS) maakt alle gegevens niet alleen via de website beschikbaar, maar ook via een API (https://opendata.cbs.nl/statline/portal.html). In dit project download je de bevolkingsgegevens, sla je ze op in data.json en verwerk je ze vervolgens om per jaar het totale bevolkingsaantal van Nederland te tonen.
Maak een nieuw project aan, met een nieuwe virtual environment. Installeer daarin de benodigde packages:
shell
cdprojects
mkdircbs_json&&cdcbs_json
python-mvenv.venv
source.venv/bin/activate# .venv\Scripts\activate.bat voor Windows
python-mpipinstallrequests
python-mpipfreeze>requirements.txt
Alle code van dit project is ook op Github te bekijken. Omdat deze respository in meerdere tutorials wordt gebruikt, zijn er meerdere branches. Zorg dat je voor deze tutorial versie-1 kiest.
Wat is JSON?
JSON staat voor JavaScript Object Notation. Het is een lichtgewicht dataformaat dat makkelijk voor mensen te lezen en schrijven is en makkelijk voor machines om te genereren en analyseren. Het wordt veel gebruikt om gegevens tussen programma's uit te wisselen, met name via internet. Veel API's zullen dan ook JSON teruggeven.
Zoals je ziet, lijkt een JSON-object erg op een dict in Python. Net als een dict wordt een JSON-object omsloten door curly braces ({}) en bestaat het uit sleutel-waarden paren. Er zijn wel een aantal beperkingen. Als waarde zijn alleen de volgende datatypes toegestaan:
Tekst
Getallen
true, false en null
Lijsten (arrays, [])
Andere JSON-objecten ({})
De sleutels zijn altijd tekst.
JSON in Python
Python heeft een ingebouwde bibliotheek genaamd json voor het werken met JSON-data. Er zijn twee manieren om dit te doen: van en naar strings en van en naar bestanden:
Van Python naar een JSON-string: json.dumps()
Van Python naar een JSON-bestand: json.dump()
Van een JSON-string naar Python: json.loads()
Van een JSON-bestand naar Python: json.load()
Van Python naar JSON noem je serialiseren. Van JSON naar Python noem je deserialiseren.
Verder met het project
Nu je de basis van JSON begrijpt, kun je verder met het project.
Gegevens downloaden
Stap 1 is het downloaden van de gegevens. Doe dit met requests. Maak in main.py een functie aan om de gegevens te downloaden. Deze functie is vrijwel gelijk aan de get_html functie uit Een website scrapen met Beautiful Soup.
main.py
importjsonimportrequestsURL="https://opendata.cbs.nl/ODataApi/odata/85496NED/TypedDataSet"defget_data(refresh=True):ifnotrefresh:try:withopen("data.json")asf:data=json.load(f)exceptFileNotFoundError:print("Bestand niet gevonden, downloaden")# Roep deze functie aan, met `refresh=True`returnget_data(refresh=True)else:response=requests.get(URL)# Als de HTTP-code 400 of hoger is, zal er een uitzondering worden opgeworpenresponse.raise_for_status()data=response.json()# Sla bestand opwithopen("data.json","w")asf:json.dump(data,f,indent=2)returndata
De functie zorgt ervoor dat je het bestand opslaat als data.json, zodat je tijdens het ontwikkelen niet steeds de URL hoeft aan te roepen. Wil je de gegevens verversen, roep dan get_data aan met refresh=True.
De gearceerde regels laten zien je waar je in de code met json werkt. Als je data.json wilt inladen, gebruik je json.load(). Haal je de gegevens eerst op van het CBS met requests, dan gebruik je data = response.json(). Dit is een hulpmiddel van requests om inkomende json om te zetten naar een Python-object. Sla je het bestand vervolgens op, dan gebruik je json.dump(data, f, indent=2). Dus: je serialiseert het Python-object data naar bestand f. Om het leesbaar te maken gebruik je een indentatie van 2.
Let op
Voor de oplettende lezer: met data = response.json() zet je JSON om naar een dict, en verderop zet je die dict weer om naar json met json.dump() om het naar het bestand te schrijven. Dat is wat omslachtig natuurlijk! Een kortere manier is om de json direct naar het bestand te schrijven, en dat kan ook.
In dit geval wilde ik graag de json.dump() en de response.json() methodes laten zien.
Roep de functie eens aan en inspecteer het opgeslagen bestand:
main.py
# ...if__name__=="__main__":data=get_data()
Het resultaat ziet er ongeveer zo uit:
Alle gegevens zijn te vinden in de sleutel value, welke een lijst bevat met JSON-objecten. Elk jaar is één object. Voor dit project heb je uit die objecten alleen de sleutels Perioden en TotaleBevolking_1 nodig.
Gegevens verwerken
Nu je de gegevens in data.json beschikbaar hebt, kun je datgene eruit halen wat je nodig hebt. Maak een functie get_total_population aan in main.py.
main.py
# ...defget_total_population():# Open het bestandwithopen("data.json")asf:data=json.load(f)# data is nu een Python object (dict)# Bereid een lege lijst voorresult=[]# Loop door de rijen in de dataforitemindata["value"]:year=item["Perioden"].split("JJ")[0]# Schoon het jaartal opvalue=item["TotaleBevolking_1"]# Voeg het jaartal en de waarde toe aan de lijst als een tupleresult.append((year,value))returnresult
Je begint met het inladen van het JSON-bestand, wat zal resulteren in een dict. Vervolgens loop je over alle items in de data["value"] lijst om er het jaar (Perioden) en de bevolkingsomvang (TotaleBevolking_1) uit te halen. Schoon het jaar op, zodat je in plaats van "1950JJ00" netjes "1950" krijgt.
Roep het geheel tot slot aan en druk de resultaten af:
main.py
importlocalelocale.setlocale(locale.LC_ALL,"nl_NL.utf8")# ...if__name__=="__main__":data=get_data(refresh=False)# Zet op False om niet steeds te downloadentotal_population=get_total_population()foryear,valueintotal_population:print(f"{year}: {value:n}")
Bovenaan je bestand stel je locale in, zodat je op de laatste regel {value:n} kunt gebruiken om duizendtallen netjes te scheiden door een punt.
Het resultaat:
Conclusie
Werken met JSON in Python is eenvoudig te doen met de jsonpackage, beschikbaar in de standaard bibliotheek. Het omzetten van Python-objecten naar JSON doe je met dump of dumps. Het omzetten van JSON naar Python doe je met load of loads. Vaak zul je JSON ophalen via een API. Gebruik je hiervoor requests, dan kun je response.json() gebruiken om de inkomende data te converteren naar een Python-object.
Alle code van dit project is ook op Github te bekijken. Omdat deze respository in meerdere tutorials wordt gebruikt, zijn er meerdere branches. Zorg dat je voor deze tutorial versie-1 kiest.
Erwin is de oprichter van python-cursus.nl. In allerlei rollen heeft hij Python ingezet, van het eenvoudiger maken van zijn werk tot het opleveren van complete (web)applicaties. Met vrouw en kinderen woont hij in Havelte (Drenthe), midden in de prachtige natuur. Daar wandelt hij graag, zeker ook omdat de beste ingevingen tijdens een wandeling - weg van de computer - lijken te komen.
Vragen, opmerkingen?
Heb je vragen, opmerkingen, suggesties of tips naar aanleiding van deze blog?
Neem dan contact met ons op, of laat het weten via
Mastodon of
LinkedIN.