Votre spider Scrapy cartonne sur 100 pages de test, puis s’écroule à 10 000. Ce n’est pas vraiment un bug de scraping — c’est un problème réseau déguisé en bug de scraping. La solution que tout le monde sort, c’est un proxy, et l’ajouter dans request.meta prend à peine trente secondes.
Le souci, c’est que ce correctif express, c’est aussi là où s’arrêtent la plupart des tutos de base. Ils montrent meta={"proxy": "http://IP:PORT"}, parfois une classe de middleware, puis passent à autre chose. Ils oublient souvent ce qui se passe quand ce proxy tombe au milieu du crawl, comment les identifiants finissent dans l’historique Git, ou pourquoi une nouvelle tentative peut réutiliser le même proxy défaillant. Ce guide couvre justement les vrais sujets de prod : configuration en mode fail-closed, gestion des secrets, sélection volontaire du proxy lors des retries, limites de protocole et arbitrages de coûts mesurables.
Qu’est-ce qu’un proxy middleware dans Scrapy ?
Un proxy middleware est un bout de code qui s’insère dans le pipeline de téléchargement de Scrapy et décide quelle adresse IP doit apparaître comme source d’une requête avant son envoi sur le réseau. Scrapy fournit déjà un middleware intégré, HttpProxyMiddleware, qui lit une clé proxy dans request.meta, ajoute l’authentification du proxy si besoin, puis transmet la requête au gestionnaire de téléchargement qui ouvre réellement la connexion. Un middleware proxy personnalisé ne remplace pas cette étape de transport — il agit comme un sélecteur qui choisit quel proxy utiliser avant que la mécanique intégrée prenne le relais. Cette distinction compte beaucoup plus qu’on ne le pense, et elle explique la plupart des retours du genre « mon middleware personnalisé ne marche pas ».
Pourquoi les proxies comptent dans les projets Scrapy de production
Un proxy modifie le chemin réseau et l’IP source apparente. Cela peut servir pour des tests géolocalisés légitimes, répartir un trafic de requêtes autorisé, et isoler des pannes réseau. Cela n’accorde aucune permission, ne contourne pas les limites de taux et ne garantit pas l’accès. Qu’un crawl ait besoin d’un proxy dépend de la cible, de ses conditions d’utilisation, du rythme des requêtes et des exigences de fiabilité du boulot.
Tous les proxies ne se valent pas, et choisir le mauvais niveau, c’est déjà un incident de prod en puissance :
| Type de proxy | Fiabilité | Vitesse | Risque de détection | Coût typique |
|---|---|---|---|---|
| Proxies publics gratuits | Très variable | Variable | Souvent élevé | Gratuit, mais avec un vrai risque opérationnel et de sécurité |
| Proxies datacenter | Dépend du fournisseur et de la cible | Souvent rapide | Dépend de la cible | Souvent facturé au Go ou à l’adresse IP |
| Proxies résidentiels | Dépend du fournisseur et de la cible | Variable | Dépend de la cible | Souvent facturé au Go |
| Proxies ISP | Dépend du fournisseur et de la cible | Variable | Dépend de la cible | Dépend du fournisseur |
Les proxies gratuits méritent qu’on s’y attarde, parce que les risques mesurés sont importants. L’étude sur 30 mois Free Proxies Unmasked a suivi plus de 640 000 adresses issues de 11 fournisseurs : 34,5 % ont été actives au moins une fois, et 16 923 ont manipulé le contenu. Cette population justifie un gros avertissement sécurité pour les listes publiques ; ce n’est pas un taux d’échec universel valable pour toute liste actuelle, tout pool payant, toute cible ou toute charge de travail.
Les proxies ne contournent pas magiquement les systèmes modernes de détection des bots. Des services comme Cloudflare évaluent les requêtes à partir de dizaines de signaux — empreintes TLS, cohérence des en-têtes, exécution JavaScript, schémas comportementaux — où l’adresse IP n’est qu’une donnée parmi d’autres. Un proxy résidentiel propre, associé à des en-têtes incohérents et sans cookie jar, peut quand même être signalé. Garde ça en tête avant de construire toute une architecture sur l’idée de « juste faire tourner l’IP ».
Avant de commencer
- Niveau : intermédiaire
- Temps requis : environ 30 à 45 minutes pour la configuration complète en production, environ 5 minutes pour le test rapide
- Prérequis : Python 3.9+, Scrapy installé (ce guide est testé avec Scrapy 2.17.0, publié en juillet 2026), un spider fonctionnel issu de
scrapy startproject, et au moins un endpoint proxy (un essai gratuit chez n’importe quel fournisseur de proxies datacenter convient très bien pour les tests)
Étape 1 : tester un proxy avec le paramètre Request Meta
Le moyen le plus rapide de vérifier qu’un proxy fonctionne est de contourner toute l’architecture de middleware et de l’essayer directement.
Le HttpProxyMiddleware intégré à Scrapy lit une clé proxy directement depuis request.meta et route la requête à travers ce proxy. Aucun changement de configuration, aucune classe de middleware — juste un couple clé/valeur.
import scrapy
class ProxyTestSpider(scrapy.Spider):
name = "proxy_test"
start_urls = ["https://httpbin.org/ip"]
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(
url,
meta={"proxy": "http://203.0.113.10:8080"},
callback=self.parse,
)
def parse(self, response):
self.logger.info(response.text)
Lance-le avec scrapy runspider proxy_test.py. Si le proxy marche, httpbin.org/ip renverra l’adresse IP du proxy au lieu de la tienne — c’est ta confirmation. Si la réponse reste bloquée puis finit par lever une erreur TCP connection timed out, le proxy est mort ou inaccessible, ce qui, spoiler, arrive bien plus souvent que les fournisseurs de proxies ne l’admettent.
Cette méthode convient pour un spider ponctuel ou des tests rapides. Elle devient vite ingérable dès que tu as plus d’un spider, parce que tu te retrouves à copier la même chaîne de proxy dans cinq fichiers différents.
Étape 2 : créer un middleware proxy personnalisé
Pour tout projet un peu plus sérieux qu’un spider unique, il faut centraliser la logique de proxy en un seul endroit. Crée une classe ProxyMiddleware dans le fichier middlewares.py de ton projet :
from scrapy.exceptions import NotConfigured
class ProxyMiddleware:
def __init__(self, proxy_url):
self.proxy_url = proxy_url
@classmethod
def from_crawler(cls, crawler):
proxy_url = crawler.settings.get("PROXY_URL")
if not proxy_url:
raise NotConfigured("PROXY_URL is required; refusing silent direct fallback")
return cls(proxy_url=proxy_url)
def process_request(self, request, spider):
if "proxy" not in request.meta:
request.meta["proxy"] = self.proxy_url
Puis enregistre-la dans settings.py :
import os
PROXY_URL = os.environ.get("PROXY_URL")
DOWNLOADER_MIDDLEWARES = {
"myproject.middlewares.ProxyMiddleware": 350,
}
Note l’usage de la méthode de classe from_crawler plutôt qu’un simple __init__. C’est le modèle recommandé par Scrapy pour lire les paramètres, et c’est exactement le point d’entrée qu’on réutilisera à l’étape 4 pour parler des secrets. L’avantage est simple : change un seul paramètre et tous les spiders du projet prennent le nouveau proxy. Plus besoin de fouiller dans cinq fichiers pour remplacer une IP devenue inutilisable.
Étape 3 : comprendre l’ordre d’exécution des middlewares pour éviter que ton proxy ne serve à rien sans prévenir
Voici la partie que presque tous les autres tutos passent sous silence avec un vague « mets juste la priorité à 350, fais-moi confiance ». Les downloader middlewares de Scrapy s’exécutent dans un ordre précis et prévisible, et si tu ne le comprends pas, ta config proxy va produire des bugs qui sembleront n’avoir rien à voir avec les proxies.
Les hooks côté requête (process_request) s’exécutent par ordre de priorité croissant — le plus petit numéro d’abord. Les hooks côté réponse (process_response, process_exception) s’exécutent par ordre décroissant — le plus grand numéro d’abord, en remontant la chaîne.
Flux des requêtes (croissant) :
Spider → [100] RobotsTxt → [300] HttpAuth → [350] VOTRE PROXY MIDDLEWARE
→ [500] UserAgent → [550] Retry → [700] Cookies → [750] HttpProxy
→ Downloader
Flux des réponses (décroissant) :
Downloader → [750] HttpProxy → [700] Cookies → [550] Retry
→ [500] UserAgent → [350] VOTRE PROXY MIDDLEWARE → [300] HttpAuth
→ [100] RobotsTxt → Spider
Voici le tableau réel et actuel des priorités par défaut des middlewares intégrés de Scrapy (vérifié avec la version 2.17.0) :
| Middleware | Priorité par défaut |
|---|---|
| RobotsTxtMiddleware | 100 |
| HttpAuthMiddleware | 300 |
| DownloadTimeoutMiddleware | 350 |
| DefaultHeadersMiddleware | 400 |
| UserAgentMiddleware | 500 |
| RetryMiddleware | 550 |
| RedirectMiddleware | 600 |
| CookiesMiddleware | 700 |
| HttpProxyMiddleware | 750 |
| DownloaderStats | 850 |
| HttpCacheMiddleware | 900 |
Quand RetryMiddleware programme une nouvelle tentative, il copie la requête en échec — y compris ses métadonnées — et cette nouvelle requête réintègre la chaîne des middlewares du downloader. Le simple fait d’être placé numériquement à côté de 550 ne garantit pas la rotation. La rotation n’a lieu que si le code du sélecteur reconnaît le retry et écrase volontairement la valeur meta["proxy"] copiée. La priorité 350 est un bon emplacement pour un sélecteur parce qu’elle s’exécute avant l’étape de transport intégrée à 750, mais ce n’est pas un mécanisme de rotation en soi.

Erreurs fréquentes d’ordre des middlewares
- Mettre ton middleware à la même priorité que
HttpProxyMiddleware(750) : cela crée une condition de course où c’est l’ordre des dictionnaires de Scrapy, et non ta logique, qui décide quel middleware traite la requête en premier. Symptôme : comportement de proxy intermittent et incompréhensible. - Utiliser
setdefault()ouif "proxy" not in request.metadans un sélecteur rotatif : la requête retry copiée garde l’ancien proxy. Symptôme : chaque retry refait le même chemin d’échec. Correction : détecte un retry (par exemple,retry_times > 0) et remplace explicitement la valeur de proxy gérée par le sélecteur. - Désactiver complètement
HttpProxyMiddleware: certains tutos conseillent de mettre"scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": Noneparce que « le middleware personnalisé gère tout ». Ce n’est pas le cas — ton middleware personnalisé est un sélecteur, pas une couche de transport. Désactiver le middleware intégré empêche l’ajout des en-têtes d’authentification proxy, et tes requêtes partent alors sans authentification (ou ne partent pas du tout).
Étape 4 : arrêter de coder en dur les identifiants du proxy
Tous les tutos Scrapy bien classés que j’ai trouvés écrivent http://username:password@proxy.example.com:8080 directement dans un fichier Python. C’est un identifiant qui reste à vie dans l’historique Git, visible dans chaque clone, chaque fork, et dans chaque dump de logs si quelqu’un utilise des print() à la légère.
En pratique, il existe trois façons de faire, de la pire à la meilleure :
| Méthode | Sécurité | Flexibilité | Idéal pour |
|---|---|---|---|
| Codé en dur dans spider/settings.py | Faible — les secrets vivent dans le dépôt | Faible | Uniquement des tests locaux rapides |
Variable d’environnement http_proxy (native Scrapy) | Mieux — hors du code | Faible (un seul proxy) | Pipelines CI/CD, Docker |
Fichier .env + python-dotenv + from_crawler | Le mieux — hors du code, par environnement | Élevée (plusieurs proxies, rotation) | Scrapers de production |
La troisième option mérite d’être mise en place correctement. Installe python-dotenv, crée un fichier .env (et ajoute-le tout de suite à .gitignore — vraiment, fais-le maintenant) :
PROXY_USER=myuser
PROXY_PASSWORD=my$ecret!Pass
PROXY_HOST=proxy.example.com
PROXY_PORT=8080
Charge-le en haut de settings.py :
from dotenv import load_dotenv
import os
load_dotenv()
PROXY_USER = os.getenv("PROXY_USER")
PROXY_PASSWORD = os.getenv("PROXY_PASSWORD")
PROXY_HOST = os.getenv("PROXY_HOST")
PROXY_PORT = os.getenv("PROXY_PORT")
Puis lis ces valeurs de façon sûre dans ton middleware via from_crawler — c’est le modèle qui résout exactement la confusion que j’ai souvent vue sur les forums, quand des gens demandent « comment définir ça avant de lancer scrapy crawl si les identifiants changent à chaque exécution ? » :
import os
from urllib.parse import quote
class SecureProxyMiddleware:
def __init__(self, user, password, host, port):
self.user = quote(user, safe="")
self.password = quote(password, safe="")
self.host = host
self.port = port
@classmethod
def from_crawler(cls, crawler):
settings = crawler.settings
return cls(
user=settings.get("PROXY_USER"),
password=settings.get("PROXY_PASSWORD"),
host=settings.get("PROXY_HOST"),
port=settings.get("PROXY_PORT"),
)
def process_request(self, request, spider):
proxy_url = f"http://{self.user}:{self.password}@{self.host}:{self.port}"
request.meta["proxy"] = proxy_url
Remarque l’appel à urllib.parse.quote() autour des identifiants. Si ton mot de passe contient un @, un : ou un / (et les générateurs de mots de passe adorent en mettre), l’analyse de l’URL cassera si la valeur n’est pas d’abord encodée en pourcentage. C’est une ligne de code qui t’épargne une heure pénible à déboguer des erreurs du type « invalid proxy URL » qui n’ont rien à voir avec un proxy réellement invalide.
Garde les identifiants hors des logs et teste l’encodage en pourcentage avec des valeurs représentatives — mais fictives. Le tunneling HTTPS, SOCKS5 et les identifiants non latins ont des limites propres à chaque handler ; ne suppose pas qu’un schéma d’authentification fonctionne partout sans test d’intégration figé.

Étape 5 : ajouter la rotation de proxies
Un seul proxy — même bon — qui envoie 5 000 requêtes vers le même site finira tôt ou tard signalé. Il te faut un pool.
Option A — le construire toi-même. C’est franchement simple :
import random
class RotatingProxyMiddleware:
def __init__(self, proxy_pool):
self.proxy_pool = proxy_pool
@classmethod
def from_crawler(cls, crawler):
return cls(proxy_pool=crawler.settings.getlist("PROXY_POOL"))
def process_request(self, request, spider):
request.meta["proxy"] = random.choice(self.proxy_pool)
Ça marche pour un usage basique, mais sans aucune connaissance des proxies réellement actifs. Tu tires à pile ou face à chaque requête.
Option B — utiliser scrapy-rotating-proxies. Ce package tiers ajoute la détection des blocages et le backoff automatique par défaut :
pip install scrapy-rotating-proxies
Je vais être honnête sur un point : la dernière version sur PyPI est la 0.6.2, datée de 2019, et le projet est marqué Alpha. Ce n’est pas forcément cassé sur les versions modernes de Scrapy, mais « pas maintenu activement depuis 2019 » n’est pas la même chose que « éprouvé pour du trafic de production en 2026 ». Pointez la version, testez-la sur tes vraies cibles et ne suppose pas qu’elle gère les endpoints proxy authentifiés — elle le fait assez mal.
Étape 6 : construire un middleware proxy tolérant aux pannes (détection des proxies morts)
C’est la section que les tutos concurrents sautent complètement, et c’est ce qui sépare une démo d’un système capable de survivre à un crawl de 6 heures sans supervision.
| Scénario | Ce que montrent la plupart des tutoriels | Ce qu’ajoute ce middleware |
|---|---|---|
| Le proxy renvoie 407 | Non traité | Le considère comme un échec d’authentification du proxy |
| La cible renvoie 403/429 | Souvent regroupé | Sépare les retours liés à la politique / au taux de l’état du proxy |
| Le proxy expire / time out | Non traité | Seuil de timeout configurable, décroissance du score de santé |
| Tous les proxies sont morts | Non traité | Repli gracieux ou pause du crawl avec avertissement journalisé |
| Proxy instable (intermittent) | Non traité | Période de refroidissement avant réintégration dans le pool |
import time
import random
from scrapy.exceptions import IgnoreRequest
class FaultTolerantProxyMiddleware:
MAX_FAILURES = 3
COOLDOWN_SECONDS = 300
def __init__(self, proxy_pool):
self.pool = {p: {"failures": 0, "banned_until": 0} for p in proxy_pool}
@classmethod
def from_crawler(cls, crawler):
return cls(proxy_pool=crawler.settings.getlist("PROXY_POOL"))
def _healthy_proxies(self):
now = time.time()
return [p for p, s in self.pool.items() if s["banned_until"] < now]
def process_request(self, request, spider):
healthy = self._healthy_proxies()
if not healthy:
spider.logger.warning("Tous les proxies sont en mauvais état — pause du crawl")
raise IgnoreRequest("No healthy proxies available")
request.meta["proxy"] = random.choice(healthy)
def process_response(self, request, response, spider):
proxy = request.meta.get("proxy")
if proxy and response.status == 407:
self._mark_failure(proxy)
return response
def process_exception(self, request, exception, spider):
proxy = request.meta.get("proxy")
if proxy:
self._mark_failure(proxy)
def _mark_failure(self, proxy):
state = self.pool[proxy]
state["failures"] += 1
if state["failures"] >= self.MAX_FAILURES:
state["banned_until"] = time.time() + self.COOLDOWN_SECONDS
state["failures"] = 0
Quelques remarques issues du terrain : ne considère pas chaque 403 comme une preuve que le proxy est mort — RFC 9110 définit 403 comme « le serveur a compris mais refuse », ce qui peut tout aussi bien venir de tes en-têtes ou de ta session, indépendamment du proxy. Un 407, en revanche, signifie que le proxy rejette spécifiquement ton authentification — signal bien plus fort et plus précis. Mélanger ces signaux dans un seul panier pousse les gens à gaspiller des proxies parfaitement sains pour rien.
Garde explicites les valeurs de retry transitoires de Scrapy en production pour que la politique soit visible lors des revues :
RETRY_HTTP_CODES = [500, 502, 503, 504, 522, 524, 408, 429]
RETRY_TIMES = 2
Ce sont les valeurs par défaut de Scrapy 2.17. N’ajoute pas 403 ou 407 de manière générique : un 403 est un refus de la cible avec beaucoup de causes possibles, tandis qu’un 407 est un problème d’authentification du proxy que de simples retries de requête ne régleront pas. Si un contrat spécifique avec une cible justifie le retry d’un autre statut, documente cette raison et teste-la séparément.

Étape 7 : un schéma proxy-sur-retry mesuré
Certaines cibles autorisées peuvent renvoyer du contenu valide directement et n’avoir besoin d’un proxy qu’après une réponse transitoire documentée. Cela peut réduire le volume de données proxyfiées, mais il n’existe ni pourcentage d’économie universel défendable ni taux de réussite portable des requêtes directes. Mesure ta propre charge avant d’adopter ce schéma.
Utilise l’aide publique get_retry_request() de Scrapy et limite l’escalade aux statuts spécifiques à la cible que tu as explicitement classés. Cet exemple traite 429 et 503 comme signaux de pression réessayables ; il exclut volontairement 403 et 407.
from scrapy.downloadermiddlewares.retry import get_retry_request
class CostAwareEscalationMiddleware:
def process_response(self, request, response, spider):
if response.status not in {429, 503}:
return response
retry = get_retry_request(
request,
spider=spider,
reason=f"proxy_escalation_{response.status}",
max_retry_times=2,
)
if retry is None:
return response
current_tier = request.meta.get("proxy_tier", "direct")
if current_tier == "direct":
retry.meta["proxy"] = spider.settings["DATACENTER_PROXY"]
retry.meta["proxy_tier"] = "datacenter"
elif current_tier == "datacenter":
retry.meta["proxy"] = spider.settings["RESIDENTIAL_PROXY"]
retry.meta["proxy_tier"] = "residential"
else:
return response
return retry
Journalise le taux de contenu valide en direct, le taux de contenu valide via proxy, les octets par enregistrement réussi, le nombre de retries par succès et la latence ajoutée. Une architecture « direct d’abord » n’est acceptable que si l’accès direct est autorisé et que le système échoue en mode fermé dès qu’un proxy devient nécessaire. L’économie correspond à la réduction mesurée du trafic proxyfié — pas à un pourcentage supposé.
Quand la gestion manuelle des proxies ne vaut plus le coup
Je préfère être franc plutôt que de faire semblant que tout le reste de cet article était inutile : tout ce qui précède relève d’une vraie ingénierie utile, et pour beaucoup de projets — crawls à gros volume, pipelines sur mesure, tout ce qui exige un contrôle fin du scheduling des requêtes — c’est la bonne approche.
Mais si ton vrai objectif, c’est « obtenir des données structurées à partir de cette page » plutôt que « gérer une infrastructure de proxies », une API d’extraction peut être une meilleure frontière. La documentation actuelle de POST /extract de Thunderbit accepte une URL de page et un schéma JSON optionnel ; lorsque le schéma est omis, le service peut en générer un à partir du contenu de la page. L’endpoint expose aussi les modes de rendu none, basic et full, ainsi que des contrôles de timeout et d’attente après chargement. L’extraction uniquement par prompt ne fait pas partie de la surface de requête actuellement prise en charge ; construis donc tes intégrations de prod autour du contrat de schéma documenté. Cela met l’interface d’extraction derrière une seule requête ; ça ne justifie pas une promesse universelle face à tous les sites anti-bot ou CAPTCHA.
| Facteur | Scrapy + proxies en propre | Extraction via API (par ex. Thunderbit) |
|---|---|---|
| Effort de mise en place | Élevé — middleware, rotation, logique de retry | Faible — un appel API avec un schéma |
| Comportement réseau / rendu | Tu configures handlers, proxies, en-têtes et délais | Contrôlé via les options documentées de l’API |
| Maintenance | Tu gères les sélecteurs, la santé du pool et les évolutions de cible | Tu gères la qualité du schéma, la validation et le comportement d’intégration |
| Modèle de coût | Frais de proxy + calcul + temps d’ingénierie | La documentation actuelle indique 20 unités par page (vérifié le 2026-08-10) |
| Contrôle | Total — pipelines personnalisés, chaîne de middlewares | Limité aux capacités de l’API |
| Idéal pour | Crawls complexes, gros volume, logique personnalisée | Extraction ciblée, prototypage, enrichissement |
Si tu extrais surtout des pages structurées pour des listes de prospects, des données produit ou de la recherche, lance un pilote représentatif avec la Thunderbit Chrome Extension ou l’API, puis compare le nombre d’enregistrements valides, la latence, les unités consommées et le temps de maintenance. Si ton projet demande des graphes de crawl personnalisés et un contrôle fin du pipeline, Scrapy reste la solution la plus solide.
En savoir plus
Conseils et pièges courants
- Conseil : teste les proxies avec
httpbin.org/ipavant de les pointer vers une vraie cible. C’est le moyen le plus rapide de confirmer que le routage fonctionne avant d’ajouter de la complexité. - Piège : définir un proxy dans
request.headersau lieu derequest.meta. C’est un bug très courant à la frontière de la faute de frappe —HttpProxyMiddlewarelit uniquementmeta["proxy"], et une tentative via les en-têtes échouera silencieusement sans erreur claire. - Piège : supposer que les proxies HTTP et HTTPS se configurent de la même manière. Une URL de proxy HTTP vers une destination HTTPS fonctionne généralement via un tunneling CONNECT avec un handler compatible, mais utiliser un schéma
https://pour le point de terminaison du proxy lui-même est une configuration différente, moins bien prise en charge — il ne faut pas les confondre. - Conseil : si tu as besoin du support SOCKS5, vérifie d’abord les capacités du download handler de ta version de Scrapy. Le handler
Httpxexpérimental de Scrapy 2.17 a ajouté le support SOCKS5 viahttpx[socks], mais il reste étiqueté expérimental — ne bâtis pas une dépendance de production dessus sans tes propres tests.
Méthodes alternatives
Au-delà de scrapy-rotating-proxies, certaines équipes font passer toute la logique proxy par une passerelle de fournisseur — une seule URL de proxy, tandis que le fournisseur gère en coulisses la rotation, la persistance des sessions et le ciblage géographique. Ça sacrifie un peu de contrôle pour bien moins de code middleware, et ça mérite d’être comparé en coût à un pool autogéré avant de tout construire de zéro.
Conclusion
Configurer un proxy dans Scrapy tient en une ligne. Faire en sorte que cette config survive à un vrai crawl de production demande une politique d’échec explicite, des identifiants protégés, des limites de handler testées et un code de sélection qui remplace volontairement les métadonnées de proxy copiées lors des retries. Si tu ne retiens que deux habitudes, garde celles-ci : échouer en mode fermé quand un proxy est requis, et ne jamais commettre un mot de passe de proxy dans un fichier Python.
FAQ
Comment configurer un proxy personnalisé dans Scrapy avec authentification ?
Utilise le format d’URL protocol://username:password@host:port, mais encode d’abord le nom d’utilisateur et le mot de passe avec urllib.parse.quote() s’ils contiennent des caractères spéciaux. En production, lis ces identifiants via une méthode de classe from_crawler alimentée par des variables d’environnement plutôt que de les écrire en dur.
Quel numéro de priorité utiliser pour mon middleware proxy personnalisé dans Scrapy ?
350 est une priorité de sélecteur courante, car elle s’exécute avant HttpProxyMiddleware à 750. Cela ne garantit pas la rotation. Une nouvelle tentative ne reçoit un proxy frais que si le sélecteur reconnaît la requête retry copiée et remplace sa valeur meta["proxy"] précédente.
Comment gérer automatiquement les proxies morts dans Scrapy ?
Construis un middleware qui suit le nombre d’échecs par proxy dans process_response et process_exception, retire les proxies du pool actif après un seuil d’échec, puis les réintroduit après une période de refroidissement au lieu de les bannir définitivement.
Puis-je utiliser Scrapy avec des proxies SOCKS5 ?
Le HttpxDownloadHandler expérimental de Scrapy 2.17 documente le support SOCKS5 lorsque httpx[socks] est installé. Le handler HTTP/1.1 par défaut ne prend pas en charge les proxys SOCKS. Verrouille la version/handler et exécute un test d’intégration avant de considérer cette voie comme prête pour la production.
Combien le schéma proxy-sur-retry peut-il réellement économiser sur les coûts de proxy ? Il n’existe pas de pourcentage portable. Mesure la part des requêtes autorisées qui renvoient un contenu valide en direct, les octets envoyés par chaque niveau de proxy, les retries par enregistrement réussi et la latence ajoutée. La réduction observée du trafic proxyfié constitue ton économie ; si l’accès direct d’abord n’est pas autorisé ou ne fonctionne pas, n’utilise pas ce schéma.


