Etik uyarı: Bu rehber yalnızca herkese açık verilere erişim içindir. Hedef sitenin robots.txt dosyasını dikkate alın, CFAA ve GDPR kapsamındaki sınırlamalara uyun ve mümkünse resmi API'leri tercih edin. Proxy rotasyonu, erişim kısıtlamalarını aşmak için değil, dağıtık scraping altyapısını yönetmek için kullanılmalıdır.
Python ile üretim düzeyinde crawler kuruyorsanız, eninde sonunda tek bir IP ile çalışmanın sınırına çarparsınız. Hedef sitenin rate limiti sizi durdurur, Cloudflare challenge'ları patlar, DataDome sizi bot olarak işaretler. İşte tam bu noktada Crawlee for Python'da proxy rotasyonu devreye girer. Crawlee'nin SessionPool ve ProxyConfiguration mimarisi, IP rotasyonunu cookie ve fingerprint yönetimiyle entegre ederek, engellenmeleri zarif biçimde yönetmenizi sağlar.
Crawlee for Python'da Proxy Rotasyonu Nedir?
Crawlee for Python'da proxy rotasyonu, ProxyConfiguration sınıfı üzerinden her session için yeni bir proxy URL'si üretme ve SessionPool ile bu proxy'yi oturuma bağlama sürecidir. Crawlee, Apify'ın açık kaynak crawling framework'üdür ve resmi dokümantasyonuna göre BeautifulSoupCrawler ile PlaywrightCrawler'ı ortak bir request queue, autoscaling pool ve session yönetimi katmanı üzerinde birleştirir.
Temel akış şudur: ProxyConfiguration.new_url(session_id=...) çağrıldığında, Crawlee o session'a sabit bir proxy URL'si döner. Session kapatılana kadar aynı IP kullanılır. Bu, sticky session olarak bilinen desendir ve login gerektiren sitelerde kritik önem taşır. Alternatif olarak, her istekte yeni bir proxy URL'si alarak round-robin rotasyon yapabilirsiniz.
Crawlee Mimarisi: Neden Proxy Rotasyonu Gerekli?
Crawlee'nin çekirdeğinde üç ana bileşen bulunur:
- Request Queue: Tüm isteklerin sıraya alındığı kalıcı depolama. BeautifulSoupCrawler ve PlaywrightCrawler bu queue'yu paylaşır.
- Autoscaled Pool: Concurrency'yi otomatik ayarlayan worker havuzu. CPU ve bellek kullanımına göre paralel istek sayısını artırıp azaltır.
- SessionPool: Her session'a cookie, fingerprint ve proxy atayan yönetici. Session'lar engellendiğinde
retire()edilir ve yenisi oluşturulur.
Bu mimaride proxy rotasyonu bir "hack" değil, framework'ün doğal bir parçasıdır. SessionPool proxy'leri session'lara bağlar; bir session engellendiğinde hem cookie'ler hem de IP birlikte değiştirilir. Bu, IP'yi değiştirip aynı cookie'lerle devam etmekten çok daha etkilidir — çünkü anti-bot sistemleri cookie-IP tutarsızlığını da tespit eder.
Residential vs Datacenter Proxy'ler: Cloudflare ve DataDome Hedeflerinde Fark
Cloudflare ve DataDome gibi anti-bot sağlayıcıları, datacenter IP bloklarını ASN veritabanlarıyla işaretler. Bir AS14618 Amazon veya AS16509 AWS IP'sinden gelen istekler, içeriği ne kadar insancıl olursa olsun, genellikle challenge'ya düşer. Residential proxy'ler ise gerçek ISP'lerden (örneğin AS3320 Deutsche Telekom) IP'ler sağladığı için bu filtreleri geçer.
Tiered proxy stratejisi şöyle çalışır:
- Önce residential proxy ile dene — çoğu durumda çalışır.
- HTTP 403 veya challenge gelirse, session'ı
retire()et, yeni residential IP al. - Maksimum deneme sayısına ulaşılırsa, mobile proxy'ye fallback yap (ASN trust score daha yüksek).
- Hala başarısızsa, isteği kuyruğa geri bırak ve sonraki turda tekrar dene.
ProxyConfiguration: Crawlee'nin İdiomatik Proxy Yönetimi
Crawlee'nin ProxyConfiguration sınıfı, proxy URL'lerini merkezi olarak yönetir. Temel kullanım:
from crawlee import ProxyConfiguration
# ProxyHat residential endpoint
proxy_config = ProxyConfiguration(
proxy_urls=[
'http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080',
]
)
Ancak tek bir URL vermek yerine, dinamik URL üretimi için new_url() metodunu kullanmak daha idiomatiktir:
from crawlee import ProxyConfiguration
async def proxy_url_factory(session_id: str | None = None) -> str:
sid = session_id or 'default'
return f'http://user-country-US-session-{sid}:pass@gate.proxyhat.com:8080'
proxy_config = ProxyConfiguration(proxy_url_factory=proxy_url_factory)
Bu yaklaşımda, Crawlee her session için new_url(session_id='session-1') çağırır ve ProxyHat'ın -session-{id} flag'i sayesinde aynı session her seferinde aynı residential IP'yi alır. Farklı session'lar farklı IP'ler alır — bu, otomatik rotasyondur.
Çalışan Örnek: BeautifulSoupCrawler ile Proxy Rotasyonu
Aşağıdaki örnek, ProxyHat residential proxy'leri ile çalışan, session-bazlı rotasyon yapan bir BeautifulSoupCrawler'dır:
import asyncio
from crawlee import BeautifulSoupCrawler, ProxyConfiguration, LogLevel
from crawlee.crawlers import BeautifulSoupCrawlingContext
PROXYHAT_USER = 'user'
PROXYHAT_PASS = 'pass'
def make_proxy_url(session_id: str | None = None) -> str:
sid = session_id or 'default'
return f'http://{PROXYHAT_USER}-country-US-session-{sid}:{PROXYHAT_PASS}@gate.proxyhat.com:8080'
async def main() -> None:
proxy_config = ProxyConfiguration(proxy_url_factory=make_proxy_url)
crawler = BeautifulSoupCrawler(
proxy_configuration=proxy_config,
max_request_retries=3,
max_requests_per_crawl=500,
request_handler_timeout=30,
log_level=LogLevel.INFO,
)
@crawler.router.default_handler
async def handler(ctx: BeautifulSoupCrawlingContext) -> None:
ctx.log.info(
'Fetching',
url=ctx.request.url,
session_id=ctx.session.id if ctx.session else None,
)
# Engellenme kontrolü
title = ctx.soup.title.string if ctx.soup.title else ''
if 'Access Denied' in title or 'blocked' in (ctx.http_response.status_code == 403):
ctx.log.warning('Blocked — retiring session')
if ctx.session:
ctx.session.retire()
# İsteği kuyruğa geri bırak
await ctx.add_requests([ctx.request.url])
return
# Veriyi çıkar
data = {
'url': ctx.request.url,
'title': title.strip(),
'status': ctx.http_response.status_code,
}
await ctx.push_data(data)
# Linkleri takip et
await ctx.enqueue_links()
await crawler.run(['https://example.com'])
if __name__ == '__main__':
asyncio.run(main())
Bu örnekte dikkat etmeniz gereken noktalar:
proxy_url_factory, her session için benzersiz bir username üretir. ProxyHat-session-{id}flag'i aynı ID için aynı IP'yi döner.session.retire()çağrıldığında, Crawlee o session'ı atar ve bir sonraki istek için yeni session + yeni proxy URL'si oluşturur.max_request_retries=3, her istek için en fazla 3 deneme yapılmasını sağlar. Her denemede yeni session oluşturulur.
Per-Session Username Üretimi: ProxyHat SDK Yaklaşımı
Büyük ölçekli crawl'lerde session ID'leri yönetmek için yardımcı bir fonksiyon kullanın:
import uuid
from typing import Iterator
def session_id_generator() -> Iterator[str]:
"""Her session için benzersiz, kısa ID üretir."""
while True:
yield uuid.uuid4().hex[:12]
# Kullanım:
gen = session_id_generator()
session_id = next(gen) # örn: 'a3f9b2c1d4e5'
proxy_url = f'http://user-country-US-session-{session_id}:pass@gate.proxyhat.com:8080'
Bu pattern, yüzlerce eşzamanlı session'ı yönetirken IP çakışmalarını önler. Crawlee SessionPool varsayılan olarak 100 session oluşturur; autoscaling pool concurrency'i artırdıkça bu sayı otomatik büyür.
Production Desenleri: Engellenmeleri Yönetmek
1. Session Retire ve Retry Stratejisi
Engellenme tespit ettiğinizde yapmanız gerekenler:
ctx.session.retire()— session'ı at, cookie'leri ve proxy'yi birlikte değiştir.- İsteği
ctx.add_requests([ctx.request.url])ile kuyruğa geri ekle. - Crawlee otomatik olarak yeni session ile tekrar deneyecektir.
Ancak max_request_retries sınırına dikkat edin. 3 deneme yeterli olmuyorsa, hedef site muhtemelen daha agresif bir strateji gerektiriyor — bu durumda request aralarına gecikme ekleyin:
import asyncio
@crawler.router.default_handler
async def handler(ctx: BeautifulSoupCrawlingContext) -> None:
# İstekler arası 1-3 saniye rastgele bekleme
await asyncio.sleep(1 + (hash(ctx.request.url) % 20) / 10)
# ... normal handler mantığı
2. Concurrency ve Autoscaling
Crawlee'nin autoscaled pool'u, CPU kullanımı %70'i aşana kadar concurrency'yi artırır. Proxy rotasyonu ile bu, aynı anda yüzlerce farklı IP'den istek göndermeniz anlamına gelir. ProxyHat residential proxy'leri 100 eşzamanlı session'a kadar sorunsuz çalışır. Daha yüksek concurrency için proxy paketinizi ölçeklendirmeniz gerekir.
Concurrency'yi manuel ayarlamak için:
crawler = BeautifulSoupCrawler(
proxy_configuration=proxy_config,
max_request_retries=3,
max_requests_per_crawl=10000,
# Autoscaling parametreleri
min_concurrency=5,
max_concurrency=50,
)
3. Hata Yönetimi ve Error Handler
Proxy timeout'ları ve bağlantı hataları için ayrı bir error handler kullanın:
@crawler.router.error_handler
async def error_handler(ctx, error):
ctx.log.error(f'Request failed: {error}', url=ctx.request.url)
# Proxy hatasıysa session'ı retire et
if 'proxy' in str(error).lower() or 'timeout' in str(error).lower():
if ctx.session:
ctx.session.retire()
PlaywrightCrawler: Ne Zaman Kullanmalı, Ne Zaman Kullanmamalı?
PlaywrightCrawler, JavaScript rendering gerektiren siteler için gereklidir. Ancak maliyeti yüksektir: her browser instance ~150-200 MB RAM kullanır ve başlatma süresi 2-5 saniyedir. Eğer hedef site statik HTML döndürüyorsa, BeautifulSoupCrawler her zaman daha hızlıdır.
PlaywrightCrawler ile proxy rotasyonu aynı şekilde çalışır:
from crawlee import PlaywrightCrawler, ProxyConfiguration
proxy_config = ProxyConfiguration(proxy_url_factory=make_proxy_url)
crawler = PlaywrightCrawler(
proxy_configuration=proxy_config,
browser_type='chromium',
headless=True,
max_request_retries=3,
)
Headless browser fleet'i containerize etmek için, her container'da Crawlee + Playwright çalıştırın ve container başına 5-10 concurrency hedefleyin. Docker ile:
FROM mcr.microsoft.com/playwright/python:v1.40.0-jammy
RUN pip install crawlee beautifulsoup4
COPY crawler.py .
CMD ["python", "crawler.py"]
Kubernetes'te 10-50 pod arasında scale yaparak binlerce eşzamanlı istek yönetebilirsiniz. Her pod kendi SessionPool'unu yönetir ve ProxyHat'ın -session-{id} flag'i sayesinde pod'lar arası IP çakışması olmaz.
Proxy Türleri Karşılaştırması
| Özellik | Residential | Mobile | Datacenter |
|---|---|---|---|
| ASN Trust Score | Yüksek (gerçek ISP) | En yüksek (telekom) | Düşük (bulut sağlayıcı) |
| Cloudflare geçişi | ~85% başarı | ~95% başarı | ~30% başarı |
| Latency | 200-800ms | 300-1200ms | 50-150ms |
| Fiyat (GB başına) | $3-8/GB | $8-15/GB | $0.5-2/GB |
| Sticky session süresi | 30 dk'ya kadar | 10 dk'ya kadar | Sınırsız (sabit IP) |
Bu rakamlar endüstri ortalamalarıdır; gerçek performans hedef siteye, coğrafi konuma ve saat dilimine göre değişir. ProxyHat lokasyonlar sayfasından mevcut ülkeleri kontrol edebilirsiniz.
Geo-Targeting ve Session Pinning
ProxyHat username formatı, hem ülke hem şehir hem de session ID belirlemenize izin verir:
# ABD, belirli session
'http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080'
# Almanya, Berlin şehri
'http://user-country-DE-city-berlin-session-xyz789:pass@gate.proxyhat.com:8080'
# Japonya, Tokyo
'http://user-country-JP-city-tokyo-session-def456:pass@gate.proxyhat.com:1080'
SERP tracking için, her hedef ülke için ayrı bir ProxyConfiguration kullanın. Örneğin ABD SERP'leri için -country-US, Alman SERP'leri için -country-DE. Bu, arama sonuçlarının coğrafi olarak doğru olmasını sağlar. Daha fazla bilgi için SERP tracking kullanım senaryosuna bakın.
SOCKS5: Ne Zaman HTTP Yerine Tercih Edilmeli?
HTTP proxy çoğu durumda yeterlidir. Ancak aşağıdaki senaryolarda SOCKS5 (port 1080) daha iyi bir seçimdir:
- WebSocket bağlantıları gerektiren siteler (örneğin real-time fiyat akışları).
- UDP tabanlı protokoller (nadiren web scraping'de gerekir).
- HTTP proxy'nin sorun çıkardığı katı corporate network ortamları.
proxy_config = ProxyConfiguration(
proxy_url_factory=lambda sid: f'socks5://user-country-US-session-{sid}:pass@gate.proxyhat.com:1080'
)
Yaygın Hatalar ve Edge Case'ler
1. Session ID Çakışması
Eğer iki farklı crawler aynı session ID kullanırsa, aynı IP'yi paylaşır ve rate limit'e takılabilir. Çözüm: her crawler instance için unique prefix kullanın (örneğin crawler1-{uuid}).
2. Proxy URL'yi Hardcode Etmek
proxy_urls=['http://...'] ile statik liste vermek, proxy değiştiğinde kod değişikliği gerektirir. proxy_url_factory kullanın ve credentials'ı environment variable'dan okuyun:
import os
PROXYHAT_USER = os.environ['PROXYHAT_USER']
PROXYHAT_PASS = os.environ['PROXYHAT_PASS']
3. Engellenme Sinyallerini Göz Ardı Etmek
HTTP 200 dönmesi her şeyin yolunda olduğu anlamına gelmez. Bazı siteler engellenmiş isteklere 200 ile CAPTCHA sayfası döner. İçerik kontrolü yapın: sayfa başlığında "blocked", "verify", "captcha" kelimeleri varsa session'ı retire edin.
4. robots.txt'i İhmal Etmek
Crawlee robots.txt kontrolü için yerleşik bir mekanizma sunmaz. Manuel kontrol ekleyin:
import urllib.robotparser
def is_allowed(url: str, user_agent: str = '*') -> bool:
rp = urllib.robotparser.RobotFileParser()
rp.set_url(f'{url.split("/")[0]}//{url.split("/")[2]}/robots.txt')
try:
rp.read()
return rp.can_fetch(user_agent, url)
except Exception:
return True # robots.txt erişilemezse varsayılan olarak izin ver
Key Takeaways
ProxyConfigurationileproxy_url_factorykullanın — statik URL listesi yerine dinamik üretim yapın.SessionPool, proxy'yi cookie ve fingerprint ile birlikte yönetir;session.retire()tümünü atomik olarak değiştirir.- Residential proxy'ler Cloudflare/DataDome hedeflerinde datacenter'dan ~3x daha yüksek başarı oranı sağlar.
max_request_retriesilesession.retire()'ı birlikte kullanın — her retry yeni IP ile gelir.- BeautifulSoupCrawler'ı varsayılan olarak tercih edin; PlaywrightCrawler yalnızca JS rendering gerektiğinde kullanın.
- Etik scraping:
robots.txt'ye uyun, resmi API varsa onu kullanın, kişisel veri toplamaktan kaçının.
Sonuç ve Sonraki Adımlar
Crawlee for Python'da proxy rotasyonu, doğru yapıldığında üretim düzeyinde scraping'i sürdürülebilir kılar. ProxyConfiguration + SessionPool kombinasyonu, IP rotasyonunu cookie/fingerprint yönetimiyle entegre eder ve engellenmeleri zarif biçimde yönetir. ProxyHat residential proxy'leri ile -session-{id} flag'i, Crawlee'nin session ID'lerini doğrudan proxy IP'sine bağlar — ekstra yapılandırma gerekmez.
Başlamak için ProxyHat fiyatlandırma sayfasını inceleyin ve resmi ProxyHat dokümantasyonundan bağlantı detaylarını kontrol edin. Web scraping kullanım senaryosu sayfamızda daha fazla örnek bulabilirsiniz.






