Exploiter une API WEB en Python
Mise en situation
Des échanges ont été interceptés entre acteurs malveillants appartenant à un groupe criminel.
L’interlocuteur de la personne que vous surveillez explique qu’il est actuellement dans une petite ville qui présente la particularité d’avoir un nom constitué uniquement de voyelles.
Il explique qu’il compte diffuser des archives zippées protégées par un mot de passe qui sera — comme à son habitude — le nom en majuscules de la commune où il se trouve actuellement suivi de sa population au dernier recensement, le tout codé en Base64.
Puisque les serveurs de Cloudflare sont hors service pour l’instant, vous ne pouvez pas accéder à votre I.A.. Vous décidez alors de trouver ce mot de passe à l’aide d’un script Python qui exploitera les données au format JSON mises à disposition par l’API
Web “Découpage administratif”
✎ Travail n° 1 Apport de connaissances
-
Consulter l’aide-mémoire JSON
pour en apprendre davantage sur ce format d’échange de données
-
Consulter l’aide-mémoire APIs Web
pour apprendre ce que cela représente
💻 Travail n° 2 Format JSON
Pour répondre au challenge, vous allez utiliser une API Web qui retourne les données au format JSON.
L’objectif de ce travail est de vous entraîner à accéder à ce genre de données en Python à partir d’un texte comportant des données météorologiques au format JSON.
🎯 Travail à faire :
-
On vous donne des données météo relevées à Marseille au format JSON sous forme de chaîne de caractères Python :
Données météo au format JSON dans une chaîne Python :
json_str = """ { "coord": { "lon": 5.5, "lat": 43.3333 }, "weather": [ { "id": 501, "main": "Rain", "description": "pluie modérée", "icon": "10d" } ], "base": "stations", "main": { "temp": 7.9, "feels_like": 5.23, "temp_min": 7.58, "temp_max": 8.06, "pressure": 1003, "humidity": 92, "sea_level": 1003, "grnd_level": 983 }, "visibility": 10000, "wind": { "speed": 4.4, "deg": 97, "gust": 10.03 }, "rain": { "1h": 2.37 }, "clouds": { "all": 100 }, "dt": 1770560663, "sys": { "type": 2, "id": 80238, "country": "FR", "sunrise": 1770533160, "sunset": 1770569906 }, "timezone": 3600, "id": 2995468, "name": "Marseille", "cod": 200 } """À partir de l’exemple fourni plus bas, compléter le code suivant pour extraire les informations météo principales :
Source à compléterimport json # 1 - Définition du texte multi-lignes avec données au format JSON ❓ # 2 - Chargement des données JSON ❓ # 3 - Extraction/Affichage des données météo principales print(f"Météo à : {❓} ({❓})") print(f"Température : {❓}°C") print(f"Vent : {❓} m/s, direction {❓}°") print(f"Observation : {❓}")Résultat attendu :Météo à : Marseille (FR) Température : 7.9°C Vent : 4.4 m/s, direction 97° Observation : pluie modéréeExemple extraction données JSON en Python :import json # 1 - On définit un texte multi-lignes (-> délimiteurs : """…""") # avec données au format JSON json_sample = """ { "device": "ESP32-S3", "sensors": [ { "type": "temperature", "val": 24.5 }, { "type": "humidity", "val": 45 } ] } """ # 2 - On charge le texte/document JSON dans une variable Python (dict) sample = json.loads(json_sample) # 3 - On accède, via un dictionnaire, à la propriété "device" # pour afficher le nom du dispositif print(f"Device : {sample["device"]}") # 4 - On accède, via une liste puis dictionnaire Python, à la # propriété "type" du 2ème élément (index 1) du tableau # JSON "sensors" de la propriété "sensors" pour afficher # le type de capteur print(f"Capteur n°2 : {sample["sensors"][1]["type"]}") # Affiche : # Device : ESP32-S3 # Capteur n°2 : humidityLorsqu’on charge un document JSON dans une variable Python avec la fonction
load()du modulejson…
… les objets JSON sont convertis en dictionnaires Python (⇒ accès aux éléments par clé)
… les tableaux JSON sont convertis en listes Python (⇒ accès aux éléments par indice) -
Compléter le script pour qu’il affiche la date du relevé météo sachant que l’information se trouve dans l’élément JSON dont la clé est “dt” sous forme de timestamp Unix, c’est-à-dire en nombre de secondes écoulées depuis le 1er janvier 1970.
Exemple de résultat attendu :Météo à : Marseille (FR) Date : 2026-02-08 15:24:23 Température : 7.9°C Vent : 4.4 m/s, direction 97° Observation : pluie modéréeLe module
datetimede Python dispose de 2 fonctionsfromtimestamp(timestamp)qui permettent la conversion d’un timestamp en date+heure ou uniquement en date.Selon ce qu’on désire, on pourra utiliser les syntaxes suivantes :
# Calculer date+heure depuis un timestamp >>> from datetime import datetime as dt >>> date_et_heure = dt.fromtimestamp(2_147_483_647) (1) >>> print(f"{date_et_heure}") 2038-01-19 04:14:07 # Calculer date seule depuis un timestamp >>> from datetime import date as d >>> date_seule = d.fromtimestamp(2_147_483_647) (1) >>> print(f"{date_seule}") 2038-01-191 Timestamp du bug prévisionnel de l’an 2038 : il correspond à la valeur maximale d’un entier signé sur 32 bits i.e. 0x7fffffff
💻 Travail n° 3 API Web
L’objectif de ce travail est de vous apprendre à interroger une API Web en Python.
Ceci est facilité par l’utilisation du module requests de Python comme l’illustre l’exmple suivant :
# import du module permettant de faire des requêtes HTTP
import requests
# On définit l'url de base de l'endpoint de l'API Web
base_url = "https://api.open-meteo.com/v1/forecast"
# On définit les paramètres de la chaîne de requête
# qui complète l'url de base
query = {
# latitude de l'Isle sur la Sorgue
"latitude" : 43.91,
# longitude de l'Isle sur la Sorgue
"longitude" : 5.06,
# données météo désirée : t° ressentie
"hourly" : "apparent_temperature",
# date de début
"start_date" : "2026-03-10",
# date de fin
"end_date" : "2026-03-10"
}
# Exécution de la requête
resp = requests.get(url=base_url, params=query)
# SI la requête a échoué ALORS
if resp.status_code != 200:
# On affiche un message d'erreur
print(f"Erreur HTTP {resp.status_code} : {resp.reason}")
# SINON
else:
# On charge les données JSON retournées dans une variable JSON
# (list ou dict selon le cas)
data = resp.json()
# On traite/affiche les données
print("T°C relevées à l'Isle sur la Sorgue le 10/03/2026")
for hour, temp in zip(data["hourly"]["time"], data["hourly"]["apparent_temperature"]) : (1)
print(
f"{hour} : {temp}°C"
)
# Affiche :
# T°C relevées à l'Isle sur la Sorgue le 10/03/2026
# 2026-03-10T00:00 : 9.3°C
# 2026-03-10T01:00 : 9.6°C
# 2026-03-10T02:00 : 10.0°C
# 2026-03-10T03:00 : 10.3°C
# 2026-03-10T04:00 : 10.1°C
# 2026-03-10T05:00 : 9.8°C
# 2026-03-10T06:00 : 9.5°C
# 2026-03-10T07:00 : 10.2°C
# […]
# 2026-03-10T21:00 : 7.4°C
# 2026-03-10T22:00 : 6.9°C
# 2026-03-10T23:00 : 6.5°C
| 1 | Noter la façon dont on peut récupérer simultanément 2 éléments de 2 listes à chaque itération avec la fonction zip() |
🎯 Travail à faire :
-
Se rendre sur la page de documentation de l’API JokeAPI
-
Depuis l’interface web de ce l’API, construire l’URL pour obtenir 5 blagues su le thème de la programmation au format JSON en anglais en “black listant” toutes les sujets criticables.
-
Transposer cette requête dans un script Python et afficher les 5 blagues retournées
Blague n°1 :
> Question : Why do programmers confuse Halloween and Christmas?
> Réponse : Because Oct 31 = Dec 25
------------------------------
Blague n°2 :
> A programmer puts two glasses on his bedside table before going to sleep.
A full one, in case he gets thirsty, and an empty one, in case he doesn't.
------------------------------
Blague n°3 :
> Judge: "I sentence you to the maximum punishment..."
Me (thinking): "Please be death, please be death..."
Judge: "Learn Java!"
Me: "Damn."
------------------------------
Blague n°4 :
> Question : How do you generate a random string?
> Réponse : Put a Windows user in front of Vim and tell them to exit.
------------------------------
Blague n°5 :
> Question : How can you tell an extroverted programmer?
> Réponse : He looks at YOUR shoes when he's talking.
------------------------------
💻 Travail n° 4 Consolidation
|
Ce travail est un complément indépendant du travail précédent. L’objectif est d’exploiter en Python une autre API Web. |
🕮 Mise en situation :
On désire coder un script Python qui permet d’afficher l’indice de qualité d’air (→ iqa) relevé dans une commune.
L’indice de qualité d’air qualifie l’état de l’air selon 6 classes :
-
Bon
-
Moyen
-
Dégradé
-
Mauvais
-
Très mauvais
-
Extrêmement mauvais
Il est calculé quotidiennement, à partir de concentrations de 5 polluants réglementés, aux effets sanitaires avérés :
-
les particules fines dont le diamètre est inférieur à 10 micromètres (→ PM10),
-
les particules fines dont le diamètre est inférieur à 2.5 micromètres (→ PM2.5),
-
le dioxyde d’azote (→ NO2),
-
l’ozone (→ O3),
-
le dioxyde de soufre (→ SO2).
L’indice de qualité d’air correspond alors au plus dégradé des sous-indices calculés pour chacun de ces 5 polluants.
Dans la région Provence/Alpes/côte d’Azur l’association agréée de surveillance de qualité d’air (→ AASQA) est AtmoSud.
Chaque jour AtmoSud diffuse un bulletin des indices calculés pour quatre échéances : de la veille (J-1) au sur-lendemain (J+2).
Ces bulletins sont disponibles depuis l’API Nouvel Indice de la Qualité de l’Air (IQA)
🎯 Travail à faire :
-
Depuis l’interface web de l’API Nouvel Indice de la Qualité de l’Air (IQA), construire et tester l’URL qui permet de collecter …
…le bulletin journalier
…d’aujourd’hui
…pour la commune de l’Isle sur la Sorgue (code INSEE : 84054)
…qui donne les valeurs (1..6) et qualificatifs (Bon… Extrêmement mauvais)
…de tous les indices (iqa, no2, o3, pm10, pm2.5, so2)
-
Coder un script Python qui affiche le bulletin du jour.
Exemple de résultat attendu--- Bulletin d'indice de qualité d'air à l'Isle sur la Sorgue le 03/03/2026 --- IQA : 2 (Moyen) > Particules majoritaires : o3, pm2.5 > Détails des particules : > PM10 : 1 (Bon) > PM2.5 : 2 (Moyen) > O3 : 2 (Moyen) > NO2 : 1 (Bon) > SO2 : 1 (Bon)
💻 Travail n° 5 Résolution du challenge initial
Vous avez désormais tous les outils en main pour trouver le mot de passe utilisé par le groupe criminel pour protéger les archives .zip échangées (Rappel : c’est le nom en majuscules d’une petite ville constitué uniquement de voyelles suivi de son nombre d’habitants, le tout codé en Base64)
🎯 Travail à faire :
-
Depuis un script Python, récupérer la liste des communes françaises depuis l’API Web “Découpage administratif > Communes”
-
Dans les données JSON retournées, filtrer celles ne comportant que des voyelles (y compris le ‘y’ et les voyelles accentuées) et dont la population est comprise entre 3 000 et 20 000 habitants (→ définition d’une “petite ville”)
-
Importer le module
base64, parcourir sa documentationpuis coder en Base64 l’ensemble nom de la commune en majuscules/population² pour obtenir le mot de passe.
Ex. pour Paris avec 2103778 habitants :
PARIS2103778⇒UEFSSVMyMTAzNzc4en Base64Résultat attendu
RVU2NDk5
La fonction d’encodage en Base64 de Python attend un objet de type
bytesen paramètre (le contenu à encoder).Pour convertir une chaîne de caractères (→ type
str) enbytes, on utilise la fonctionencodeen précisant l’encodage de départ (UTF8 par défaut dans Python depuis sa version 3).Exemple :>>> "Où est le temps béni où l'essence était à 1€ ?".encode("utf8") b"O\xc3\xb9 est le temps b\xc3\xa9ni o\xc3\xb9 l'essence \xc3\xa9tait \xc 3\xa0 1\xe2\x82\xac ?" (1)1 Les caractères accentués/spéciaux (‘ù’, ‘é’,‘€’) sont transformés en séquences d’octets correspondant à leur codage dans l’alphabet UTF-8.
🞄 🞄 🞄