Rotation de proxies dans Colly : guide complet pour le web scraping en Go

Apprenez à implémenter une rotation de proxies dans Colly avec des proxies résidentiels ProxyHat. Couvre proxy.RoundRobinProxySwitcher, SetProxyFunc, sessions collantes, et patterns de production pour le scraping à grande échelle.

Rotating Proxies in Colly: A Framework-Idiomatic Guide for Go Developers
Dans cet article

La rotation de proxies dans Colly est la technique la plus efficace pour maintenir un throughput élevé lors du web scraping en Go sans se faire bloquer. Colly, le framework de scraping le plus populaire en Go, expose des points d'extension idiomatiques — notamment proxy.RoundRobinProxySwitcher et c.SetProxyFunc — qui s'intègrent naturellement dans son modèle de collecteur asynchrone. Ce guide vous montre comment configurer une rotation de proxies résidentiels via ProxyHat, gérer les sessions collantes par pays/ville, et déployer un scraper de production robuste.

Note légale : Le scraping de données publiques doit respecter le robots.txt, les conditions d'utilisation des sites, et les réglementations comme le RGPD en Europe et le CFAA aux États-Unis. Ce guide couvre des techniques techniques, pas des conseils juridiques.

Pourquoi la rotation de proxies dans Colly est indispensable

Colly est construit autour d'un modèle de Collector qui émet des requêtes HTTP asynchrones via un pool de goroutines. Chaque requête traverse une chaîne de callbacks : OnRequest, OnResponse, OnHTML, OnError. Le framework repose sur goquery pour la traversée du DOM, ce qui permet de sélectionner des éléments avec une syntaxe proche de jQuery.

Le problème : la plupart des sites modernes détectent les patterns de scraping en surveillant le volume de requêtes par adresse IP. Un scraper Colly sans rotation peut envoyer des centaines de requêtes par seconde depuis une seule IP. Les systèmes anti-bot comme Cloudflare, DataDome, ou PerimeterX bloquent généralement une IP après 50 à 200 requêtes dans un court intervalle. La rotation de proxies distribue ces requêtes sur des centaines ou milliers d'adresses IP, réduisant la charge par IP à un niveau indétectable.

Les proxies résidenti sont particulièrement efficaces car ils utilisent des adresses IP attribuées par des FAI réels (Orange, Comcast, Deutsche Telekom), ce qui les rend indiscernables du trafic humain normal. Les proxies datacenter, en revanche, sont souvent déjà flaggés par les listes de réputation IP.

Anatomie d'un Collector Colly

Avant de plonger dans la rotation, rappelons les composants clés du Collector Colly que nous allons exploiter :

  • OnRequest(func(*colly.Request)) — intercepte chaque requête avant l'envoi. Idéal pour injecter des headers personnalisés.
  • OnHTML(selector, func(*colly.HTMLElement)) — callback déclenché quand un sélecteur CSS matche dans la réponse.
  • OnError(func(*colly.Response, error)) — gère les erreurs HTTP et réseau, crucial pour les retries.
  • c.Async = true — active le mode asynchrone avec goroutines.
  • c.Limit(&colly.LimitRule{...}) — contrôle le taux de requêtes par domaine.
  • c.SetProxyFunc(func(*http.Request) (*url.URL, error)) — fonction appelée pour chaque requête pour déterminer le proxy à utiliser.

Proxy rotation idiomatique : RoundRobinProxySwitcher et SetProxyFunc

Colly fournit un package proxy avec un RoundRobinProxySwitcher prêt à l'emploi. Cette fonction retourne une colly.ProxyFunc qui alterne entre une liste de proxies de manière circulaire. C'est le point d'entrée le plus simple pour la rotation.

Exemple 1 : RoundRobinProxySwitcher basique avec ProxyHat

package main

import (
    "fmt"
    "log"
    "github.com/gocolly/colly/v2"
    "github.com/gocolly/colly/v2/proxy"
)

func main() {
    c := colly.NewCollector(
        colly.Async(true),
    )

    // Liste de proxies ProxyHat avec sessions différentes
    proxies := []string{
        "http://user-session-sess1:pass@gate.proxyhat.com:8080",
        "http://user-session-sess2:pass@gate.proxyhat.com:8080",
        "http://user-session-sess3:pass@gate.proxyhat.com:8080",
        "http://user-session-sess4:pass@gate.proxyhat.com:8080",
        "http://user-session-sess5:pass@gate.proxyhat.com:8080",
    }

    rp, err := proxy.RoundRobinProxySwitcher(proxies...)
    if err != nil {
        log.Fatal(err)
    }
    c.SetProxyFunc(rp)

    c.OnHTML("title", func(e *colly.HTMLElement) {
        fmt.Println("Titre:", e.Text)
    })

    c.OnError(func(r *colly.Response, err error) {
        fmt.Printf("Erreur sur %s: %v\n", r.Request.URL, err)
    })

    c.Limit(&colly.LimitRule{
        DomainGlob:  "*",
        Parallelism: 5,
        Delay:       2 * time.Second,
    })

    c.Visit("https://httpbin.org/ip")
    c.Wait()
}

Dans cet exemple, chaque requête utilise une session ProxyHat différente (sess1 à sess5), ce qui force le changement d'IP à chaque requête. Le LimitRule avec Parallelism: 5 et un délai de 2 secondes évite de saturer les cibles.

Géociblage et sessions collantes

ProxyHat permet de contrôler la géolocalisation et la persistance d'IP via le nom d'utilisateur. Pour un scraping ciblé sur l'Allemagne :

// Proxy résidentiel à Berlin
proxy := "http://user-country-DE-city-berlin-session-abc123:pass@gate.proxyhat.com:8080"

// Proxy résidentiel à Munich
proxy2 := "http://user-country-DE-city-munich-session-def456:pass@gate.proxyhat.com:8080"

// Proxy mobile au Royaume-Uni
proxy3 := "http://user-country-GB-session-ghi789:pass@gate.proxyhat.com:8080"

Le flag -session-abc123 garantit que toutes les requêtes utilisant cette session sortiront par la même IP résidentielle jusqu'à expiration. C'est essentiel pour les sites qui nécessitent une continuité de session (paniers, authentification, pagination stateful).

Proxy switcher personnalisé : contrôle total par requête

Le RoundRobinProxySwitcher est pratique mais limité. Pour un contrôle fin — par exemple, alterner les pays, gérer un pool dynamique d'IP, ou marquer les proxies défaillants — il faut implémenter une ProxyFunc personnalisée.

Exemple 2 : Proxy switcher personnalisé avec géorotation

package main

import (
    "fmt"
    "math/rand"
    "net/http"
    "net/url"
    "sync"
    "time"
    "github.com/gocolly/colly/v2"
)

type ProxyRotator struct {
    mu      sync.Mutex
    counter int
    countries []string
    baseUser  string
    password string
}

func (pr *ProxyRotator) NextProxy(req *http.Request) (*url.URL, error) {
    pr.mu.Lock()
    defer pr.mu.Unlock()

    country := pr.countries[pr.counter % len(pr.countries)]
    sessionID := fmt.Sprintf("sess-%d-%d", time.Now().Unix(), rand.Intn(9999))
    pr.counter++

    proxyURL := fmt.Sprintf("http://%s-country-%s-session-%s:%s@gate.proxyhat.com:8080",
        pr.baseUser, country, sessionID, pr.password)

    return url.Parse(proxyURL)
}

func main() {
    c := colly.NewCollector(colly.Async(true))

    rotator := &ProxyRotator{
        countries: []string{"DE", "FR", "GB", "US", "ES"},
        baseUser:  "user",
        password:  "pass",
    }

    c.SetProxyFunc(rotator.NextProxy)

    c.OnHTML("title", func(e *colly.HTMLElement) {
        fmt.Printf("[%s] %s\n", e.Request.AbsoluteURL(e.Request.URL.String()), e.Text)
    })

    c.OnError(func(r *colly.Response, err error) {
        fmt.Printf("Erreur: %v (status: %d)\n", err, r.StatusCode)
    })

    c.Limit(&colly.LimitRule{
        DomainGlob:  "*",
        Parallelism: 10,
        Delay:       500 * time.Millisecond,
    })

    for i := 0; i < 50; i++ {
        c.Visit("https://httpbin.org/ip")
    }
    c.Wait()
}

Ce switcher génère un identifiant de session unique à chaque appel, ce qui force ProxyHat à attribuer une nouvelle IP résidentielle dans un pays différent à chaque requête. Le mutex protège le compteur contre les accès concurrents puisque Colly exécute les callbacks en parallèle.

Support SOCKS5 et configuration TLS avancée

ProxyHat supporte également SOCKS5 sur le port 1080. SOCKS5 peut être préférable pour le scraping car il opère au niveau TCP et supporte n'importe quel protocole au-dessus. Pour utiliser SOCKS5 dans Colly :

import (
    "crypto/tls"
    "net/http"
    "net/url"
    "github.com/gocolly/colly/v2"
)

func main() {
    c := colly.NewCollector()

    // Proxy SOCKS5 ProxyHat
    proxyURL, _ := url.Parse("socks5://user-country-DE-session-sock1:pass@gate.proxyhat.com:1080")

    c.SetProxyFunc(func(req *http.Request) (*url.URL, error) {
        return proxyURL, nil
    })

    // Configuration TLS pour éviter les erreurs de certificat
    c.WithTransport(&http.Transport{
        Proxy: http.ProxyURL(proxyURL),
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: false,
            MinVersion:         tls.VersionTLS12,
        },
    })

    c.Visit("https://httpbin.org/ip")
}

Notez que InsecureSkipVerify: false est volontaire — en production, la validation TLS est essentielle pour la sécurité. Ne la désactivez que pour le débogage.

Patterns de production : retries, clonage, et scaling

Retries avec c.Clone()

Colly permet de cloner un Collector avec c.Clone(). Le clone hérite de la configuration mais peut avoir son propre proxy et ses propres callbacks. C'est idéal pour implémenter un retry avec un proxy différent :

func retryWithNewProxy(c *colly.Collector, url string, maxRetries int) {
    var attempt func(n int)
    attempt = func(n int) {
        if n >= maxRetries {
            log.Printf("Échec après %d tentatives: %s", maxRetries, url)
            return
        }

        clone := c.Clone()
        sessionID := fmt.Sprintf("retry-%d-%d", n, time.Now().UnixNano())
        proxyStr := fmt.Sprintf("http://user-session-%s:pass@gate.proxyhat.com:8080", sessionID)

        proxyURL, _ := url.Parse(proxyStr)
        clone.SetProxyFunc(func(req *http.Request) (*url.URL, error) {
            return proxyURL, nil
        })

        clone.OnError(func(r *colly.Response, err error) {
            if r.StatusCode == 403 || r.StatusCode == 429 {
                time.Sleep(time.Duration(n+1) * 2 * time.Second) // backoff exponentiel
                attempt(n + 1)
            }
        })

        clone.OnHTML("title", func(e *colly.HTMLElement) {
            fmt.Println("Succès après", n, "tentative(s):", e.Text)
        })

        clone.Visit(url)
        clone.Wait()
    }
    attempt(0)
}

Limites de parallélisme et délais aléatoires

Le LimitRule de Colly est votre première ligne de défense contre la détection :

d>0.5–2s
Paramètre Valeur recommandée Effet
Parallelism 5–20 Nombre de requêtes simultanées par domaine
Delay 1–3s Délai fixe entre requêtes vers le même domaine
RandomDelay Jitter aléatoire ajouté au délai, imite le comportement humain

Un RandomDelay de 1 seconde avec un Parallelism de 10 et 100 proxies en rotation donne un throughput d'environ 10 requêtes/seconde par domaine — suffisant pour la plupart des cas d'usage sans déclencher de protections.

Stockage distribué avec Redis

Pour un scraping distribué sur plusieurs instances, Colly supporte des backends de stockage comme Redis pour partager les cookies et l'état des URLs visitées :

import (
    "github.com/gocolly/colly/v2/storage"
    "github.com/gocolly/redisstorage"
)

func main() {
    c := colly.NewCollector()

    storage := &redisstorage.Storage{
        Address:  "redis://localhost:6379",
        Prefix:   "colly_scraper",
    }

    c.SetStorage(storage)

    // Les URLs visitées et les cookies sont maintenant partagés
    // entre toutes les instances connectées au même Redis
    c.Visit("https://example.com")
}

Ce pattern permet de déployer plusieurs conteneurs Docker, chacun exécutant un Collector Colly, tous connectés au même Redis. La déduplication des URLs et la distribution de charge sont gérées automatiquement.

Erreurs courantes et cas limites

1. Oublier c.Wait() en mode Async

En mode Async(true), c.Visit() retourne immédiatement. Sans c.Wait(), le programme principal se termine avant que les goroutines aient terminé. C'est l'erreur la plus fréquente chez les débutants Colly.

2. Ne pas gérer les erreurs 429 et 403

Un code 429 (Too Many Requests) ou 403 (Forbidden) signifie que l'IP actuelle est flaggée. Le bon réflexe : changer de session proxy et réessayer après un backoff, pas insister avec la même IP.

3. Surcharger les LimitRules

Un Parallelism trop élevé (50+) sans rotation de proxies suffisante va déclencher des blocages IP. La règle empirique : 1 proxy session active par requête parallèle, avec une marge de 20%.

4. Ignorer le type de contenu

Colly est conçu pour le HTML. Pour les APIs JSON, utilisez OnResponse au lieu de OnHTML. Pour les SPAs JavaScript (React, Vue, Angular), Colly ne suffira pas — il faut un navigateur headless comme playwright-go ou Rod.

Quand ne PAS utiliser Colly

Colly excelle pour le scraping de pages HTML statiques ou rendues côté serveur. Il atteint ses limites quand :

  • Le site est une SPA nécessitant l'exécution de JavaScript (React, Vue, Angular).
  • Le contenu est chargé via WebSocket ou Server-Sent Events.
  • Le site utilise des challenges CAPTCHA interactifs (hCaptcha, reCAPTCHA v3).
  • Le rendu nécessite une interaction utilisateur complexe (scroll infini, clics multiples).

Dans ces cas, combinez Colly avec un navigateur headless : utilisez Colly pour l'orchestration et la rotation de proxies, et déléguez le rendu à Playwright ou Chromium. Vous pouvez injecter le proxy ProxyHat directement dans la configuration du navigateur.

Configuration ProxyHat : checklist de production

Pour un déploiement en production avec ProxyHat et Colly, voici la configuration recommandée :

  • Endpoint HTTP : gate.proxyhat.com:8080 — utilisez ce port pour le trafic HTTP/HTTPS.
  • Endpoint SOCKS5 : gate.proxyhat.com:1080 — préférez SOCKS5 pour les connexions non-HTTP.
  • Rotation par requête : utilisez un session-ID unique à chaque requête pour forcer le changement d'IP.
  • Géociblage : ajoutez -country-XX et optionnellement -city-ville dans le nom d'utilisateur.
  • Pool de sessions : préparez au moins 50 sessions différentes pour un throughput de 10 req/s.
  • Monitoring : logguez le StatusCode et l'IP de sortie pour détecter les dégradations.

Consultez la documentation ProxyHat pour la liste complète des paramètres de géociblage et les limites de concurrency par plan. Pour comparer les types de proxies disponibles, visitez notre page de tarification. Pour voir la couverture géographique, consultez nos localisations proxy.

Key Takeaways

  • RoundRobinProxySwitcher est le point d'entrée le plus simple pour la rotation de proxies dans Colly, mais une ProxyFunc personnalisée offre un contrôle total sur la géolocalisation et les sessions.
  • Sessions collantes via -session-abc123 garantissent une IP constante pour les flux nécessitant une continuité (pagination, auth, panier).
  • Géorotation avec -country-DE-city-berlin permet de cibler des marchés spécifiques et d'éviter les blocages géographiques.
  • LimitRules avec Parallelism et RandomDelay sont aussi importants que la rotation elle-même — un bon scraper combine les deux.
  • Retries avec c.Clone() permettent de changer de proxy à chaque tentative, maximisant les chances de succès sur les cibles difficiles.
  • Redis storage permet un scraping distribué multi-instances avec déduplication automatique des URLs.
  • Colly ne suffit pas pour les SPAs JavaScript — combinez-le avec un navigateur headless si nécessaire.

Prêt à industrialiser votre scraping ? Découvrez comment ProxyHat peut améliorer vos projets de web scraping et de suivi SERP avec des proxies résidentiels à rotation automatique.

Questions fréquentes

Qu'est-ce que la rotation de proxies dans Colly ?

La rotation de proxies dans Colly consiste à utiliser la fonction SetProxyFunc ou proxy.RoundRobinProxySwitcher pour changer d'adresse IP à chaque requête HTTP. Colly appelle la ProxyFunc avant chaque requête, ce qui permet de distribuer le trafic sur un pool de proxies résidentiels ou datacenter et d'éviter les blocages IP des sites cibles.

Pourquoi la rotation de proxies dans Colly est-elle importante ?

Sans rotation de proxies, toutes les requêtes d'un scraper Colly sortent par la même IP. Les systèmes anti-bot modernes bloquent une IP après 50 à 200 requêtes rapprochées. La rotation distribue le trafic sur des centaines d'IP résidentielles, réduisant la charge par IP à un niveau indétectable et maintenant un throughput élevé sans interruptions.

Quel type de proxy fonctionne le mieux pour la rotation dans Colly ?

Les proxies résidentiels sont le meilleur choix pour la rotation dans Colly car ils utilisent des adresses IP attribuées par des FAI réels, ce qui les rend indiscernables du trafic humain. Les proxies datacenter sont souvent flaggés par les listes de réputation IP. Les proxies mobiles offrent le plus haut niveau de confiance mais à un coût plus élevé. ProxyHat propose les trois types sur le endpoint gate.proxyhat.com:8080.

Comment éviter les blocages lors de la rotation de proxies dans Colly ?

Pour éviter les blocages : combinez la rotation de proxies avec des LimitRules (Parallelism de 5-20, RandomDelay de 0.5-2s), utilisez des sessions uniques par requête pour forcer le changement d'IP, implémentez des retries avec c.Clone() et backoff exponentiel sur les codes 429/403, et utilisez des proxies résidentiels avec géociblage pour correspondre au trafic légitime de la région cible.

Prêt à commencer ?

Proxys résidentiels, ISP et mobiles dans plus de 148 pays. Créez un compte gratuit.

Créer un compte gratuit
← Retour au Blog