Comment configurer un proxy personnalisé dans Scrapy (prêt pour la production)

Dernière mise à jour le August 11, 2026
Hand-drawn Scrapy crawler routing through a proxy pool, retrying a 503 route and completing through a 200 route
Résumé IA
- Construire un middleware proxy Scrapy personnalisé qui attribue des routes approuvées, ajoute l’authentification en toute sécurité, consigne les raisons d’échec et préserve les métadonnées de requête lors des retries. - Comprendre l’ordre d’exécution des middlewares de téléchargement, en particulier l’interaction entre la logique proxy personnalisée, HttpProxyMiddleware, RetryMiddleware, les redirections et la gestion des exceptions. - Ajouter une rotation avec des tentatives bornées, des périodes de refroidissement, un état de santé des proxies et des politiques adaptées à la cible au lieu de choisir un proxy aléatoire pour chaque requête. - Distinguer les échecs d’authentification proxy, les erreurs de connexion, les problèmes DNS, les réponses 403 de la cible et les limites de débit afin que chaque cas reçoive le traitement approprié. - Mettre en place des garde-fous de production pour le stockage des secrets, la concurrence, l’observabilité, la cohérence des sessions et un comportement fail-closed lorsqu’aucun proxy approuvé n’est disponible.

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 proxyFiabilitéVitesseRisque de détectionCoût typique
Proxies publics gratuitsTrès variableVariableSouvent élevéGratuit, mais avec un vrai risque opérationnel et de sécurité
Proxies datacenterDépend du fournisseur et de la cibleSouvent rapideDépend de la cibleSouvent facturé au Go ou à l’adresse IP
Proxies résidentielsDépend du fournisseur et de la cibleVariableDépend de la cibleSouvent facturé au Go
Proxies ISPDépend du fournisseur et de la cibleVariableDépend de la cibleDé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) :

MiddlewarePriorité par défaut
RobotsTxtMiddleware100
HttpAuthMiddleware300
DownloadTimeoutMiddleware350
DefaultHeadersMiddleware400
UserAgentMiddleware500
RetryMiddleware550
RedirectMiddleware600
CookiesMiddleware700
HttpProxyMiddleware750
DownloaderStats850
HttpCacheMiddleware900

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.

Trajets des requêtes et réponses Scrapy à travers les priorités 350, 550 et 750, avec un retry 503 qui réintègre la chaîne de middlewares

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() ou if "proxy" not in request.meta dans 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": None parce 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éthodeSécuritéFlexibilitéIdéal pour
Codé en dur dans spider/settings.pyFaible — les secrets vivent dans le dépôtFaibleUniquement des tests locaux rapides
Variable d’environnement http_proxy (native Scrapy)Mieux — hors du codeFaible (un seul proxy)Pipelines CI/CD, Docker
Fichier .env + python-dotenv + from_crawlerLe 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é.

Flux sécurisé allant d’un fichier d’environnement verrouillé vers des paramètres proxy encodés puis vers les métadonnées de requête Scrapy

É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énarioCe que montrent la plupart des tutorielsCe qu’ajoute ce middleware
Le proxy renvoie 407Non traitéLe considère comme un échec d’authentification du proxy
La cible renvoie 403/429Souvent regroupéSépare les retours liés à la politique / au taux de l’état du proxy
Le proxy expire / time outNon traitéSeuil de timeout configurable, décroissance du score de santé
Tous les proxies sont mortsNon 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.

Traitement distinct d’un échec d’authentification 407, d’un rate limiting 429, d’un retry 503, d’un succès 200 et d’une porte fermée quand les proxies ne sont pas disponibles

É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.

FacteurScrapy + proxies en propreExtraction via API (par ex. Thunderbit)
Effort de mise en placeÉlevé — middleware, rotation, logique de retryFaible — un appel API avec un schéma
Comportement réseau / renduTu configures handlers, proxies, en-têtes et délaisContrôlé via les options documentées de l’API
MaintenanceTu gères les sélecteurs, la santé du pool et les évolutions de cibleTu gères la qualité du schéma, la validation et le comportement d’intégration
Modèle de coûtFrais de proxy + calcul + temps d’ingénierieLa documentation actuelle indique 20 unités par page (vérifié le 2026-08-10)
ContrôleTotal — pipelines personnalisés, chaîne de middlewaresLimité aux capacités de l’API
Idéal pourCrawls complexes, gros volume, logique personnaliséeExtraction 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/ip avant 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.headers au lieu de request.meta. C’est un bug très courant à la frontière de la faute de frappe — HttpProxyMiddleware lit uniquement meta["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 Httpx expérimental de Scrapy 2.17 a ajouté le support SOCKS5 via httpx[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.

Ke
Ke
CTO chez Thunderbit | Data Scientist senior et expert en ML Forte d’une expérience de près de dix ans en machine learning et en data science, Ke Shen est diplômé de Columbia University et ancien Data Scientist senior chez Walmart Labs. Grâce à une expertise approfondie, reconnue par ses pairs, en Python, R, Java et statistiques, il partage des analyses éprouvées sur le passage d’algorithmes d’IA complexes de la théorie à une architecture prête pour la production.
Topics
middleware proxy Scrapyscraping web en Pythonrotation de proxy
Table des matières
Thunderbit · Agent de données web IA

Extrayez des données de n'importe quelle page en 1 clic

Approuvé par plus de 250 000 utilisateurs
plan gratuit disponible
Extraire des données avec l'IA
Transférez facilement des données vers Google Sheets, Airtable ou Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week