Werken met JSON

Werken met JSON

19 februari 2024
Erwin Matijsen
Geplaatst in Tutorial
Onderdeel van Werken met JSON


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.

output
1950: 10.026.773
1951: 10.200.280
...
2022: 17.590.672
2023: 17.811.291

Voordat je begint

Maak een nieuw project aan, met een nieuwe virtual environment. Installeer daarin de benodigde packages:

shell
cd projects
mkdir cbs_json && cd cbs_json
python -m venv .venv
source .venv/bin/activate  # .venv\Scripts\activate.bat voor Windows
python -m pip install requests
python -m pip freeze > 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.

In onderstaand voorbeeld van de Wikipediapagina over JSON, zie je een lijst met twee elementen:

json
[
   {
      "Naam":"JSON",
      "Type":"Gegevensuitwisselingsformaat",
      "isProgrammeertaal":false,
      "Zie ook":[
         "XML",
         "ASN.1"
      ]
   },
   {
      "Naam":"JavaScript",
      "Type":"Programmeertaal",
      "isProgrammeertaal":true,
      "Jaar":1995
   }
]

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
import json
import requests

URL = "https://opendata.cbs.nl/ODataApi/odata/85496NED/TypedDataSet"

def get_data(refresh=True):
    if not refresh:
        try:
            with open("data.json") as f:
                data = json.load(f)
        except FileNotFoundError:
            print("Bestand niet gevonden, downloaden")

            # Roep deze functie aan, met `refresh=True`
            return get_data(refresh=True)
    else:
        response = requests.get(URL)

        # Als de HTTP-code 400 of hoger is, zal er een uitzondering worden opgeworpen
        response.raise_for_status()
        data = response.json()

        # Sla bestand op
        with open("data.json", "w") as f:
            json.dump(data, f, indent=2)

    return data

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:

Een deel van het JSON-bestand van het CBS

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
# ...

def get_total_population():

    # Open het bestand
    with open("data.json") as f:
        data = json.load(f)  # data is nu een Python object (dict)

    # Bereid een lege lijst voor
    result = []

    # Loop door de rijen in de data
    for item in data["value"]:
        year = item["Perioden"].split("JJ")[0]  # Schoon het jaartal op
        value = item["TotaleBevolking_1"]

        # Voeg het jaartal en de waarde toe aan de lijst als een tuple
        result.append((year, value))

    return result

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
import locale
locale.setlocale(locale.LC_ALL, "nl_NL.utf8")
# ...

if __name__ == "__main__":
    data = get_data(refresh=False)  # Zet op False om niet steeds te downloaden
    total_population = get_total_population()

    for year, value in total_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:

Een deel van het resultaat

Conclusie

Werken met JSON in Python is eenvoudig te doen met de json package, 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.

Lees alle tutorials in deze reeks: Werken met JSON

Over de auteur


Erwin Matijsen

Erwin Matijsen

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.



Contact

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.