Faire des requêtes HTTP en Python avec requests
Faire une requête HTTP en Python consiste à dialoguer avec un serveur web : récupérer une page, interroger une API, envoyer des données. La bibliothèque de référence pour cela est requests, réputée pour sa simplicité. Ce guide la couvre de façon exhaustive : requêtes GET et POST, passage de paramètres, headers, envoi et réception de JSON, authentification, gestion des erreurs et des timeouts, sessions persistantes, téléchargement de fichiers, et enfin l’alternative moderne httpx.
Installer requests
requests ne fait pas partie de la bibliothèque standard : on l’installe avec pip.
pip install requests
Une fois installée, on l’importe simplement :
import requests
La requête GET de base
Une requête GET récupère des données. requests.get(url) renvoie un objet Response riche d’informations.
import requests
reponse = requests.get("https://api.github.com")
print(reponse.status_code) # 200 si tout va bien
print(reponse.headers["Content-Type"]) # application/json; ...
print(reponse.text[:80]) # les premiers caractères du corps
Les attributs les plus utiles de l’objet Response :
status_code: le code HTTP (200, 404, 500…)text: le corps de la réponse sous forme de chaînecontent: le corps sous forme d’octets (pour les fichiers binaires)headers: un dictionnaire des en-têtes de réponseurl: l’URL finale (après d’éventuelles redirections)
Passer des paramètres d’URL
Plutôt que de construire l’URL à la main avec des ? et des &, on passe un dictionnaire à l’argument params. requests s’occupe de l’encodage.
import requests
parametres = {"q": "python", "page": 2}
reponse = requests.get("https://httpbin.org/get", params=parametres)
print(reponse.url)
# https://httpbin.org/get?q=python&page=2
C’est plus sûr : les caractères spéciaux (espaces, accents) sont automatiquement échappés.
Recevoir du JSON
La plupart des API renvoient du JSON. La méthode .json() de l’objet Response le convertit directement en dictionnaire ou liste Python.
import requests
reponse = requests.get("https://api.github.com/users/python")
donnees = reponse.json()
print(donnees["name"]) # Python
print(donnees["public_repos"]) # nombre de dépôts publics
Inutile d’importer le module json : requests gère la conversion. Attention toutefois, .json() lève une exception si le corps n’est pas du JSON valide.
La requête POST
Une requête POST envoie des données au serveur, typiquement pour créer une ressource ou soumettre un formulaire.
Envoyer des données de formulaire
Avec l’argument data, les données sont envoyées au format formulaire (application/x-www-form-urlencoded).
import requests
formulaire = {"nom": "Léa", "email": "[email protected]"}
reponse = requests.post("https://httpbin.org/post", data=formulaire)
print(reponse.json()["form"])
# {'email': '[email protected]', 'nom': 'Léa'}
Envoyer du JSON
Pour envoyer un corps JSON (le cas le plus courant avec les API REST), on utilise l’argument json. requests sérialise le dictionnaire et ajoute le bon en-tête Content-Type.
import requests
charge = {"titre": "Mon article", "publie": True}
reponse = requests.post("https://httpbin.org/post", json=charge)
print(reponse.json()["json"])
# {'publie': True, 'titre': 'Mon article'}
Pour tout savoir sur la conception de ces API, consultez notre guide de l’API REST.
Personnaliser les headers
On passe un dictionnaire à l’argument headers, par exemple pour définir un User-Agent ou un jeton d’API.
import requests
entetes = {
"User-Agent": "MonApp/1.0",
"Accept": "application/json",
}
reponse = requests.get("https://httpbin.org/headers", headers=entetes)
print(reponse.json()["headers"]["User-Agent"]) # MonApp/1.0
L’authentification
requests prend en charge plusieurs schémas d’authentification.
Authentification basique
On passe un tuple (utilisateur, mot_de_passe) à l’argument auth.
import requests
reponse = requests.get(
"https://httpbin.org/basic-auth/lea/secret",
auth=("lea", "secret"),
)
print(reponse.status_code) # 200
Jeton Bearer (API modernes)
Le plus fréquent aujourd’hui : un jeton placé dans l’en-tête Authorization.
import requests
jeton = "abc123xyz"
entetes = {"Authorization": f"Bearer {jeton}"}
reponse = requests.get("https://httpbin.org/bearer", headers=entetes)
print(reponse.json()) # {'authenticated': True, 'token': 'abc123xyz'}
Gérer les erreurs et les timeouts
Une requête peut échouer : serveur injoignable, délai dépassé, code d’erreur HTTP. Un code robuste anticipe ces cas.
Toujours définir un timeout
Sans timeout, une requête peut se bloquer indéfiniment. Définissez-en toujours un.
import requests
try:
reponse = requests.get("https://httpbin.org/delay/10", timeout=3)
except requests.exceptions.Timeout:
print("La requête a dépassé le délai de 3 secondes")
Vérifier le code de statut
raise_for_status() lève une exception si le code indique une erreur (4xx ou 5xx).
import requests
try:
reponse = requests.get("https://httpbin.org/status/404", timeout=5)
reponse.raise_for_status()
donnees = reponse.json()
except requests.exceptions.HTTPError as err:
print("Erreur HTTP :", err)
except requests.exceptions.RequestException as err:
print("Erreur réseau :", err)
RequestException est la classe mère de toutes les exceptions de requests : l’attraper couvre timeouts, erreurs DNS, problèmes de connexion, etc.
Les sessions persistantes
Un objet Session réutilise la connexion TCP et conserve les cookies et en-têtes entre les requêtes. C’est plus rapide et plus pratique dès qu’on enchaîne plusieurs appels au même serveur.
import requests
with requests.Session() as session:
session.headers.update({"Authorization": "Bearer abc123"})
# Les deux requêtes partagent en-têtes et cookies
r1 = session.get("https://httpbin.org/cookies/set/session/actif")
r2 = session.get("https://httpbin.org/cookies")
print(r2.json()) # {'cookies': {'session': 'actif'}}
Le bloc with garantit la fermeture propre de la session à la fin.
Télécharger un fichier
Pour un fichier volumineux, on active le mode stream=True et on écrit le contenu par blocs afin de ne pas tout charger en mémoire.
import requests
url = "https://httpbin.org/image/png"
with requests.get(url, stream=True, timeout=10) as reponse:
reponse.raise_for_status()
with open("image.png", "wb") as fichier:
for bloc in reponse.iter_content(chunk_size=8192):
fichier.write(bloc)
print("Téléchargement terminé")
iter_content renvoie les données par morceaux de 8 Ko, ce qui permet de télécharger des fichiers de plusieurs gigaoctets sans saturer la RAM.
L’alternative moderne : httpx
httpx est une bibliothèque plus récente, dont l’API est presque identique à celle de requests, mais qui ajoute le support de HTTP/2 et surtout de l’asynchrone (async/await).
pip install httpx
En mode synchrone, la transition est immédiate :
import httpx
reponse = httpx.get("https://api.github.com", timeout=5)
print(reponse.status_code)
print(reponse.json()["current_user_url"])
Et en mode asynchrone, pour lancer de nombreuses requêtes en parallèle :
import asyncio
import httpx
async def recuperer(url):
async with httpx.AsyncClient() as client:
reponse = await client.get(url, timeout=5)
return reponse.status_code
print(asyncio.run(recuperer("https://api.github.com")))
Retenez la règle simple : requests reste parfait pour du code synchrone classique ; passez à httpx si vous avez besoin d’asynchrone ou de HTTP/2.
Conclusion
Avec requests, interroger le web tient en quelques lignes : get et post pour l’essentiel, params et json pour les données, headers et auth pour l’authentification. N’oubliez jamais les deux réflexes de robustesse : un timeout sur chaque requête et un raise_for_status() pour détecter les erreurs. Pour des besoins d’asynchrone ou de performance, httpx prend le relais avec une API familière.