Rotacja Proxy w Colly: Kompletny Przewodnik dla Programistów Go

Praktyczny przewodnik po rotacji proxy w frameworku Colly dla Go. Dowiedz się, jak skonfigurować RoundRobinProxySwitcher, geo-targeting i wzorce produkcyjne z residential proxy.

Rotating Proxies in Colly: A Framework-Idiomatic Guide for Go Developers
W tym artykule

Jeśli budujesz scrapery w Go, prawdopodobnie znasz Colly — najpopularniejszy framework do web scrapingu w tym języku. Colly jest szybki, asynchroniczny i idiomatyczny, ale bez odpowiedniej rotacji proxy szybko napotkasz blokad IP, CAPTCHA i bany. W tym przewodniku pokazujemy, jak zaimplementować rotację proxy w Colly używając residential proxy, przełącznika RoundRobinProxySwitcher oraz własnych funkcji proxy z geo-targetowaniem.

Uwaga prawna: Scrapowanie danych publicznych jest ogólnie legalne, ale musisz przestrzegać robots.txt (RFC 9309), warunków usług (ToS) witryny oraz przepisów takich jak GDPR i CFAA. Ten artykuł dotyczy wyłącznie danych publicznie dostępnych. Nie zachęcamy do omijania zabezpieczeń ani naruszania praw własności.

Rotacja proxy w Colly — dlaczego jest niezbędna

Colly wysyła żądania HTTP asynchronicznie, wykorzystując goroutines i kanały Go. Domyślnie wszystkie żądania wychodzą z jednego adresu IP. Jeśli wykonasz 1000 żądań do tej samej domeny w ciągu minuty, większość nowoczesnych stron wykryje ten wzorzec i zablokuje Twój adres IP — często w ciągu pierwszych 200 żądań.

Rotacja proxy rozwiązuje ten problem, dystrybuując żądania przez wiele adresów IP. Każde żądanie może wychodzić z innego IP, co utrudnia wykrycie wzorca. W Colly rotacja proxy realizowana jest na poziomie http.Request — framework pozwala na podmianę URL proxy dla każdego żądania przez mechanizm SetProxyFunc.

Dlaczego residential proxy są lepsze niż datacenter dla trudnych celów? Strony e-commerce, platformy społecznościowe i wyszukiwarki mają zaawansowane systemy anty-bot, które flagują ranges IP z centrów danych. Residential IP należą do rzeczywistych dostawców internetowych (ISP), co czyni je trudniejszymi do odróżnienia od ruchu organicznego.

Model Collector w Colly — OnRequest, OnHTML, OnError

Colly opiera się na wzorcu Collector — obiekcie konfigurowanym przez callbacki. Najważniejsze z nich to:

  • OnRequest — wywoływany przed wysłaniem każdego żądania. Idealne miejsce do ustawiania nagłówków, modyfikacji URL lub logowania.
  • OnHTML — wywoływany po pobraniu strony, gdy HTML jest parsowany przez goquery. Pozwala na selektor-based traversal DOM.
  • OnError — wywoływany, gdy żądanie kończy się błędem. Tu implementujesz logikę retry.
  • OnResponse — wywoływany po otrzymaniu pełnej odpowiedzi, przed parsowaniem HTML.

Tryb asynchroniczny (domyślny w Colly) oznacza, że żądania są kolejkowane i wykonywane równolegle z ograniczeniem współbieżności ustawianym przez colly.AsyncOptions.Parallelism. To kluczowe dla wydajności, ale zwiększa ryzyko blokad — dlatego rotacja proxy jest tu krytyczna.

Przełącznik proxy w Colly — RoundRobinProxySwitcher i SetProxyFunc

Colly oferuje wbudowany proxy.RoundRobinProxySwitcher, który przyjmuje listę URL-i proxy i rotuje je cyklicznie. Oto podstawowy przykład z ProxyHat:

package main

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

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

    // Lista endpointów ProxyHat (HTTP, port 8080)
    proxies := []*url.URL{
        url.Parse("http://user-country-US:pass@gate.proxyhat.com:8080"),
        url.Parse("http://user-country-DE:pass@gate.proxyhat.com:8080"),
        url.Parse("http://user-country-GB:pass@gate.proxyhat.com:8080"),
        url.Parse("http://user-country-FR:pass@gate.proxyhat.com:8080"),
    }

    // RoundRobinProxySwitcher rotuje proxy cyklicznie
    switcher, err := proxy.RoundRobinProxySwitcher(proxies...)
    if err != nil {
        log.Fatal(err)
    }
    c.SetProxyFunc(switcher)

    c.OnHTML("title", func(e *colly.HTMLElement) {
        log.Printf("Tytuł: %s | IP proxy: %s", e.Text, e.Request.ProxyURL)
    })

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

SetProxyFunc przyjmuje funkcję typu func(*http.Request) (*url.URL, error). Możesz napisać własną funkcję zamiast RoundRobinProxySwitcher, aby implementować logikę rotacji dostosowaną do Twoich potrzeb — np. wybór kraju na podstawie docelowego URL albo sticky sessions.

Rotacyjne proxy z geo-targetowaniem — username per request

ProxyHat pozwala na geo-targetowanie i kontrolę sesji przez nazwę użytkownika. Format to:

  • user-country-DE — proxy z Niemiec
  • user-country-DE-city-berlin — proxy z Berlina
  • user-session-abc123 — sticky session (ten sam IP dla wielu żądań)
  • user-country-US-session-xyz789 — kombinacja kraju i sesji

W Colly możesz dynamicznie generować URL proxy dla każdego żądania, korzystając z własnej funkcji w SetProxyFunc. Oto przykład, który rotuje kraje i przypisuje unikalne sesje:

package main

import (
    "crypto/rand"
    "encoding/hex"
    "fmt"
    "math/rand/v2"
    "net/http"
    "net/url"
    "github.com/gocolly/colly/v2"
)

var countries = []string{"US", "DE", "GB", "FR", "PL", "NL", "SE", "CA"}

func randomSession() string {
    b := make([]byte, 6)
    rand.Read(b)
    return hex.EncodeToString(b)
}

func proxyFunc(r *http.Request) (*url.URL, error) {
    country := countries[rand.IntN(len(countries))]
    session := randomSession()
    proxyURL := fmt.Sprintf(
        "http://user-country-%s-session-%s:pass@gate.proxyhat.com:8080",
        country, session,
    )
    return url.Parse(proxyURL)
}

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

    c.OnHTML("h1", func(e *colly.HTMLElement) {
        fmt.Printf("Proxy: %s\n", e.Request.ProxyURL)
    })

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

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

Ten wzorzec daje pełną kontrolę: każde żądanie wychodzi z innego kraju i innej sesji, co maksymalizuje dywersyfikację IP. Jeśli potrzebujesz sticky session (np. do logowania i utrzymania sesji), użyj tego samego identyfikatora sesji dla całego przepływu.

SOCKS5 jest również obsługiwany — wystarczy zmienić schemat URL i port:

proxyURL := "socks5://user-country-US:pass@gate.proxyhat.com:1080"

Kompletny przykład Go — Collector z residential proxy i Limit()

Poniżej znajduje się kompletny, produkcyjny przykład łączący rotację proxy, limitowanie współbieżności, opóźnienia i logikę retry przez c.Clone():

package main

import (
    "crypto/rand"
    "encoding/hex"
    "fmt"
    "math/rand/v2"
    "net/http"
    "net/url"
    "time"
    "github.com/gocolly/colly/v2"
    "github.com/gocolly/colly/v2/debug"
)

var countries = []string{"US", "DE", "GB", "FR", "PL", "NL"}

func randomSession() string {
    b := make([]byte, 6)
    rand.Read(b)
    return hex.EncodeToString(b)
}

func residentialProxyFunc(r *http.Request) (*url.URL, error) {
    country := countries[rand.IntN(len(countries))]
    session := randomSession()
    u := fmt.Sprintf(
        "http://user-country-%s-session-%s:YOUR_PASSWORD@gate.proxyhat.com:8080",
        country, session,
    )
    return url.Parse(u)
}

func main() {
    c := colly.NewCollector(
        colly.MaxDepth(2),
        colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)"),
    )

    // Konfiguracja proxy
    c.SetProxyFunc(residentialProxyFunc)

    // Limitowanie: max 5 równoległych żądań, losowe opóźnienie 1-3s
    c.Limit(&colly.LimitRule{
        DomainGlob:  "*",
        Parallelism: 5,
        Delay:       2 * time.Second,
        RandomDelay: 1 * time.Second,
    })

    // Włącz tryb asynchroniczny
    c.Async = true

    var visited int

    c.OnHTML("a[href]", func(e *colly.HTMLElement) {
        link := e.Attr("href")
        e.Request.Visit(link)
    })

    c.OnResponse(func(r *colly.Response) {
        visited++
        fmt.Printf("[%d] %s — status: %d, proxy: %s\n",
            visited, r.Request.URL, r.StatusCode, r.Request.ProxyURL)
    })

    c.OnError(func(r *colly.Response, err error) {
        fmt.Printf("Błąd: %v, status: %d, URL: %s\n", err, r.StatusCode, r.Request.URL)
        // Retry przez klonowanie collector z nowym proxy
        if r.StatusCode == 403 || r.StatusCode == 429 {
            clone := r.Request.Ctx.Colly.Clone()
            clone.SetProxyFunc(residentialProxyFunc)
            clone.Visit(r.Request.URL.String())
        }
    })

    c.Visit("https://example.com")
    c.Wait()
}

Kluczowe elementy tego przykładu:

  • LimitRule z Parallelism: 5 i Delay: 2s + RandomDelay: 1s zapobiega zalananiu serwera.
  • OnError z retry przez c.Clone() tworzy nowy collector z nowym proxy dla nieudanych żądań (403/429).
  • MaxDepth(2) ogranicza głębokość crawlowania.
  • Async = true włącza asynchroniczne wykonywanie żądań.

Wzorce produkcyjne — skalowanie, retries, distributed scraping

Własny Transport z konfiguracją TLS

Dla trudnych celów, które wymagają specyficznej konfiguracji TLS (np. niestandardowe cipher suites), możesz podmienić http.Transport w collectorze:

import (
    "crypto/tls"
    "net/http"
)

c := colly.NewCollector()
c.WithTransport(&http.Transport{
    TLSClientConfig: &tls.Config{
        InsecureSkipVerify: false,
        MinVersion:         tls.VersionTLS12,
    },
    MaxIdleConns:        100,
    MaxIdleConnsPerHost: 10,
    IdleConnTimeout:     30 * time.Second,
})

Distributed scraping z redis storage

Colly wspiera rozproszone crawlowanie przez kolejki współdzielone. Backend redis pozwala wielu instancjom na współdzielenie stanu odwiedzonych URL-i:

import (
    "github.com/gocolly/colly/v2"
    "github.com/gocolly/redis"
)

c := colly.NewCollector()
storage := &redis.Storage{
    Address:     "redis://localhost:6379",
    Prefix:      "colly_scraper_",
    Client:      nil,
}
c.SetStorage(storage)

W połączeniu z rotacyjnymi residential proxy z ProxyHat, możesz uruchomić wiele instancji scrapera w kontenerach Docker, każda z własnym zestawem sesji proxy. Skonsultuj dokumentację ProxyHat, aby dowiedzieć się więcej o dostępnych krajach i konfiguracji.

Porównanie typów proxy dla Colly

d>Koszt
Cecha Residential Datacenter Mobile
Wykrywalność przez anty-bot Niska Wysoka Bardzo niska
Prędkość Średnia (~100-300 ms) Wysoka (<50 ms) Niska (~300-800 ms)
Średni Niski Wysoki
Najlepsze zastosowanie E-commerce, SERP, social media Proste API, dane publiczne App mobile, bardzo trudne cele
Limit równoległych sesji Wysoki (100+) Średni Niski

Dla większości zastosowań web scrapingu w Colly residential proxy oferują najlepszy stosunek wydajności do wykrywalności. Sprawdź dostępne lokalizacje ProxyHat, aby zaplanować strategię geo-targetowania.

Częste błędy i przypadki brzegowe

1. Brak obsługi błędów proxy

Jeśli proxy zwraca błąd połączenia, Colly wywoła OnError. Bez logiki retry tracisz żądanie. Zawsze implementuj retry z nowym proxy przez c.Clone() lub kolejkowanie ponownych prób.

2. Zbyt wysoka współbieżność

Parallelism: 50 bez rotacji proxy to gwarancja bana. Utrzymuj współbieżność na poziomie 5-10 równoległych żądań na domenę z rotacją IP.

3. Ignorowanie robots.txt

Colly domyślnie nie sprawdza robots.txt. Możesz włączyć to przez colly.IgnoreRobotsTxt(false). Zawsze przestrzegaj RFC 9309 i zasady robots.txt.

4. Brak timeoutów

Bez timeoutów scraper może zawiesić się na martwym proxy. Ustaw c.SetRequestTimeout(30 * time.Second), aby uniknąć nieskończonego czekania.

5. Niespójne nagłówki

Każde żądanie z innym IP, ale z tym samym User-Agent, może zostać wykryte. Używaj realistycznych nagłówków i rotuj je razem z proxy.

Kiedy NIE używać Colly

Colly jest świetne dla stron serwerowo renderowanych (SSR), gdzie HTML jest dostępny w odpowiedzi HTTP. Jeśli strona wymaga JavaScript do renderowania treści (SPA oparte na React, Vue, Angular), Colly nie wykona JS i nie zobisz dynamicznej treści. W takich przypadkach rozważ:

  • chromedp — sterowanie Chrome w Go przez DevTools Protocol.
  • Playwright — przez bindings Go.
  • Rod — higher-level wrapper dla chromedp.

Nawet w tych przypadkach rotacja proxy jest konieczna — większość browser-automation frameworks wspiera konfigurację proxy na poziomie launch options.

Konfiguracja ProxyHat dla Colly

ProxyHat oferuje residential, mobile i datacenter proxy z geo-targetowaniem na poziomie kraju i miasta. Konfiguracja w Colly jest prosta — wszystkie parametry przekazywane są w nazwie użytkownika. Szczegóły znajdziesz w dokumentacji ProxyHat.

Dla SERP tracking i monitorowania wyników wyszukiwania, residential proxy z ProxyHat zapewniają 99.9% uptime i tysiące unikalnych IP. Sprawdź naszą stronę SERP tracking oraz web scraping, aby dowiedzieć się więcej o zastosowaniach. Cennik znajdziesz na stronie ProxyHat pricing.

Najważniejsze wnioski

  • Rotacja proxy jest obowiązkowa dla jakiegokolwiek scrapera powyżej ~100 żądań do jednej domeny.
  • RoundRobinProxySwitcher jest prosty, ale własna funkcja w SetProxyFunc daje pełną kontrolę nad geo-targetowaniem i sesjami.
  • Residential proxy są najlepsze dla trudnych celów — datacenter IP są łatwo flagowane przez systemy anty-bot.
  • LimitRule z Parallelism i RandomDelay jest kluczowy dla unikania blokad.
  • Retry przez c.Clone() pozwala na ponowne próby z nowym proxy przy błędach 403/429.
  • Redis storage umożliwia distributed scraping z współdzielonym stanem odwiedzonych URL-i.
  • Colly nie renderuje JS — dla SPA używaj chromedp lub Playwright.
  • Etyka: przestrzegaj robots.txt, ToS i GDPR. Scrapuj tylko dane publiczne.

Rotacja proxy w Colly to nie dodatek — to fundament produkcyjnego scrapera. Z residential proxy ProxyHat, idiomatycznym SetProxyFunc i wzorcami opisanymi w tym artykule, możesz budować scrapery, które działają niezawodnie na dużą skalę.

Często zadawane pytania

Czym jest rotacja proxy w Colly?

Rotacja proxy w Colly to mechanizm dystrybucji żądań HTTP przez wiele adresów IP, zapobiegający blokadom. Colly oferuje wbudowany RoundRobinProxySwitcher oraz interfejs SetProxyFunc, który przyjmuje własną funkcję func(*http.Request) (*url.URL, error). Pozwala to na dynamiczne przypisywanie proxy per-żądanie, w tym geo-targetowanie i sticky sessions przez parametry w nazwie użytkownika.

Dlaczego rotacja proxy w Colly ma znaczenie dla scraperów?

Bez rotacji proxy wszystkie żądania wychodzą z jednego IP, co pozwala systemom anty-bot na szybką detekcję i blokadę — często po zaledwie 200 żądaniach. Rotacja proxy dystrybuuje ruch przez wiele IP, co utrudnia wykrycie wzorca scrapowania. W połączeniu z residential proxy, które wyglądają jak ruch organiczny, rotacja znacząco zwiększa niezawodność scrapera.

Który typ proxy najlepiej sprawdza się w Colly?

Dla większości zastosowań web scrapingu w Colly residential proxy oferują najlepszy kompromis między wydajnością a wykrywalnością. Mają niską wykrywalność przez systemy anty-bot, średnią latencję około 100-300 ms i wysoką liczbę równoległych sesji. Datacenter proxy są szybsze i tańsze, ale łatwo flagowane. Mobile proxy są najtrudniejsze do wykrycia, ale wolniejsze i droższe.

Jak unikać blokad implementując rotację proxy w Colly?

Aby unikać blokad, używaj residential proxy z rotacją per-żądanie, ustawiaj LimitRule z Parallelism na 5-10 i RandomDelay 1-3 sekundy. Implementuj retry przez c.Clone() dla błędów 403/429. Rotuj nie tylko proxy, ale też nagłówki User-Agent. Przestrzegaj robots.txt i utrzymuj timeout żądań na poziomie 30 sekund, aby unikać zawieszeń na martwych proxy.

Czy Colly nadaje się do scrapowania stron JavaScript SPA?

Nie, Colly nie renderuje JavaScript. Jest frameworkiem do scrapowania HTML serwerowo renderowanego (SSR). Dla stron SPA opartych na React, Vue czy Angular, które wymagają wykonania JS do wyrenderowania treści, należy użyć narzędzi takich jak chromedp, Playwright lub Rod. Nawet w tych przypadkach rotacja proxy pozostaje konieczna — większość frameworków browser-automation wspiera konfigurację proxy.

Sprawdź konfigurację proxy w kilka sekund

Darmowy tester proxy — potwierdź, że Twoje IP są szybkie, anonimowe i nieblokowane.

Sprawdź proxy za darmo
← Powrót do Bloga