Requêtes HTTP et API en Python avec requests

Appelez une API web depuis Python : récupérez une URL en GET, passez des paramètres de requête, envoyez du JSON en POST, lisez l’objet réponse, et gérez erreurs et timeouts de façon robuste — avec de vraies réponses capturées.

Appelez n’importe quelle API web depuis Python avec la bibliothèque requests. Envoyez une requête GET, laissez requests encoder vos paramètres de requête, envoyez du JSON en POST, et lisez la réponse — code de statut, en-têtes, et le corps JSON avec .json(). Apprenez le jugement qu’un appel en une ligne saute : définissez toujours un timeout, et vérifiez toujours le statut avec raise_for_status() avant de faire confiance au corps. Chaque exemple est du vrai code avec de vraies réponses capturées d’une API publique stable — copiez chaque bloc et exécutez-le dans votre terminal.

Date de publication

18 juillet 2026

Modifié

18 juillet 2026

AstucePoints clés
  • requests est la façon standard de dialoguer avec une API web depuis Python — une fonction par méthode HTTP. Une requête HTTP est un message que votre programme envoie à un serveur web ; requests.get(url) envoie une requête GET (récupérer des données), requests.post(url, json=...) envoie une requête POST (envoyer des données). Installez-la une fois avec pip install requests.
  • Chaque appel renvoie un objet réponse — lisez-le, ne devinez pas. La réponse porte le code de statut (r.status_code200 signifie OK, 404 Not Found), le corps parsé (r.json()), le texte brut (r.text), et les en-têtes (r.headers).
  • Passez les paramètres de requête sous forme de dict — ne construisez jamais l’URL à la main. Donnez à requests.get(url, params={...}) un dictionnaire et requests l’encode correctement (espaces, &, =) ; construire la chaîne de requête à la main, c’est de là que viennent les bugs.
  • Définissez toujours un timeout — une requête sans timeout peut se bloquer indéfiniment. requests.get(url, timeout=10) abandonne après 10 secondes au lieu de figer votre script quand un serveur ne répond jamais.
  • Vérifiez le statut avant de faire confiance au corps — c’est le jugement qu’une réponse d’IA en une ligne saute. Appelez r.raise_for_status() (elle lève sur un 4xx/5xx) avant r.json(), pour ne pas parser une page d’erreur comme si c’était vos données.

Introduction

Vous avez besoin de données qui vivent sur un serveur web — les derniers taux de change, la liste de vos dépôts, des enregistrements d’un service interne. Le service expose une API web (application programming interface) : un ensemble d’URL qu’un programme peut appeler pour lire ou envoyer des données, au lieu qu’un humain clique sur un site web. La question est de savoir comment l’appeler depuis Python et récupérer proprement les données.

requests est la bibliothèque de fait pour cela. Elle transforme « récupère cette URL » en une seule ligne lisible, vous rend un objet réponse que vous pouvez inspecter, et encode les parties délicates (chaînes de requête, corps JSON, en-têtes) pour que vous n’ayez pas à le faire. Cette leçon construit le vrai modèle dans l’ordre où vous l’utiliserez : installer et envoyer votre premier GET, lire l’objet réponse, passer des paramètres de requête, envoyer des données en POST, et — la partie qui distingue un script qui fonctionne d’un script qui fonctionne de façon fiable — définir un timeout et vérifier le statut avant de faire confiance au corps.

Contrairement à la plupart du Python que vous écrivez, requests dialogue avec un serveur en direct sur le réseau, il ne s’exécute donc pas dans le bac à sable du navigateur — copiez chaque bloc dans un script ou votre shell Python et exécutez-le dans votre terminal. Les exemples appellent jsonplaceholder.typicode.com, une fausse API gratuite et stable prévue exactement pour cela : elle renvoie des données d’exemple fixes, si bien que les réponses montrées ci-dessous sont celles que vous obtiendrez aussi. Installez la bibliothèque une fois (dans l’environnement virtuel de votre projet — voir Environnements virtuels et dépendances en Python) :

pip install requests

Votre première requête : récupérer une ressource avec GET

Une requête GET demande à un serveur de renvoyer les données situées à une URL — la chose la plus courante que vous ferez. Pointez requests.get() vers un endpoint (une URL sur laquelle l’API répond) et elle renvoie un objet réponse contenant tout ce que le serveur a renvoyé :

import requests

r = requests.get("https://jsonplaceholder.typicode.com/todos/1")
print(r.status_code)
print(r.json())
200
{'userId': 1, 'id': 1, 'title': 'delectus aut autem', 'completed': False}

Deux lignes portent tout le résultat. r.status_code est le code de statut HTTP — un nombre que le serveur renvoie pour indiquer comment s’est passée la requête ; 200 signifie OK. r.json() parse le corps de la réponse depuis le JSON (JavaScript Object Notation — le format texte que renvoient la plupart des API, une imbrication de paires clé/valeur et de listes) en un dict Python natif que vous pouvez indexer comme n’importe quel autre : r.json()["title"] donne 'delectus aut autem'. Voilà la boucle — appeler l’endpoint, vérifier le statut, lire le corps.

L’objet réponse

requests.get() ne renvoie jamais « les données » directement — elle renvoie la réponse, et les données sont l’un de ses attributs. Connaître ce que contient cet objet, c’est l’essentiel de la bibliothèque. Voici ceux que vous utiliserez :

Attribut / méthode Ce qu’il vous donne Exemple de valeur
r.status_code Le code de statut HTTP, sous forme d’int200 OK, 201 Created, 404 Not Found 200
r.ok True quand le statut est inférieur à 400 (c.-à-d. pas une erreur) True
r.json() Le corps de la réponse parsé depuis le JSON en un dict ou une list Python {'id': 1, ...}
r.text Le corps brut de la réponse sous forme de str (avant tout parsing JSON) '{"id": 1, ...}'
r.content Le corps brut sous forme de bytes — pour les charges binaires comme les images ou les fichiers b'{"id": 1, ...}'
r.headers Les en-têtes de la réponse, sous forme d’objet façon dict insensible à la casse {'Content-Type': 'application/json; charset=utf-8', ...}
r.url L’URL finale réellement demandée (après encodage + redirections) 'https://.../todos/1'
r.raise_for_status() Lève HTTPError si le statut est 4xx/5xx ; sinon renvoie None lève sur 404

Un en-tête (header) est une ligne de métadonnées que le serveur envoie à côté du corps — le plus utile étant Content-Type, qui vous indique que le corps est du JSON (application/json). Utilisez r.json() quand l’API renvoie du JSON (presque toujours), r.text quand elle renvoie du texte brut ou du HTML, et r.content pour les téléchargements binaires. L’API de réponse complète est dans le guide de démarrage de requests et la référence de l’API.

Paramètres de requête : passez un dict, laissez requests l’encoder

La plupart des endpoints acceptent des paramètres de requête (query parameters) — les filtres ?key=value&key=value après l’URL — pour restreindre ce qu’ils renvoient. L’erreur est de construire cette chaîne à la main : les espaces, & et les caractères non-ASCII ont tous besoin d’un encodage-pourcent, et un seul mauvais caractère casse silencieusement la requête. Passez plutôt un dict à params= et requests l’encode pour vous.

Voici ce que fait cet encodage, montré sans appel réseau pour que vous puissiez voir le résultat. requests construit l’URL finale à partir de votre dict :

import requests

req = requests.Request(
    "GET",
    "https://api.example.com/search",
    params={"q": "python requests", "page": 2, "sort": "new"},
)
print(req.prepare().url)
https://api.example.com/search?q=python+requests&page=2&sort=new

Remarquez que l’espace dans "python requests" est devenu +, que les trois clés ont été jointes par &, et que l’entier 2 a été rendu sous forme de texte — le tout correctement, rien de tout cela n’est votre problème. Dans le code de tous les jours, vous passez params= directement à requests.get() :

r = requests.get(
    "https://jsonplaceholder.typicode.com/todos",
    params={"userId": 1},
)
print(r.status_code)
print(len(r.json()))
200
20

L’API a renvoyé chaque todo appartenant à l’utilisateur 1 — une list de 20 éléments, donc len(r.json()) vaut 20. Ajoutez une autre clé au dict et vous avez ajouté un autre filtre, sans aucune manipulation de chaîne. La règle vaut pour toute API : donnez un dict à requests, jamais une chaîne de requête construite à la main. Le passage de paramètres est couvert dans la section « passing parameters in URLs » du guide de démarrage.

Envoyer des données avec POST

Une requête POST envoie des données vers le serveur — typiquement pour créer quelque chose. Passez votre charge utile à json= et requests sérialise le dict en un corps JSON et définit pour vous l’en-tête Content-Type: application/json :

r = requests.post(
    "https://jsonplaceholder.typicode.com/posts",
    json={"title": "hello", "body": "world", "userId": 1},
)
print(r.status_code)
print(r.json())
201
{'title': 'hello', 'body': 'world', 'userId': 1, 'id': 101}

Le statut 201 signifie « Created » — la ressource a été créée — et l’API renvoie en écho ce qu’elle a stocké, désormais avec un id attribué par le serveur. Utilisez json= (et non data=) chaque fois que l’API attend du JSON : json= envoie {"title": "hello"} comme corps JSON, tandis que data= l’enverrait comme une chaîne encodée en formulaire HTML. Chaque méthode HTTP correspond à une fonction requests :

Méthode Appel requests À utiliser pour
GET requests.get(url, params=...) Récupérer des données (lecture) — de loin la plus courante
POST requests.post(url, json=...) Envoyer des données pour créer une ressource
PUT requests.put(url, json=...) Remplacer entièrement une ressource
PATCH requests.patch(url, json=...) Mettre à jour une partie d’une ressource
DELETE requests.delete(url) Supprimer une ressource

Beaucoup d’API exigent aussi un token dans les en-têtes de la requête pour l’authentification — passez-les de la même manière, comme un dict à headers= :

headers = {"Authorization": "Bearer YOUR_TOKEN", "Accept": "application/json"}
r = requests.get("https://api.example.com/data", headers=headers, timeout=10)

Requêtes robustes : le jugement

Les trois appels ci-dessus ont tous fonctionné. Le vrai code doit gérer les appels qui échouent — un serveur qui ne répond jamais, une ressource qui n’existe pas, un corps qui n’est pas les données attendues. Deux habitudes font la différence, et un requests.get(url).json() en une ligne n’a ni l’une ni l’autre.

Définissez toujours un timeout. Par défaut, requests attend une réponse indéfiniment. Si le serveur se bloque, votre script aussi — pas d’erreur, pas de sortie, juste un processus figé. Un timeout plafonne cette attente : abandonner après N secondes et lever une exception à la place.

r = requests.get("https://jsonplaceholder.typicode.com/todos/1", timeout=10)

Vérifiez toujours le statut avant de lire le corps. Une réponse 404 ou 500 a quand même un corps — c’est juste une page d’erreur, pas vos données. Appelez r.json() dessus et vous parserez la mauvaise chose (ou planterez). r.raise_for_status() transforme un mauvais statut en une exception que vous pouvez attraper :

r = requests.get("https://jsonplaceholder.typicode.com/todos/999999")
print(r.status_code)
r.raise_for_status()   # raises because the status is 404
404
Traceback (most recent call last):
  ...
requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://jsonplaceholder.typicode.com/todos/999999

Le todo 999999 n’existe pas, le serveur renvoie donc 404, et raise_for_status() lève HTTPError avec un message qui nomme le statut et l’URL. Mettez les deux habitudes ensemble et vous obtenez le modèle à utiliser à chaque fois :

import requests

try:
    r = requests.get("https://jsonplaceholder.typicode.com/todos/1", timeout=10)
    r.raise_for_status()
    data = r.json()
except requests.RequestException as err:
    print(f"Request failed: {err}")
else:
    print(data["title"])

requests.RequestException est la classe de base pour toutes les erreurs que requests peut lever — un timeout, un échec DNS/de connexion, un mauvais statut issu de raise_for_status() — si bien qu’un seul except les attrape toutes. Ce n’est que lorsque la requête a réussi et que le statut était bon que vous atteignez data = r.json(). Voilà toute l’histoire de la robustesse : définir un timeout, vérifier le statut, puis faire confiance au corps. La gestion des erreurs et les timeouts sont documentés dans errors and exceptions et timeouts.

Les API web en une minute

Trois mots suffisent comme vocabulaire. Un endpoint est une URL sur laquelle l’API répond — https://jsonplaceholder.typicode.com/todos/1 est l’endpoint « todo numéro 1 ». La méthode est le verbe : GET pour lire, POST pour créer, PUT/PATCH pour mettre à jour, DELETE pour supprimer — une fonction requests pour chacune (voir le tableau ci-dessus). Et les données voyagent presque toujours sous forme de JSON, que requests lit avec r.json() (en un dict/list Python) et écrit depuis json= (à partir d’un dict). Lisez la documentation de l’API pour connaître ses endpoints et les paramètres qu’ils acceptent ; la mécanique — appeler, vérifier le statut, lire le JSON — est la même pour chacun.

Quand une IA écrit la requête

Demandez à un assistant de code de « récupérer les données de cette API » et vous obtiendrez généralement une ligne unique qui fonctionne : data = requests.get(url).json(). Elle s’exécute, elle renvoie quelque chose, elle a l’air correcte — et c’est exactement la forme que cette leçon existe pour corriger. Cette ligne n’a aucun timeout (elle peut bloquer votre programme indéfiniment sur un serveur lent) et aucune vérification de statut (elle appelle .json() sur tout ce qui revient, si bien qu’une page d’erreur 404 est parsée comme si c’était vos données — un plantage déroutant ou, pire, des valeurs silencieusement fausses). Aucun des deux problèmes n’apparaît sur le chemin heureux où l’assistant l’a testée ; les deux apparaissent en production.

La compétence durable n’est pas de mémoriser requests — c’est de vous faire juge de toute réponse, générée ou non. Quand vous obtenez un extrait comme celui-là, ajoutez les deux choses qu’une réponse en un coup saute : un timeout=, et un raise_for_status() avant le .json(). Une ligne générée est un bon point de départ ; la version robuste est celle que vous livrez réellement.

🟢 Avec un agent IA

Vous avez un extrait requests généré, ou une API que vous ne savez pas trop comment appeler ? Collez-le et demandez à Prova « rends cette requête robuste — ajoute un timeout et une vérification de statut, et gère le chemin d’erreur » — puis exécutez-la vous-même contre le vrai endpoint et relisez le code de statut. Prova rédige l’appel ; c’est la réponse réelle qui est votre preuve, pas sa parole. The runtime is the judge. Demander à Prova →

Problèmes fréquents

Mon script se bloque indéfiniment et ne se termine jamais. Vous n’avez pas passé de timeout. Sans lui, requests attend une réponse indéfiniment, si bien qu’un seul serveur qui ne répond pas fige tout votre programme sans aucune erreur. Passez toujours timeout= (par exemple requests.get(url, timeout=10)) ; l’appel lève alors une exception Timeout après N secondes au lieu de se bloquer, et votre except requests.RequestException peut la gérer.

J’ai obtenu une KeyError, ou les données ont l’air fausses. Vous avez appelé r.json() sur une réponse d’erreur. Un 404 ou un 500 renvoie quand même un corps — une page d’erreur, pas vos données — donc le parser vous donne des champs qui n’existent pas. Vérifiez d’abord le statut : appelez r.raise_for_status() (ou testez r.ok/r.status_code) avant r.json(), pour qu’une mauvaise réponse lève une exception au lieu de vous remettre silencieusement le mauvais dictionnaire.

Ma chaîne de requête est fausse, ou des espaces ont cassé la requête. Vous avez construit l’URL à la main — quelque chose comme f"{url}?q={query}". Les espaces, &, = et les caractères non-ASCII ont tous besoin d’un encodage-pourcent, et un seul mauvais caractère corrompt la requête. Ne concaténez pas ; passez un dict à params= et laissez requests l’encoder : requests.get(url, params={"q": query}).

Questions fréquentes

Installez la bibliothèque requests avec pip install requests, puis appelez la fonction correspondant à la méthode HTTP dont vous avez besoin : requests.get(url) pour lire des données, requests.post(url, json=...) pour en envoyer. Chaque appel renvoie un objet réponse — lisez r.status_code pour vérifier que ça a fonctionné et r.json() pour obtenir le corps sous forme de dict ou de list Python. Un appel robuste ajoute toujours un timeout= et un raise_for_status() avant de faire confiance au corps. La bibliothèque standard de Python fournit aussi urllib.request, mais requests est le choix quasi universel pour son API plus simple.

Appelez requests.get(url). Pour ajouter des paramètres de requête, passez un dictionnaire à params=requests.get(url, params={"userId": 1}) — et requests construit et encode la chaîne de requête pour vous. L’appel renvoie un objet réponse : vérifiez r.status_code (200 signifie OK) et lisez le corps avec r.json(). Ajoutez timeout=10 pour que la requête ne puisse pas se bloquer indéfiniment, et appelez r.raise_for_status() avant de parser pour transformer un statut d’erreur en exception.

Appelez .json() sur l’objet réponse : data = r.json(). requests parse le corps JSON en types Python natifs — un objet JSON devient un dict, un tableau JSON devient une list — que vous indexez ensuite normalement (data["title"], data[0]). Vérifiez d’abord le statut avec r.raise_for_status(), car appeler .json() sur une réponse d’erreur parse la page d’erreur, pas vos données. Si le corps n’est pas du JSON valide, .json() lève une JSONDecodeError ; utilisez r.text pour voir la réponse brute dans ce cas.

urllib.request est le client HTTP intégré à Python — toujours disponible, mais bas niveau : vous assemblez les requêtes, encodez les paramètres et décodez les réponses vous-même. requests est une bibliothèque tierce (pip install requests) qui enveloppe la même capacité dans une API bien plus simple — requests.get(url, params=...), l’encodage JSON automatique avec json=, un objet réponse riche, et une gestion des erreurs simple. Pour presque tout le code applicatif, les développeurs se tournent vers requests ; urllib n’est un choix raisonnable que lorsque vous devez éviter toute dépendance. Voir la documentation de requests.

Faites deux choses à chaque appel. D’abord, passez timeout= pour qu’un serveur lent ou mort lève une exception au lieu de se bloquer. Ensuite, appelez r.raise_for_status() avant de lire le corps — elle lève HTTPError sur un statut 4xx/5xx, si bien que vous ne parsez jamais une page d’erreur comme des données. Enveloppez les deux dans try/except requests.RequestException, la classe de base pour toutes les erreurs de requests (timeouts, échecs de connexion et mauvais statuts), et gérez l’échec à un seul endroit : try: r = requests.get(url, timeout=10); r.raise_for_status(); data = r.json() except requests.RequestException as err: ....

Testez vos connaissances

Vous voulez récupérer le post numéro 5 depuis https://jsonplaceholder.typicode.com/posts/5 et afficher son title. Écrivez l’appel de façon robuste, pas comme une ligne unique.

Tâche 1. Envoyez une requête GET vers cet endpoint avec un timeout de 10 secondes.

Tâche 2. Vérifiez le statut avec raise_for_status() avant de lire le corps, et ne le parsez qu’ensuite avec .json().

Tâche 3. Enveloppez le tout dans try/except requests.RequestException pour qu’un timeout, un échec de connexion ou un mauvais statut affichent tous un message convivial au lieu de planter. En cas de succès, affichez le title du post.

L’ordre à l’intérieur du try est toujours le même : envoyer la requête (avec timeout=), appeler r.raise_for_status(), puis data = r.json(). Attrapez requests.RequestException — c’est la classe de base pour toutes les erreurs de requests, donc un seul except couvre le timeout, l’erreur de connexion et l’HTTPError de raise_for_status(). Indexez le dict parsé avec data["title"].

import requests

try:
    r = requests.get("https://jsonplaceholder.typicode.com/posts/5", timeout=10)
    r.raise_for_status()
    data = r.json()
except requests.RequestException as err:
    print(f"Request failed: {err}")
else:
    print(data["title"])

Le timeout=10 garantit que l’appel ne peut pas se bloquer ; raise_for_status() convertit un mauvais statut en exception avant que r.json() ne s’exécute, si bien que vous ne parsez jamais une page d’erreur ; et except requests.RequestException attrape le timeout, tout échec de connexion et l’HTTPError à un seul endroit. Le bloc else ne s’exécute que lorsque la requête a pleinement réussi — c’est là qu’il est sûr de lire data["title"].

Vérification rapide. Le script de chargement de données d’un collègue se fige parfois et doit être tué, et d’autres fois plante avec une KeyError sur data["results"]. D’après ce que vous avez appris, nommez les deux choses qui manquent à son appel requests.get(url).json().

Un timeout et une vérification de statut. Sans timeout=, l’appel attend indéfiniment quand un serveur ne répond pas — c’est le blocage. Sans r.raise_for_status() avant .json(), une réponse d’erreur (disons un 404) est parsée comme si c’était les données, donc data["results"] n’existe pas — c’est la KeyError. La correction est le modèle robuste : requests.get(url, timeout=10), puis r.raise_for_status(), puis r.json(), le tout enveloppé dans try/except requests.RequestException.

Conclusion

Dialoguer avec une API web depuis Python se résume à une petite boucle répétable : appeler l’endpoint avec la bonne méthode (requests.get / requests.post), passer les paramètres de requête sous forme de dict pour que requests les encode, et lire l’objet réponsestatus_code, headers, et le corps JSON avec .json(). L’habitude qui transforme un script qui fonctionne en un script fiable, c’est le jugement qu’un appel en une ligne saute : définissez toujours un timeout, et vérifiez toujours le statut avec raise_for_status() avant de faire confiance au corps, en enveloppant les deux dans try/except requests.RequestException. Copiez le modèle robuste de cette page, exécutez-le dans votre terminal contre votre propre API, et relisez le code de statut — c’est la requête que vous livrez vraiment.

Leçons connexes

Cette page vous a-t-elle été utile ?

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Requêtes HTTP et API en Python avec requests},
  date = {2026-07-18},
  url = {https://www.datanovia.com/learn/programming/python-tools/http-requests-and-apis},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Requêtes HTTP et API en Python avec requests.” 2026. July 18. https://www.datanovia.com/learn/programming/python-tools/http-requests-and-apis.