Colly'de Rotasyonlu Proxy Kullanımı: Go ile Üretim Seviyesi Web Scraping

Go'nun Colly çatısında rotasyonlu proxy kullanımını derinlemesine inceleyen bu rehber, proxy.RoundRobinProxySwitcher, özel proxy fonksiyonları, residential IP rotasyonu ve üretim kalıplarını örnek kodlarla açıklar.

Rotating Proxies in Colly: A Framework-Idiomatic Guide for Go Scrapers
Bu makalede

Go ekosisteminde web scraping denildiğinde akla gelen ilk çatı olan Colly, hafif yapısı ve asenkron HTTP istek modeliyle yüksek throughput gerektiren projeler için idealdir. Ancak hedef siteler anti-bot korumaları giderek sıkılaştıkça, tek IP üzerinden yapılan istekler hızla engellenir. İşte bu noktada Colly'de rotasyonlu proxy kullanımı devreye girer. Bu rehberde, Colly'nin collector modelinden proxy yüzeyine, residential IP rotasyonundan dağıtık scraping kalıplarına kadar tüm detayları ele alacağız.

Yasal Uyarı: Bu rehber yalnızca herkese açık verilerin toplanması için hazırlanmıştır. scraping yaptığınız sitelerin robots.txt dosyalarına saygı gösterin, Hizmet Şartlarını ihlal etmeyin ve GDPR ile CFAA gibi düzenlemelerin kapsamını göz önünde bulundurun.

Colly'de Rotasyonlu Proxy: Temel Kavramlar ve Sorunun Kökeni

Colly, Go'nun net/http paketi üzerine inşa edilmiş, goquery tabanlı DOM traversal sunan bir scraping çatısıdır. Her Collector instance'ı bağımsız bir HTTP istemcisidir ve OnRequest, OnHTML, OnError gibi callback'ler üzerinden istek yaşam döngüsünü yönetir.

Web siteleri, gelen isteklerin IP adresini, User-Agent'ını, istek sıklığını ve TLS parmak izini analiz ederek bot trafiğini tespit eder. Tek bir IP'den saniyede 50+ istek geldiğinde, çoğu WAF (Web Application Firewall) bu IP'yi otomatik olarak 403 veya 429 yanıtıyla engeller. Colly proxy rotasyonu, her isteği veya her N isteği farklı bir IP'den göndererek bu tespit mekanizmalarını aşmanın idiomatik yoludur.

Colly'nin async modu, colly.Async(true) ile etkinleştirildiğinde, istekler goroutine'ler üzerinden paralel olarak gönderilir. Bu, scraping hızını dramatik biçimde artırır ancak proxy rotasyonu olmadan tek IP hızla yasaklanır. Bu nedenle async mod ve proxy rotasyonu birlikte kullanılmalıdır.

Collector Modeli ve Callback'ler

Colly'nin çekirdeği Collector struct'ıdır. Temel callback'ler şunlardır:

  • OnRequest: İstek gönderilmeden önce çağrılır. Header'ları değiştirmek, proxy ayarlamak veya istek loglamak için kullanılır.
  • OnHTML: HTML parse edildikten sonra CSS selector'lerle eşleşen elementler için çağrılır. goquery tabanlıdır.
  • OnError: İstek başarısız olduğunda çağrılır. Retry mantığı burada uygulanabilir.
  • OnResponse: Ham HTTP yanıtı alındığında çağrılır. HTML dışındaki içerikler (JSON API'ler) için kullanışlıdır.

Colly Proxy Switcher: İdiomatik Proxy Yüzeyi

Colly, proxy yönetimi için iki temel API sunar:

  1. proxy.RoundRobinProxySwitcher: Verilen proxy listesi arasında round-robin (sıralı) geçiş yapan hazır bir fonksiyon döndürür. c.SetProxyFunc() ile Collector'a bağlanır.
  2. c.SetProxyFunc(func(*http.Request) (*url.URL, error)): Her istek için tam kontrol sağlayan özel proxy fonksiyonu. URL'yi dinamik olarak seçebilir, hedef domain'e göre farklı proxy kullanabilirsiniz.

Her iki yaklaşım da HTTP, HTTPS ve SOCKS5 proxy'leri destekler. ProxyHat ile kullanımda, HTTP proxy için gate.proxyhat.com:8080, SOCKS5 için gate.proxyhat.com:1080 portları kullanılır.

RoundRobinProxySwitcher ile Temel Kurulum

package main

import (
    "fmt"
    "log"
    "net/url"

    "github.com/gocolly/colly/v2"
    "github.com/gocolly/colly/v2/proxy"
)

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

    // ProxyHat residential proxy URL'leri
    proxyURLs := []*url.URL{
        {Scheme: "http", Host: "gate.proxyhat.com:8080",
         User: url.UserPassword("user-country-US", "pass")},
        {Scheme: "http", Host: "gate.proxyhat.com:8080",
         User: url.UserPassword("user-country-DE", "pass")},
        {Scheme: "http", Host: "gate.proxyhat.com:8080",
         User: url.UserPassword("user-country-GB", "pass")},
    }

    // Round-robin switcher oluştur
    switcher, err := proxy.RoundRobinProxySwitcher(
        proxyURLs[0].String(),
        proxyURLs[0].String(),
        proxyURLs[1].String(),
        proxyURLs[2].String(),
    )
    if err != nil {
        log.Fatal(err)
    }
    c.SetProxyFunc(switcher)

    c.OnResponse(func(r *colly.Response) {
        fmt.Printf("[%s] %d bytes from %s\n",
            r.Request.URL, len(r.Body), r.Request.ProxyURL)
    })

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

Neden Residential Proxy? Datacenter vs Mobile vs Residential

Hedef sitenin anti-bot koruması ne kadar sıkıysa, o kadar gerçekçi IP kaynaklarına ihtiyaç duyarsınız. Üç ana proxy türü arasındaki farklar:

ÖzellikDatacenter ProxyResidential ProxyMobile Proxy
IP KaynağıVeri merkezi bloklarıGerçek ISP atanan ev IP'leri4G/5G mobil operatör IP'leri
Tespit ZorluğuKolay (ASN veri tabanları)Zor (gerçek kullanıcı gibi görünür)Çok zor (en yüksek güven)
HızEn hızlı (~50ms)Orta (~200ms)Değişken (~500ms+)
FiyatEn düşükOrtaEn yüksek
Uygun KullanımAPI scraping, düşük korumalı sitelerSERP, e-ticaret, sosyal medyaSneaker, ticketing, en sıkı korumalar

Colly web scraping projelerinde residential proxy'ler, çoğu üretim senaryosu için en iyi dengeyi sunar. ProxyHat'ın residential ağı, user-country-XX ve user-city-YY parametreleriyle ülke ve şehir bazında hedefleme yapmanıza olanak tanır.

Ülke ve Şehir Hedefleme ile Rotasyon

ProxyHat'ın residential proxy'lerinde, kullanıcı adı içine gömülü flag'ler ile geo-targeting ve session yönetimi yapılır:

  • user-country-DE: Almanya IP'si
  • user-country-DE-city-berlin: Berlin şehri IP'si
  • user-session-abc123: Aynı IP'yi koruyan sticky session
  • user-country-US-session-xyz789: US IP'si + sticky session

Her istekte farklı bir session ID'si kullanarak IP rotasyonu sağlarsınız. Aynı session ID'sini kullandığınızda, aynı IP korunur — bu, oturum bazlı scraping (login gerektiren siteler) için kritiktir.

Çalışan Go Örneği: Residential Proxy ile Collector

Aşağıdaki örnek, ProxyHat residential proxy'leri ile çalışan tam bir Colly Collector kurulumunu gösterir. Özel proxy switcher, her istek için rastgele bir ülke ve session ID'si üretir:

package main

import (
    "crypto/rand"
    "fmt"
    "math/big"
    "net/http"
    "net/url"
    "sync/atomic"
    "time"

    "github.com/gocolly/colly/v2"
    "github.com/gocolly/colly/v2/extensions"
)

var countries = []string{"US", "DE", "GB", "FR", "JP", "BR"}

func randomSessionID() string {
    n, _ := rand.Int(rand.Reader, big.NewInt(1000000))
    return fmt.Sprintf("sess-%d", n.Int64())
}

func randomCountry() string {
    n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(countries))))
    return countries[n.Int64()]
}

// Özel proxy switcher — her istek için dinamik proxy URL üretir
func proxyHatSwitcher(req *http.Request) (*url.URL, error) {
    country := randomCountry()
    session := randomSessionID()
    username := fmt.Sprintf("user-country-%s-session-%s", country, session)

    proxyURL := &url.URL{
        Scheme: "http",
        Host:   "gate.proxyhat.com:8080",
        User:   url.UserPassword(username, "YOUR_PASSWORD"),
    }
    return proxyURL, nil
}

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

    // Özel proxy fonksiyonunu bağla
    c.SetProxyFunc(proxyHatSwitcher)

    // Rate limiting: domain başına saniyede maksimum 2 istek
    c.Limit(&colly.LimitRule{
        DomainGlob:  "*",
        Parallelism: 5,
        Delay:       500 * time.Millisecond,
        RandomDelay: 500 * time.Millisecond,
    })

    // User-Agent rotasyonu
    extensions.RandomUserAgent(c)
    extensions.Referer(c)

    var reqCount int64

    c.OnRequest(func(r *colly.Request) {
        n := atomic.AddInt64(&reqCount, 1)
        fmt.Printf("[req #%d] %s via %s\n", n, r.URL, r.ProxyURL)
    })

    c.OnHTML("title", func(e *colly.HTMLElement) {
        fmt.Printf("Title: %s\n", e.Text)
    })

    c.OnError(func(r *colly.Response, err error) {
        fmt.Printf("Error on %s: %v (status %d)\n",
            r.Request.URL, err, r.StatusCode)
        // Retry with clone
        if r.StatusCode == 429 || r.StatusCode == 403 {
            time.Sleep(2 * time.Second)
            r.Request.Retry()
        }
    })

    urls := []string{
        "https://httpbin.org/ip",
        "https://httpbin.org/headers",
        "https://httpbin.org/user-agent",
        "https://httpbin.org/anything",
    }

    for _, u := range urls {
        c.Visit(u)
    }
    c.Wait()
    fmt.Printf("Total requests: %d\n", atomic.LoadInt64(&reqCount))
}

Bu örnekte her istek, farklı bir ülkeden ve farklı bir session ID'siyle gönderilir. LimitRule ile paralellik 5'e, istekler arası gecikme 500ms'e ayarlanmıştır. RandomDelay ile bu gecikme rastgeleleştirilir — bu, pattern-based tespitini zorlaştırır.

Üretim Kalıpları: Retry, Clone ve Dağıtık Scraping

Retry Mantığı ve c.Clone()

Colly'de retry için en idiomatik yol c.Clone() kullanmaktır. Clone, orijinal Collector'ın tüm ayarlarını (proxy fonksiyonu, limit kuralları, callback'ler) kopyalar ancak bağımsız bir instance oluşturur. Bu, retry sırasında farklı proxy kullanmanıza olanak tanır:

func retryCollector(c *colly.Collector, url string, maxRetries int) {
    var attempt int

    var doRetry func()
    doRetry = func() {
        attempt++
        if attempt > maxRetries {
            log.Printf("Max retries reached for %s", url)
            return
        }

        clone := c.Clone()
        clone.OnError(func(r *colly.Response, err error) {
            if r.StatusCode >= 500 || r.StatusCode == 429 {
                backoff := time.Duration(attempt*attempt) * time.Second
                log.Printf("Retry %d for %s after %v", attempt, url, backoff)
                time.Sleep(backoff)
                doRetry()
            }
        })
        clone.OnScraped(func(r *colly.Response) {
            log.Printf("Success after %d attempts: %s", attempt, url)
        })
        clone.Visit(url)
        clone.Wait()
    }
    doRetry()
}

Custom Transport ve TLS Konfigürasyonu

Bazı hedefler TLS parmak izini (JA3) kontrol eder. Colly'nin underlying HTTP client'ına özel bir http.Transport atayarak TLS ayarlarını özelleştirebilirsiniz:

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

    "github.com/gocolly/colly/v2"
)

func newCollectorWithCustomTLS() *colly.Collector {
    c := colly.NewCollector()

    transport := &http.Transport{
        TLSClientConfig: &tls.Config{
            MinVersion:         tls.VersionTLS12,
            InsecureSkipVerify: false,
            CipherSuites: []uint16{
                tls.TLS_AES_256_GCM_SHA384,
                tls.TLS_CHACHA20_POLY1305_SHA256,
                tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            },
        },
        MaxIdleConns:        100,
        MaxIdleConnsPerHost: 10,
        IdleConnTimeout:     90 * time.Second,
        DisableKeepAlives:   false,
    }

    c.SetTransport(transport)
    return c
}

DisableKeepAlives: false ayarı, bağlantıların yeniden kullanılmasını sağlar ve latency'i düşürür. Ancak proxy rotasyonunda her istek farklı proxy'ye gittiği için keep-alive'in faydası sınırlıdır.

Dağıtık Scraping: Redis Storage Backend

Tek bir makine scraping kapasitesini aştığında, Colly'nin storage paketi ile dağıtık scraping yapabilirsiniz. Redis backend, ziyaret edilen URL'leri ve cookie'leri birden fazla Colly instance'ı arasında paylaşır:

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

func newDistributedCollector(redisAddr string) *colly.Collector {
    c := colly.NewCollector()

    // Redis storage backend
    s, err := storage.NewRedisStorage(
        fmt.Sprintf("redis://%s", redisAddr),
    )
    if err != nil {
        log.Fatal(err)
    }

    c.SetStorage(s)
    // URL deduplication across instances
    // Cookie sharing across instances

    return c
}

Bu kalıp, Kubernetes pod'larında veya Docker container'larında çalışan birden fazla scraper instance'ının koordineli çalışmasını sağlar. Her instance farklı proxy'ler kullanırken, aynı URL'i iki kez ziyaret etmez. ProxyHat'ın lokasyonları ile birleştirildiğinde, her instance farklı bölgelerden scraping yapabilir.

Yaygın Hatalar ve Edge Case'ler

1. Proxy URL Format Hataları

En sık yapılan hata, proxy URL'sini yanlış formatlamaktır. ProxyHat için doğru format:

// DOĞRU
http://user-country-DE:pass@gate.proxyhat.com:8080

// YANLIŞ — port eksik
http://user-country-DE:pass@gate.proxyhat.com

// YANLIŞ — yanlış host
http://user-country-DE:pass@proxy.proxyhat.com:8080

2. c.Wait() Çağrısını Unutmak

Async modda c.Visit() bloklanmaz. Tüm isteklerin tamamlanmasını beklemek için c.Wait() çağrısı şarttır. Unutulursa program istekler tamamlanmadan sonlanır.

3. Proxy Fonksiyonunda Panic

Özel proxy fonksiyonu (func(*http.Request) (*url.URL, error)) içinde panic olursa tüm Collector çöker. Hata yönetimi için her zaman error döndürün:

func safeProxySwitcher(req *http.Request) (*url.URL, error) {
    defer func() {
        if r := recover(); r != nil {
            log.Printf("Proxy switcher panic: %v", r)
        }
    }()

    // Fallback proxy
    return &url.URL{
        Scheme: "http",
        Host:   "gate.proxyhat.com:8080",
        User:   url.UserPassword("user-country-US", "pass"),
    }, nil
}

4. SOCKS5 ile HTTP İsteklerinin Karıştırılması

SOCKS5 proxy kullanırken port 1080 olmalıdır:

// SOCKS5 — port 1080
socks5://user-country-DE:pass@gate.proxyhat.com:1080

// HTTP — port 8080
http://user-country-DE:pass@gate.proxyhat.com:8080

Colly Ne Zaman Kullanılmamalı?

Colly, statik HTML ve JSON API'leri için mükemmel bir araçtır. Ancak JavaScript ile dinamik olarak render edilen içerikler (SPA'lar, React/Vue/Angular uygulamaları) için Colly yetersiz kalır. Bu durumlarda headless browser çözümleri gerekir:

  • Chromedp: Go için Chrome DevTools Protocol client. Colly ile birlikte kullanılabilir.
  • Rod: Go için yüksek seviyeli browser automation. Headless Chrome fleet yönetimi için uygundur.
  • Playwright-go: Playwright'ın Go port'u. Multi-browser desteği sunar.

JS-heavy hedeflerde bile Colly, ilk istek katmanı (URL keşfi, API endpoint'lerini bulma) için kullanılabilir; ardından headless browser ile render edilen sayfalar işlenir. Bu hibrit yaklaşım, tam headless scraping'e göre 10x daha hızlı olabilir.

ProxyHat ile Colly Entegrasyonu

ProxyHat, Colly'nin proxy yüzeyiyle tam uyumludur. ProxyHat dokümantasyonu, tüm bağlantı parametrelerini detaylandırır. Fiyatlandırma sayfamızda residential, mobile ve datacenter proxy paketlerini karşılaştırabilirsiniz.

Scraping projelerinizde web scraping kullanım senaryomuzu ve SERP tracking rehberimizi de inceleyebilirsiniz. ProxyHat'ın residential ağı 190+ ülkeyi kapsar ve lokasyonlar sayfasından mevcut ülkeleri görebilirsiniz.

Key Takeaways

  • Colly proxy rotasyonu, proxy.RoundRobinProxySwitcher veya özel SetProxyFunc ile yapılır. Her istek için farklı proxy URL üretmek, anti-bot tespitini zorlaştırır.
  • Residential proxy'ler, datacenter proxy'lere göre ~4x daha az engellenir. ProxyHat'ın user-country-XX-session-YY username formatı ile per-request rotasyon sağlanır.
  • Retry için c.Clone() kullanın. Clone, proxy fonksiyonunu da kopyalar; retry sırasında farklı IP'den istek gönderilir.
  • LimitRule ile Parallelism ve RandomDelay ayarlamak, pattern-based tespiti engeller. Domain başına saniyede 2-5 istek güvenli bir başlangıçtır.
  • JS-heavy SPA'lar için Colly yetersizdir. Chromedp veya Rod gibi headless browser çözümleri kullanın. Hibrit yaklaşım en verimli sonucu verir.
  • Dağıtık scraping için Redis storage backend kullanın. URL deduplication ve cookie sharing, multi-instance koordinasyon sağlar.

SSS

Colly'de rotasyonlu proxy nedir?

Colly'de rotasyonlu proxy, her HTTP isteğini farklı bir IP adresinden göndermek için SetProxyFunc veya RoundRobinProxySwitcher kullanmaktır. Bu, tek IP'den gelen yüksek hacimli isteklerin hedef site tarafından engellenmesini önler. Colly, proxy fonksiyonunu her istek öncesi çağırır ve döndürülen URL'i o istek için kullanır.

Colly'de rotasyonlu proxy neden önemlidir?

Proxy rotasyonu olmadan, tek IP'den yapılan istekler hedef sitenin WAF'ı tarafından hızla engellenir — genellikle 50-100 istek sonrası 403 veya 429 yanıtı alınır. Rotasyonlu proxy, istekleri birden çok IP'ye dağıtarak her IP'nin istek hacmini düşük tutar ve tespit eşiklerinin altında kalır. Bu, scraping projelerinin kesintisiz çalışması için kritiktir.

Colly proxy rotasyonu için hangi proxy türü en iyisidir?

Çoğu üretim senaryosu için residential proxy'ler en iyi seçimdir. Datacenter IP'leri ASN veri tabanlarıyla kolayca tespit edilirken, residential IP'ler gerçek ISP'lere atanan ev IP'leridir ve bot gibi görünmezler. ProxyHat residential proxy'leri, user-country-DE-city-berlin formatı ile ülke ve şehir bazında hedefleme sunar. En sıkı korumalı siteler (sneaker, ticketing) için mobile proxy'ler düşünülebilir.

Colly'de proxy kullanırken engellenmeyi nasıl önlersiniz?

Engellenmeyi önlemek için birkaç stratejiyi birlikte uygulayın: (1) Her istek için farklı residential IP kullanın — ProxyHat'ın session flag'i ile per-request rotasyon yapın. (2) LimitRule ile Parallelism'i 5'e, RandomDelay'i 500ms'e ayarlayın. (3) extensions.RandomUserAgent ile User-Agent rotasyonu yapın. (4) c.Clone() ile retry mantığı kurun ve exponential backoff uygulayın. (5) robots.txt'ye saygı gösterin ve hedef sitenin rate limit kurallarına uyun.

Sık sorulan sorular

Colly'de rotasyonlu proxy nedir?

Colly'de rotasyonlu proxy, her HTTP isteğini farklı bir IP adresinden göndermek için SetProxyFunc veya RoundRobinProxySwitcher kullanmaktır. Bu, tek IP'den gelen yüksek hacimli isteklerin hedef site tarafından engellenmesini önler. Colly, proxy fonksiyonunu her istek öncesi çağırır ve döndürülen URL'i o istek için kullanır.

Colly'de rotasyonlu proxy neden önemlidir?

Proxy rotasyonu olmadan, tek IP'den yapılan istekler hedef sitenin WAF'ı tarafından hızla engellenir — genellikle 50-100 istek sonrası 403 veya 429 yanıtı alınır. Rotasyonlu proxy, istekleri birden çok IP'ye dağıtarak her IP'nin istek hacmini düşük tutar ve tespit eşiklerinin altında kalır. Bu, scraping projelerinin kesintisiz çalışması için kritiktir.

Colly proxy rotasyonu için hangi proxy türü en iyisidir?

Çoğu üretim senaryosu için residential proxy'ler en iyi seçimdir. Datacenter IP'leri ASN veri tabanlarıyla kolayca tespit edilirken, residential IP'ler gerçek ISP'lere atanan ev IP'leridir ve bot gibi görünmezler. ProxyHat residential proxy'leri, user-country-DE-city-berlin formatı ile ülke ve şehir bazında hedefleme sunar. En sıkı korumalı siteler için mobile proxy'ler düşünülebilir.

Colly'de proxy kullanırken engellenmeyi nasıl önlersiniz?

Engellenmeyi önlemek için birkaç stratejiyi birlikte uygulayın: Her istek için farklı residential IP kullanın, LimitRule ile Parallelism'i 5'e RandomDelay'i 500ms'e ayarlayın, RandomUserAgent ile User-Agent rotasyonu yapın, c.Clone() ile retry mantığı kurun ve exponential backoff uygulayın, robots.txt'ye saygı gösterin ve hedef sitenin rate limit kurallarına uyun.

Başlamaya hazır mısınız?

148'den fazla ülkede residential, ISP ve mobil proxy'ler. Ücretsiz hesap oluşturun.

Ücretsiz hesap oluştur
← Bloga Dön