En bref : il existe trois façons judicieuses d'utiliser cURL avec Python : lancer une commande via lecurlbinaire avecsubprocess, lier libcurl via PycURL, ou ignorer complètement cURL et utiliser la bibliothèque Requests. Bien savoir utiliser cURL avec Python, c'est connaître ces trois méthodes. Ce guide vous propose des exemples exécutables pour chacune d'entre elles, un tableau de conversion des options cURL vers Python, ainsi qu'une matrice de décision pour vous aider à choisir le bon outil dès le départ.
Introduction
Si vous écrivez en Python et utilisez des API HTTP, vous avez probablement déjà rencontré cette situation : la documentation d’une API ou le bouton « Copier en cURL » de votre navigateur vous fournit une ligne de commande commençant par curl -X POST ..., et vous en avez maintenant besoin dans un script Python. Comprendre comment utiliser cURL avec Python semble simple, mais il existe plusieurs bonnes réponses.
cURL est un outil en ligne de commande permettant de transférer des données via des protocoles réseau (HTTP, HTTPS, FTP). Depuis Python, vous pouvez appeler le binaire curl en tant que processus externe, piloter sa bibliothèque C sous-jacente (libcurl) via PycURL, ou utiliser la bibliothèque Requests comme alternative Python. Chaque option présente des compromis en termes de vitesse, de contrôle et de maintenabilité.
Ce guide s’adresse aux ingénieurs backend, données et scraping qui connaissent déjà Python et souhaitent disposer d’une méthode claire pour traduire n’importe quel extrait de code curl en code fonctionnel. Nous abordons ces trois méthodes à l’aide d’exemples exécutables, nous établissons une correspondance entre les indicateurs curl courants et leurs équivalents Python, nous construisons un petit pipeline de scraping et nous terminons par le dépannage afin que vous puissiez livrer le code au lieu de vous battre avec vos outils.
Pourquoi les développeurs exécutent-ils cURL dans Python ?
La plupart des équipes se posent la question de l’utilisation de curl dans Python pour la même raison : quelqu’un leur a fourni une commande curl. Les documentations d’API fournissent des exemples de requêtes sous forme d’ curl appels, les outils de développement des navigateurs exportent les appels réseau dans le même format, et Postman et Insomnia vous permettent de copier n'importe quelle requête sous forme de curl. Cet extrait de code est la référence, et vous voulez que votre code Python se comporte de manière identique.
Exécuter cURL dans Python vous permet de déboguer d’abord la requête exacte, puis de passer à quelque chose de plus idiomatique. Une exécution par copier-coller via subprocess prouve que le point de terminaison fonctionne. À partir de là, vous pouvez réécrire l'appel en PycURL ou Requests en étant sûr de ne pas avoir modifié le format de transmission. Ce court cycle de rétroaction est la véritable raison pour laquelle les développeurs veulent savoir comment utiliser cURL avec Python, et non curl seul.
Comment utiliser cURL avec Python : trois approches en un coup d'œil
Lorsque les développeurs demandent comment utiliser cURL avec Python, ils font généralement référence à l’une des trois approches concrètes suivantes. Avant d’écrire le moindre code, choisissez celle qui correspond à la tâche à accomplir. Ces trois options ne sont pas interchangeables, et choisir la mauvaise implique généralement de réécrire l’appel par la suite.
|
Approche |
Idéale pour |
Installation requise |
Compromis |
|---|---|---|---|
|
|
Rejouer un extrait de code curl à l'identique, débogage ponctuel, scripts CI |
Aucun (curl dans le PATH) |
Implique un coût de création de processus par requête et analyse la sortie sous forme de chaîne |
|
PycURL (liaisons libcurl) |
Scrapers à haut débit, contrôle fin de TLS/timeout, FTP et autres protocoles |
|
API de bas niveau, problèmes de compilation sur certains systèmes |
|
Bibliothèque Requests |
Presque tout le reste : API REST, JSON, cookies, sessions |
|
Non fournie avec Python ; masque certaines options spécifiques à curl |
Considérez subprocess comme votre étape de traduction, PycURL comme votre outil puissant et Requests comme votre option par défaut. La plupart du code Python en production finit par utiliser Requests ; les deux autres couvrent les cas particuliers.
Méthode 1 : subprocess : exécuter directement les commandes curl
Le subprocess module fait partie de la bibliothèque standard de Python, vous pouvez donc lancer curl sans rien installer de nouveau. C'est l'interprétation la plus littérale de « utiliser cURL avec Python », et cela s'avère vraiment utile lorsque vous souhaitez reproduire une commande exactement telle qu'elle apparaît dans la documentation de l'API.
Une règle de sécurité incontournable : transmettez la commande sous forme de liste d'arguments, et non comme une simple chaîne de caractères shell. Les chaînes de caractères exposent au risque d'injection shell lorsque toute partie de la requête provient d'une saisie utilisateur. La forme liste d'arguments contourne entièrement le shell. La documentation Python subprocess traite en détail du modèle de sécurité.
Insérez un extrait de code curl dans subprocess.run
Prenez une ligne de commande curl, divisez-la en tokens, puis transmettez la liste à subprocess.run. Définissez capture_output=True pour que stdout et stderr vous soient renvoyés, et text=True vous obtenez ainsi des chaînes de caractères au lieu d’octets.
import subprocess
cmd = [
"curl", "-s",
"-H", "Accept: application/json",
"https://httpbin.org/get?lang=python",
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
print(result.stdout)Le -s drapeau désactive la barre de progression de curl afin que stdout ne contienne que le corps de la réponse. L' timeout=15 argument déclenche une subprocess.TimeoutExpired si curl se bloque, ce qui est exactement ce que vous souhaitez dans un script qui ne doit pas se bloquer indéfiniment. Conservez cette forme pour la traduction : une fois qu’elle fonctionne, vous disposez d’une base de référence vérifiée pour le portage vers PycURL ou Requests.
Capture de la sortie et vérification des codes de retour
Par défaut, subprocess.run ne lève pas d'exception lorsque curl se termine avec un code de sortie différent de zéro. Vous devez inspecter le code de retour vous-même ou choisir explicitement de lever une exception.
import json, subprocess
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
if result.returncode != 0:
raise RuntimeError(f"curl failed ({result.returncode}): {result.stderr.strip()}")
try:
payload = json.loads(result.stdout)
except json.JSONDecodeError as exc:
raise RuntimeError(f"non-JSON response: {result.stdout[:200]}") from exc
print(payload["args"])Vous pouvez également appeler result.check_returncode(), qui lève une exception CalledProcessError lors de toute sortie non nulle. Dans tous les cas, consignez result.stderr lorsque l'appel échoue. Curl y écrit ses messages de diagnostic, et ce message suffit généralement à distinguer un échec DNS d'une erreur TLS ou d'une réponse 4xx.
Méthode 2 : PycURL : liaisons natives avec libcurl
PycURL est une interface Python pour libcurl, la même bibliothèque C qui alimente le binaire curl lui-même. Elle expose des options de bas niveau pour les délais d'expiration, la configuration SSL, les en-têtes, les cookies, les redirections et les protocoles au-delà de HTTP. Lorsque le débit ou un contrôle fin est important, PycURL est la solution idéale.
Installez-le avec pip install pycurl. Le paquet Python est un simple wrapper, vous aurez donc également besoin de libcurl et des en-têtes de développement OpenSSL sur le système. Sous Debian/Ubuntu, cela correspond à apt install libcurl4-openssl-dev libssl-dev; sur macOS, brew install curl openssl. Nous aborderons les erreurs de liaison OpenSSL dans la section Dépannage, car elles constituent la cause la plus fréquente d'échec d'une nouvelle installation.
GET, POST et JSON avec PycURL
PycURL suit le modèle de libcurl : créer un descripteur, définir les options, exécuter, puis fermer. Les écritures sont dirigées vers un tampon de type fichier, qui est généralement un BytesIO.
import json, pycurl
from io import BytesIO
from urllib.parse import urlencode
# GET
buf = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, "https://httpbin.org/get?lang=python")
c.setopt(c.WRITEDATA, buf)
c.perform()
status = c.getinfo(pycurl.RESPONSE_CODE)
c.close()
print(status, buf.getvalue().decode("utf-8"))Pour un POST avec encodage de formulaire, définissez POSTFIELDS un corps encodé en URL. Pour JSON, vider le dictionnaire et définir le bon Content-Type.
# POST form
form = urlencode({"a": 1, "b": "two"})
buf = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, "https://httpbin.org/post")
c.setopt(c.POSTFIELDS, form)
c.setopt(c.WRITEDATA, buf)
c.perform(); c.close()
# POST JSON
body = json.dumps({"hello": "world"})
buf = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, "https://httpbin.org/post")
c.setopt(c.HTTPHEADER, ["Content-Type: application/json"])
c.setopt(c.POSTFIELDS, body)
c.setopt(c.WRITEDATA, buf)
c.perform(); c.close()C'est HTTPHEADER permet de contrôler Content-Type, Accept, Authorization et tout autre en-tête de requête. Nous allons nous appuyer sur ce modèle dans la suite.
En-têtes personnalisés, cookies et redirections
HTTPHEADER prend une liste de "Name: value" chaînes de caractères. Les cookies peuvent être intégrés en tant qu' Cookie en-tête pour les appels ponctuels, ou vous pouvez laisser libcurl gérer un fichier de cookies avec COOKIEFILE et COOKIEJAR.
c.setopt(c.HTTPHEADER, [
"Accept: application/json",
"Authorization: Bearer eyJhbGciOi...",
"Cookie: session=abc123; theme=dark",
])
# Or use a cookie jar to persist Set-Cookie across requests
c.setopt(c.COOKIEFILE, "cookies.txt")
c.setopt(c.COOKIEJAR, "cookies.txt")Pour les redirections, activez FOLLOWLOCATION (l'équivalent de curl -L) et limitez la chaîne avec MAXREDIRS afin qu'un serveur défectueux ne puisse pas vous faire tourner en boucle indéfiniment.
c.setopt(c.FOLLOWLOCATION, True)
c.setopt(c.MAXREDIRS, 5)Si vous n'avez besoin que des en-têtes de réponse (une curl -I requête de type), définissez NOBODY sur True et acheminez le flux d'en-têtes vers un callback via HEADERFUNCTION. Ce callback s'exécute une fois par ligne d'en-tête, ce qui est pratique pour extraire des éléments tels que Last-Modified ou des métadonnées de limitation de débit. Pour des recettes plus avancées, consultez notre analyse des en-têtes de réponse HTTP dans cURL.
Téléchargement de fichiers en continu avec PycURL
WRITEDATA accepte tout objet de type fichier, donc un téléchargement ne nécessite qu’une seule ligne de code : ouvrez un fichier en mode d’écriture binaire et pointez libcurl vers celui-ci. L’utilisation de la mémoire reste constante quelle que soit la taille de la charge utile.
import os, pycurl
url = "https://example.com/large.iso"
out = "large.iso"
mode = "ab" if os.path.exists(out) else "wb"
offset = os.path.getsize(out) if mode == "ab" else 0
with open(out, mode) as fp:
c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.WRITEDATA, fp)
c.setopt(c.FOLLOWLOCATION, True)
if offset:
c.setopt(c.RANGE, f"{offset}-") # resume from byte offset
c.perform(); c.close()L'en-tête Range: bytes={offset}- en-tête indique au serveur de n'envoyer que la partie manquante, ce qui correspond exactement à la manière dont curl -C - reprend les téléchargements interrompus. Le serveur doit prendre en charge les requêtes de plage (ce qui est le cas de la plupart des CDN).
Méthode 3 : Requests : l'alternative Pythonic à curl
Pour la plupart des tâches quotidiennes, Requests est la solution. Il n’est pas fourni avec Python (installez-le avec pip install requests), mais son API correspond parfaitement à la sémantique de curl : les paramètres de requête, les en-têtes, les cookies, les corps JSON et les délais d’expiration sont tous des arguments clés.
import requests
# GET with query params
r = requests.get(
"https://httpbin.org/get",
params={"lang": "python"},
headers={"Accept": "application/json"},
timeout=15,
)
r.raise_for_status()
print(r.json())
# POST JSON
r = requests.post(
"https://httpbin.org/post",
json={"hello": "world"},
headers={"Authorization": "Bearer ..."},
timeout=15,
)raise_for_status() est votre allié : il transforme tout code 4xx/5xx en requests.HTTPError, ce qui permet de distinguer clairement dans votre code les échecs réseau (requests.ConnectionError, requests.Timeout) et les erreurs HTTP reste claire dans votre code.
Optez pour Requests par défaut lorsque l'appel fait partie d'une série dans un programme Python, que vous avez besoin d'un état de session ou que votre équipe assurera la maintenance du code. Optez pour PycURL lorsque vous avez identifié un véritable goulot d'étranglement ou que vous avez besoin d'options propres à libcurl. Pour une comparaison plus approfondie des clients HTTP Python, consultez notre tour d'horizon sur le sujet.
Traduire les indicateurs curl courants en Python
Une fois que vous savez utiliser cURL avec Python dans ses trois variantes, le moyen le plus rapide de porter une nouvelle commande est de traduire ses indicateurs un par un. Ce tableau couvre les indicateurs que vous verrez dans 95 % des documentations d'API et des exportations d'outils de développement.
|
Indicateur curl |
Fonction |
PycURL |
Mot-clé Requests |
|---|---|---|---|
|
|
Définit la méthode HTTP |
|
|
|
|
Ajouter un en-tête de requête |
|
|
|
|
Corps encodé en URL |
|
|
|
|
Corps brut à partir d'un fichier |
|
|
|
|
Corps JSON brut |
|
|
|
|
Formulaire multipart |
|
|
|
|
Convertir les données en chaîne de requête |
|
|
|
|
Suivre les redirections |
|
|
|
|
Authentification de base |
|
|
|
|
Envoyer un cookie |
|
|
|
|
Écrire le corps dans un fichier |
|
|
|
|
Délai d'expiration total |
|
|
Si vous préférez ne pas traduire manuellement, il existe des convertisseurs curl-vers-Python publics (et celui de ScrapingBee est l'un des plus connus) qui prennent une commande curl et génèrent un appel Requests avec les en-têtes, les paramètres et les données renseignés. Utilisez-les pour démarrer, puis vérifiez la validité de la sortie par rapport à ce tableau.
Mise en pratique : un pipeline de scraping piloté par curl
L'une des raisons courantes d'apprendre à utiliser cURL avec Python est le scraping web. Voici le modèle que nous utilisons pour prototyper un petit scraper : récupérer le code HTML avec PycURL pour plus de rapidité, l'analyser avec BeautifulSoup, puis enregistrer le résultat. Le tout tient en moins de 40 lignes et couvre les vérifications d'état, l'encodage et l'écriture au format CSV.
import csv, json, pycurl
from io import BytesIO
from bs4 import BeautifulSoup
URL = "https://books.toscrape.com/catalogue/page-1.html"
def fetch(url: str) -> str:
buf = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.WRITEDATA, buf)
c.setopt(c.FOLLOWLOCATION, True)
c.setopt(c.TIMEOUT, 20)
c.setopt(c.HTTPHEADER, ["User-Agent: scraping-pipeline/1.0"])
c.perform()
code = c.getinfo(pycurl.RESPONSE_CODE)
c.close()
if code != 200:
raise RuntimeError(f"unexpected status {code} for {url}")
return buf.getvalue().decode("utf-8")
def parse(html: str) -> list[dict]:
soup = BeautifulSoup(html, "html.parser")
rows = []
for card in soup.select("article.product_pod"):
rows.append({
"title": card.h3.a["title"],
"price": card.select_one(".price_color").text.strip(),
"stock": card.select_one(".availability").text.strip(),
})
return rows
def main():
rows = parse(fetch(URL))
with open("books.csv", "w", newline="") as fp:
writer = csv.DictWriter(fp, fieldnames=rows[0].keys())
writer.writeheader(); writer.writerows(rows)
print(json.dumps(rows[:2], indent=2))
if __name__ == "__main__":
main()Remplacez PycURL par subprocess si vous souhaitez reproduire une commande cURL à l'identique, ou par Requests si vous avez besoin d'un état de session. Dès que vous commencerez à interagir avec des sites réels dotés de limites de débit et de défenses anti-bot, vous aurez besoin d'une couche proxy en amont de cette étape de récupération.
Dépannage des erreurs courantes de cURL avec Python
La plupart des difficultés rencontrées lors de l'apprentissage de l'utilisation de cURL avec Python proviennent d'un petit ensemble d'erreurs récurrentes. Voici une liste succincte et la manière de résoudre chacune d'entre elles.
- PycURL
ImportError: pycurl: libcurl link-time ssl backend (...) is different from compile-time ssl backend (...). Votre paquet PycURL a été compilé avec un backend SSL différent de celui de la bibliothèque libcurl installée sur votre système. À l'heure où nous écrivons ces lignes, la solution la plus fiable sous macOS consiste à installer OpenSSL via Homebrew et à réinstaller PycURL à partir du code source en utilisant ce backend ; sous Windows, installez les binaires OpenSSL 1.1.x et définissezPYCURL_SSL_LIBRARY,LIB, etINCLUDEavantpip install pycurl --no-binary :all:. Vérifiez à nouveau les notes d'installation de PycURL pour votre plateforme, car les variables d'environnement exactes ont changé d'une version à l'autre. UnicodeEncodeErrorde PycURL sur les corps POST. PycURL s'attend à des octets pourPOSTFIELDS. Encodez explicitement les données non ASCII :c.setopt(c.POSTFIELDS, body.encode("utf-8")).subprocess.TimeoutExpired. Transmettez toujourstimeout=àsubprocess.run. Traitez l'exception comme une défaillance réseau, et non comme un bug.- Erreurs TLS et certificats auto-signés. PycURL :
c.setopt(c.SSL_VERIFYPEER, 0); Requests :verify=False. Ne procédez ainsi que dans des environnements de confiance, et privilégiez l'épinglage d'un ensemble de certificats CA en production. - Distinguer les erreurs HTTP des erreurs de transport. Avec Requests, interceptez
requests.HTTPErrorséparément derequests.ConnectionError. Avec subprocess, unreturncodecorrespond à une erreur au niveau du transport ; un code HTTP 4xx renvoie toujours 0, sauf si vous passez--fail.
Choisir la bonne approche pour votre cas d'utilisation
Une fois que vous disposez des trois outils, le choix dépend de la situation.
- Déboguer une API ou reproduire un rapport de bogue. Optez d’abord pour
subprocess. L'exécution de la commande curl littérale élimine la variable « mon client Python est le problème ». - Scripts ponctuels et tâches d'intégration continue. Requests. Il est lisible, bien documenté et facile à maintenir pour le prochain ingénieur.
- Scrapers à exécution longue, volumes de requêtes élevés ou protocoles autres que HTTP. PycURL. Vous bénéficiez de la réutilisation des connexions de libcurl, d’un contrôle TLS fin et d’une charge par requête réduite.
- Cookies et flux de connexion. Requests
Sessionest la solution la plus simple ; le cookie jar de PycURL est l'alternative si vous utilisez déjà libcurl.
Savoir utiliser cURL avec Python ne consiste pas tant à choisir un gagnant qu'à adapter l'outil à la requête.
Points clés
- Trois options concrètes pour combiner curl avec Python :
subprocess(rejouer le binaire), PycURL (liaisons libcurl) et Requests. Choisissez de manière réfléchie, et non par habitude. - Utilisez
subprocesscomme couche de traduction : vérifiez le format de transmission avec la commande littérale, puis portez vers PycURL ou Requests en toute confiance. - Mappez systématiquement les indicateurs curl vers Python :
-Hdevient des en-têtes,-ddevient data ou json,-Gdevient des paramètres,-Fdevient des fichiers,-Ldevient des redirections,-odevient une écriture en continu. - Définissez toujours des délais d'expiration, vérifiez toujours les codes d'état et traitez les erreurs HTTP comme une catégorie distincte des erreurs de transport.
- Pour le scraping à haut débit ou les téléchargements avec reprise, PycURL est un investissement rentable. Pour tout le reste, utilisez Requests par défaut.
FAQ
Que signifie « utiliser cURL en Python » : est-ce que j'exécute le binaire curl ou une bibliothèque Python ?
Les deux. « Exécuter curl » signifie généralement appeler l'exécutable système curl à partir de Python via subprocess, ce qui nécessite que curl soit dans votre PATH. « Utiliser une bibliothèque Python » signifie importer PycURL (un wrapper autour de libcurl) ou Requests (un client HTTP purement Python) sans jamais toucher au binaire. Les requêtes réseau semblent identiques au serveur ; seul le code d'appel diffère.
PycURL est-il vraiment plus rapide que la bibliothèque Requests dans des charges de travail réelles, ou seulement en théorie ?
PycURL est généralement plus rapide dans les benchmarks synthétiques car il déleste le travail HTTP vers libcurl en C. Dans les charges de travail réelles, l'écart se réduit : la latence réseau, les handshakes TLS et l'analyse syntaxique prennent généralement le dessus. PycURL l'emporte toujours sur des milliers de connexions simultanées, où la surcharge par requête s'accumule. Pour la plupart des scripts, la différence n'est pas mesurable.
Quel est le moyen le plus rapide de convertir une longue commande curl issue de la documentation d'une API en code Python fonctionnel ?
Collez la commande curl dans un convertisseur curl-vers-Python (il en existe plusieurs gratuits en ligne), sélectionnez la sortie Requests, puis vérifiez le code généré à l'aide du tableau de traduction des indicateurs fourni dans ce guide. Le convertisseur gère automatiquement les en-têtes, les paramètres et les données. Il vous reste à ajouter timeout, raise_for_status()et une gestion des exceptions appropriée avant de le déployer.
Comment envoyer un téléchargement de fichier multipart (équivalent à curl -F) depuis Python ?
Dans Requests, utilisez le files : requests.post(url, files={"upload": open("data.csv", "rb")}). Pour un contrôle supplémentaire sur le nom de fichier et le type de contenu, passez un tuple : files={"upload": ("data.csv", fp, "text/csv")}. Dans PycURL, définissez l' HTTPPOST option avec une liste de tuples décrivant chaque champ du formulaire, y compris une pycurl.FORM_FILE entrée pour le chemin d'accès sur le disque.
Pourquoi l'installation de PycURL échoue-t-elle avec une erreur de liaison OpenSSL ou libcurl, et comment y remédier ?
Cette erreur signifie que le module wheel a été compilé avec un backend SSL qui ne correspond pas à votre libcurl système. La solution consiste à réinstaller PycURL à partir des sources en utilisant votre libcurl locale : pip install --no-binary :all: pycurl après avoir installé libcurl et les en-têtes de développement OpenSSL (brew install curl openssl sur macOS ; les paquets de développement équivalents sur Linux). Sous Windows, définissez les chemins d'accès à OpenSSL via des variables d'environnement avant de réinstaller.
Conclusion
Savoir utiliser cURL avec Python, c'est en réalité trois compétences en une : appeler le binaire curl avec subprocess, piloter libcurl via PycURL et écrire du code Requests idiomatique. Chacune a son rôle. subprocess est votre étape de traduction entre la documentation de l'API et le code vérifié. PycURL est votre outil de performance pour les scrapers et les téléchargements à haut débit. Requests est la valeur par défaut pour tout le reste, car il reste lisible à mesure que le projet se développe.
Le tableau de correspondance des options vers Python, la recette de téléchargement en continu et la liste de dépannage ci-dessus couvrent la plupart des difficultés. Il reste à savoir comment votre serveur cible traite le trafic non-navigateur : les limites de débit, les CAPTCHA, les défis JavaScript et les blocages d'IP finiront par vous affecter, quelle que soit la qualité de votre code Python.
C'est sur cette couche que nous nous concentrons chez WebScrapingAPI. Si vous passez plus de temps à lutter contre les défenses anti-bot qu'à écrire votre scraper, notre API Scraper prend une requête de type curl et renvoie le HTML brut, en gérant la rotation des proxys, la résolution des CAPTCHA et les tentatives de reconnexion de son côté. Vous pouvez ainsi conserver votre code subprocess, PycURL ou Requests tel quel et simplement changer de point de terminaison. Choisissez la méthode curl qui convient à votre tâche, et laissez la couche réseau devenir le problème de quelqu'un d'autre.




