En bref : ce guide explique en détail comment utiliser des proxys avec Python Requests : unproxies, des URL authentifiées, des variables d'environnement, laSessionla réutilisation, SOCKS5 sans fuite DNS, et un pool de rotation avec tentatives de reconnexion et disjoncteur. À la fin, vous saurez quand une API gérée vaut mieux qu’un pool DIY.
Introduction
Si vous avez déjà déployé un scraper qui fonctionnait localement mais qui a ensuite commencé à renvoyer des codes 403, 429 ou des timeouts silencieux en production, vous savez déjà pourquoi les proxys existent. Apprendre à utiliser les proxys avec Python Requests fait la différence entre un script qui s'exécute une seule fois sur votre ordinateur portable et une tâche qui résiste aux limites de débit, aux blocages géographiques et aux interdictions d'IP sur des milliers de pages.
Une configuration de proxy Python Requests, dans sa forme la plus simple, est un dictionnaire qui mappe http et https à une URL de proxy et est transmis à requests.get(). Cela vous permet de débloquer l'accès pendant dix minutes. La production exige davantage : des identifiants conservés hors de Git, des sessions qui persistent les cookies, des points de terminaison SOCKS5 qui ne divulguent pas de DNS, des tentatives de reconnexion avec délai d'attente, et une stratégie de rotation qui ne martèle pas sans cesse un proxy inactif.
Ce guide s'adresse aux développeurs Python de niveau intermédiaire qui connaissent déjà les bases de requests et qui ont désormais besoin d’une méthode fiable pour ajouter la prise en charge des proxys sans réécrire leur scraper. Nous abordons l’utilisation des proxys avec Python Requests, du simple dictionnaire à une boucle de rotation en production, en soulignant les compromis en langage clair.
Démarrage rapide : un proxy Python Requests fonctionnel en cinq minutes
Avant d'approfondir la rotation et les tentatives de reconnexion, voici l'exemple de huit lignes dont 90 % des développeurs ont réellement besoin lorsqu'ils cherchent comment utiliser des proxys avec Python Requests. Copiez-le dans un fichier, remplacez par n'importe quelle combinaison hôte:port de proxy fonctionnelle, puis exécutez.
import requests
proxies = {
"http": "http://203.0.113.10:8080",
"https": "http://203.0.113.10:8080",
}
resp = requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=10)
print(resp.json())Si l'adresse IP affichée est celle du proxy et non la vôtre, votre proxy se trouve dans le chemin de la requête. Le reste de ce guide explique comment renforcer ce modèle.
Prérequis : Python, pip et un proxy accessible
Vous avez besoin de Python 3.8 ou une version ultérieure (python --version), pip) et au moins un hôte-port de proxy utilisable. Un environnement virtuel (python -m venv venv) permet de garder les dépendances propres pour chaque projet. Installez Requests avec pip install requests. Le proxy peut provenir d'une liste gratuite, d'un pool payant ou d'une instance locale de Squid ou Tor.
Comment utiliser des proxys avec Python Requests : le modèle mental
Avant de se plonger dans le code, il est utile de savoir comment Requests détermine réellement où envoyer le trafic. La bibliothèque achemine chaque appel via une URL de proxy en fonction du schéma utilisé : HTTP, HTTPS et (avec un paquet supplémentaire) SOCKS. Trois sources peuvent fournir cette URL, dans cet ordre de priorité approximatif : l’ proxies= argument d'un appel unique, le session.proxies dict sur un Session, et enfin les HTTP_PROXY / HTTPS_PROXY variables d'environnement. L'ordre de priorité exact et la gestion des variantes en minuscules sont documentés dans la documentation d'utilisation avancée de Requests ; vérifiez toujours par rapport à votre version épinglée.
Configurer un proxy de base avec Python Requests
La configuration de base se fait en deux étapes : créer un proxies dictionnaire, puis d'envoyer une requête de vérification via celui-ci. Les deux sous-sections suivantes détaillent chaque étape et les pièges à éviter en cas de proxys inactifs ou mal configurés.
Créer le dictionnaire de proxys pour HTTP et HTTPS
Dans Python Requests, les proxys sont transmis sous la forme d'un dictionnaire mappant les schémas à une URL de proxy. Remplissez toujours les deux clés, même si vous prévoyez uniquement d'accéder à des cibles HTTPS, car les redirections peuvent faire passer à un schéma inférieur.
proxies = {
"http": "http://user:pass@proxy.example.com:8080",
"https": "http://user:pass@proxy.example.com:8080",
}
requests.get(url, proxies=proxies, timeout=(5, 15))Le timeout=(connect, read) tuple est indispensable en production. Sans lui, un proxy inactif bloque votre worker.
Vérifiez que le proxy se trouve dans le chemin de la requête
Accédez à un point de terminaison d'écho IP et comparez-le à votre adresse IP réelle. Deux sites fiables sont https://api.ipify.org?format=json et https://httpbin.org/ip.
print(requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=10).json())Si l'adresse renvoyée diffère de votre IP locale, le proxy fonctionne. Si elle correspond, le proxy a silencieusement échoué en mode « failed open ».
Authentifier les proxys et protéger les identifiants
La plupart des proxys payants sont authentifiés, et c'est là que l'utilisation des proxys avec Python Requests se complique. Les trois sous-sections suivantes traitent de l'intégration d'URL, des variables d'environnement et des trois codes d'erreur que vous rencontrerez.
Intégrer un nom d'utilisateur et un mot de passe dans l'URL du proxy
Le format accepté est http://user:pass@host:port. Si votre mot de passe contient @, :, %, ou /, encodez-le en URL, sinon Requests analysera mal l'URL et vous obtiendrez des erreurs 407 :
from urllib.parse import quote
user = quote("alice@corp")
pwd = quote("p@ss:w/rd%1")
proxy_url = f"http://{user}:{pwd}@proxy.example.com:8080"Ne commitez jamais cette chaîne dans Git.
Déplacez les secrets vers HTTP_PROXY, HTTPS_PROXY et NO_PROXY
Requests récupère automatiquement HTTP_PROXY, HTTPS_PROXY, et NO_PROXY dans l'environnement, et selon la documentation officielle, il prend également en charge les variantes en minuscules sur les systèmes POSIX. Cela signifie que vous pouvez garder les identifiants entièrement hors du code :
# Linux / macOS
export HTTPS_PROXY="http://user:pass@proxy.example.com:8080"
export NO_PROXY="localhost,127.0.0.1,.internal"# Windows
setx HTTPS_PROXY "http://user:pass@proxy.example.com:8080"C'est la méthode la plus propre pour les images Docker et les exécuteurs CI, où les secrets résident dans l'environnement et non dans le dépôt.
Diagnostiquer les erreurs de proxy 407, 401 et 403
Lorsqu’un problème survient, le code d’état vous indique quelle couche est en difficulté.
|
Statut |
Cause probable |
Correction en une ligne |
|---|---|---|
|
407 Authentification proxy requise |
Identifiants de proxy manquants ou incorrects |
Encoder le mot de passe en URL et réessayer |
|
401 Non autorisé |
Nom d'utilisateur ou mot de passe incorrect |
Modifiez les identifiants et vérifiez avec |
|
403 Accès interdit |
Le site cible a bloqué l'adresse IP du proxy |
Passez à un autre proxy ou modifiez la localisation |
Vérifiez d'abord le proxy, puis la cible.
Réutilisez les paramètres avec requests.Session pour les cookies et la mise en pool des connexions
A Session est la primitive idéale dès que vous effectuez plus d'un appel. Elle conserve proxies, les en-têtes par défaut et les cookies, et elle maintient la connexion TCP sous-jacente active afin que vous n’ayez pas à effectuer une nouvelle poignée de main TLS à chaque requête. La session est intégrée à Requests, il n’y a donc rien de supplémentaire à installer.
session = requests.Session()
session.proxies = proxies
session.headers.update({"User-Agent": "my-scraper/1.0"})
session.post("https://example.com/login", data={"u": "alice", "p": "secret"})
dashboard = session.get("https://example.com/dashboard") # cookies persist
print(dashboard.status_code, len(dashboard.content))La même session couvre .text, .json(), et .content, de sorte que les téléchargements de texte, JSON et binaires transitent tous par le même proxy de session Python Requests sans reconfiguration.
Utilisez des proxys SOCKS5 via requests[socks]
Requests ne prend pas en charge SOCKS par défaut. Intégrez PySocks avec l'option socks extra :
pip install "requests[socks]"Utilisez ensuite le socks5h:// scheme. Le suffixe h indique à PySocks de résoudre le DNS via le proxy plutôt que localement, ce qui est ce que vous souhaitez lorsque vous ne faites pas confiance au résolveur de votre FAI ou que vous passez par Tor.
proxies = {
"http": "socks5h://127.0.0.1:9050", # Tor default
"https": "socks5h://127.0.0.1:9050",
}
requests.get("https://check.torproject.org/", proxies=proxies, timeout=15)Plain socks5:// résout le DNS localement et divulgue discrètement les noms d'hôtes que vous visitez.
Faites tourner les proxys pour éviter les interdictions et les limitations de débit
Une seule adresse IP est soumise à une limitation de débit et finit par être bloquée. La véritable solution pour utiliser des proxys avec Python Requests à grande échelle est la rotation, et les trois sous-sections suivantes présentent des modèles de maturité croissante.
Rotation aléatoire avec une boucle de réessai
Le modèle le plus simple consiste à random.choice une liste de proxys, encapsulée dans une boucle de réessai :
import random, requests
from requests.exceptions import RequestException
PROXIES = [{"http": p, "https": p} for p in PROXY_URLS]
def fetch(url, attempts=4):
for _ in range(attempts):
proxy = random.choice(PROXIES)
try:
return requests.get(url, proxies=proxy, timeout=10)
except RequestException:
continue
raise RuntimeError("all attempts failed")Cela fonctionne, mais le hasard pur sélectionne allègrement des proxys inactifs à plusieurs reprises et ignore la charge.
Choix par puissances de deux pour un équilibrage de charge plus intelligent
Une amélioration bien étudiée consiste à utiliser des choix de type « puissance de deux » : pour chaque requête, on tire au sort deux proxys et on utilise celui qui traite actuellement le moins d'appels en cours. L'intuition, étayée par la littérature sur l'équilibrage de charge et généralement attribuée à l'analyse de Mitzenmacher de 2001, est que cela atténue bien mieux la charge dans le pire des cas qu'un aléatoire uniforme, tout en restant peu coûteux.
import random
LOAD = {p: 0 for p in PROXY_URLS}
def pick():
a, b = random.sample(PROXY_URLS, 2)
return a if LOAD[a] <= LOAD[b] else bIncrément LOAD[proxy] avant la requête et décrémenter après. Les gains exacts dépendent de la taille du pool ; effectuez des tests de performance avant de citer des chiffres.
Ajoutez un disjoncteur pour que les proxys inactifs cessent de gaspiller des requêtes
Les méthodes aléatoire et « puissance de deux » continuent toutes deux à sélectionner un proxy inactif jusqu’à ce qu’il réussisse. Un disjoncteur résout ce problème. Suivre l’état par proxy : CLOSED (en état de marche), OPEN (ignoré) et HALF_OPEN (en période d'essai).
import time
state = {p: {"fail": 0, "open_until": 0} for p in PROXY_URLS}
MAX_FAILS, COOLDOWN = 3, 60
def usable(p):
return time.time() >= state[p]["open_until"]
def record(p, ok):
if ok:
state[p]["fail"] = 0
else:
state[p]["fail"] += 1
if state[p]["fail"] >= MAX_FAILS:
state[p]["open_until"] = time.time() + COOLDOWNAprès le délai de refroidissement, envoyez une requête à titre probatoire au proxy avant de le réactiver complètement.
Réessayer les requêtes ayant échoué avec HTTPAdapter et urllib3 Réessayer
Montage d'un HTTPAdapter avec une urllib3 Retry politique sur une session applique des tentatives de réessai à chaque appel HTTP et HTTPS provenant de cette session. Épingler urllib3 (par exemple, urllib3==2.2.*) afin que les noms des paramètres restent stables lors des mises à jour.
from requests import Session
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
retry = Retry(
total=3,
status_forcelist=[429, 500, 502, 503, 504],
backoff_factor=2,
allowed_methods=["GET", "POST"],
respect_retry_after_header=True,
)
adapter = HTTPAdapter(max_retries=retry)
s = Session()
s.mount("http://", adapter)
s.mount("https://", adapter)Avec backoff_factor=2, urllib3 attend environ backoff_factor * (2 ** (n - 1)) secondes entre chaque tentative (environ 2, 4, 8 s). Combinez les tentatives avec la rotation afin que chaque nouvelle tentative sélectionne également un nouveau proxy.
Gérer la vérification SSL et les certificats de proxy auto-signés
Si un proxy présente un certificat auto-signé, verify=False cela désactive l'avertissement mais vous expose à des attaques de type « man-in-the-middle » ; utilisez donc cette option uniquement sur des proxys locaux de confiance ou lors de tests. La solution la plus sûre consiste à ajouter le proxy ou le bundle d'autorités de certification d'entreprise au magasin de confiance via verify="/path/to/ca.pem" ou REQUESTS_CA_BUNDLE. Ne InsecureRequestWarning qu'après avoir délibérément fait ce compromis de sécurité.
Quand abandonner le pool de proxys DIY au profit d'une API de scraping gérée
Passez en revue cette liste de contrôle. Si vous cochez trois cases ou plus, un proxy géré ou une API de scraping est généralement plus économique que le temps que vous y consacreriez :
- Vous avez besoin d'un ciblage géographique dans plus de deux pays.
- Les interdictions entraînent une perte de revenus réelle, et pas seulement une nouvelle tentative.
- Les cibles affichent du contenu avec JavaScript.
- Un ingénieur senior passe une journée par semaine à surveiller le pool.
- La conformité exige des adresses IP résidentielles auditées.
Points clés
- La réponse la plus concise à la question de savoir comment utiliser des proxys avec Python Requests est un dictionnaire mappant
httpethttpsà une URL de proxy, transmise viaproxies=avec untimeout. - Ne pas inclure les identifiants dans le code source : privilégiez
HTTP_PROXY,HTTPS_PROXY, etNO_PROXYdes variables d'environnement, et en codant les caractères spéciaux des mots de passe en URL. - Un
requests.Sessionconserve les proxys, les en-têtes et les cookies, et réutilise les connexions TCP, ce qui constitue le bon comportement par défaut pour tout workflow à appels multiples. - La rotation en production associe des choix de type « puissance de deux » à un disjoncteur et à une
HTTPAdapterRetrypolitique qui résiste aux codes 429 et 5xx. - Pour SOCKS5, installez
requests[socks]et utilisezsocks5h://afin que la résolution DNS s'effectue via le proxy au lieu de fuiter localement.
Ressources WebScrapingAPI associées
FAQ
Python Requests prend-il en charge les proxys SOCKS5 dès l'installation ?
Non. L'installation de base requests ne prend en charge que les protocoles HTTP et HTTPS. Exécutez pip install "requests[socks]" pour installer PySocks, puis utilisez une socks5:// ou, de préférence, socks5h:// une URL dans votre proxies dict. C'est la méthode la plus propre pour prendre en charge SOCKS.
Pourquoi mes requêtes transitant par le proxy continuent-elles de révéler ma véritable adresse IP via les requêtes DNS ?
Parce que le socks5:// schéma indique à PySocks de résoudre les noms d'hôte localement avant de tunnelliser la connexion. Passez à socks5h://, où le h signifie une résolution de nom d'hôte à distance, de sorte que les requêtes DNS transitent par le serveur SOCKS. Cela est particulièrement important pour Tor ou tout autre modèle de menace où votre résolveur DNS n'est pas fiable ou fait l'objet d'un enregistrement.
Comment encoder en URL un mot de passe de proxy contenant les caractères @, : ou % ?
Utilisez urllib.parse.quote de la bibliothèque standard : quote("p@ss:w/rd%1") devient p%40ss%3Aw%2Frd%251. Intégrez la valeur encodée dans http://user:encoded_pwd@host:port. Sans encodage, ces caractères mettent fin prématurément au segment d'informations utilisateur, et vous obtiendrez une erreur 407 Proxy Authentication Required même si le mot de passe est techniquement correct.
Comment indiquer à Python Requests d'ignorer le proxy pour localhost ou les domaines internes ?
Définissez NO_PROXY sur une liste séparée par des virgules d'hôtes ou de suffixes de domaine, par exemple NO_PROXY="localhost,127.0.0.1,.internal,.svc.cluster.local". Requests respecte les variantes en majuscules et minuscules sur les systèmes POSIX. Pour les remplacements par appel, passez proxies={"http": None, "https": None} pour contourner tout proxy au niveau de la session.
Quand dois-je passer d'un pool de proxys rotatifs DIY à une API de scraping gérée ?
Lorsque les coûts opérationnels dépassent la facture. Exemple concret : les interdictions coûtent plus cher qu’une nouvelle tentative, vous avez besoin d’adresses IP résidentielles dans plusieurs pays, les cibles font un usage intensif de JavaScript, ou vous passez plus de quelques heures d’ingénierie par semaine à régler le pool. En dessous de ce seuil, un petit pool DIY avec des tentatives de reconnexion et un disjoncteur suffit généralement.
Conclusion
Savoir utiliser les proxys avec Python Requests relève moins d'une astuce unique que d'une approche par couches : un proxies dict pour commencer, des identifiants dans des variables d'environnement pour que les secrets restent hors de git, un Session pour la réutilisation des connexions et les cookies, socks5h:// lorsque les fuites DNS posent problème, et une rotation avec des tentatives de reconnexion lorsqu’une seule adresse IP ne suffit plus. Associez des choix de type « puissance de deux » à un disjoncteur et à une HTTPAdapter Retry politique, et votre scraper cessera de s'effondrer dès qu'un proxy sera hors service ou qu'une cible renverra des erreurs 429.
À un moment donné, chaque équipe atteint le seuil où l'exploitation du pool coûte plus cher que la valeur des données. Si vos cibles sont fortement protégées, géolocalisées ou rendues en JavaScript, une option gérée comme l'API WebScrapingAPI Scraper gère la couche de requêtes, la rotation et le déblocage derrière un seul point de terminaison, ce qui vous permet de conserver le code d'analyse que vous avez déjà écrit et de simplement remplacer l'étape de récupération. Utilisez la liste de contrôle ci-dessus pour prendre votre décision ; si trois cases ou plus sont cochées, le calcul fait pencher la balance en faveur d'une infrastructure gérée plutôt que d'un nouveau sprint de maintenance du pool. Quoi qu'il en soit, les modèles présentés dans ce guide devraient permettre à votre requests- en bon état, du prototype à la production.




