Rate limiting — parser'ların çökmesinin, API entegrasyonlarının kopmasının ve otomatik script'lerin 429 Too Many Requests durumunu almasının en yaygın nedenlerinden biridir. Sunucu, bir IP'den çok fazla istek gördüğünde, yanıt vermeyi durdurur. Bu makalede, proxy kullanarak istek sınırlarını aşmak için altyapıyı nasıl doğru bir şekilde kuracağımızı inceleyeceğiz; gerçek Python ve Node.js kod örnekleri ile.
Rate limiting nedir ve neden sıradan gecikmeler yardımcı olmaz
Rate limiting (istek sıklığı sınırlaması), belirli bir zaman diliminde bir kaynaktan gelen istek sayısını sınırlayan bir sunucu koruma mekanizmasıdır. Kaynak genellikle bir IP adresidir, ancak gelişmiş sistemler ayrıca yetkilendirme token'larını, User-Agent'ı, çerezleri ve hatta davranış kalıplarını da dikkate alır.
Script'iniz limiti aştığında, sunucu aşağıdaki yanıtlardan birini döndürür:
429 Too Many Requests— rate limiting için standart HTTP durumu503 Service Unavailable— bazen 429 yerine kullanılır403 Forbidden— eğer IP zaten kara listeye alınmışsa- Boş yanıt veya zaman aşımı — agresif engelleme durumunda
Çoğu geliştiricinin ilk düşüncesi, istekler arasında time.sleep(1) eklemektir. Bu, yalnızca çok yumuşak limitlerde (örneğin, dakikada 60 istek) işe yarar. Ancak gerçek senaryolar daha karmaşıktır:
Popüler platformların gerçek limitleri:
- Twitter/X API (ücretsiz): ayda 500.000 tweet, ancak her 15 dakikada en fazla 15 istek
- Google Search: yetkilendirme olmadan bir IP'den günde ~100 istek
- Wildberries, Ozon: agresif rate limiting — dakikada 30–50 istekten sonra engelleme
- GitHub API: token olmadan saatte 60 istek, token ile 5000/sa
- Cloudflare korumalı siteler: dakikada 10–20 istekten sonra engelleyebilir
Eğer bir pazaryerinden 100.000 ürün kartı toplamanız veya gerçek zamanlı fiyatları izlemeniz gerekiyorsa — gecikmeler yeterli olmayacaktır. Farklı bir mimariye ihtiyacınız var. İşte burada proxy'ler bir seçenek değil, bir gereklilik haline geliyor.
Anlamak önemlidir: rate limiting IP adresine bağlıdır. Eğer 100 farklı IP'niz varsa — aslında 100 bağımsız "kota"ya sahip olursunuz. Bu, proxy'ler aracılığıyla sınırlamaları aşmanın temel ilkesidir.
Proxy'ler istek sınırlama sorununu nasıl çözer
Mekanizma basit: hedef sunucuya her istek farklı bir IP adresi üzerinden gider. Sunucu açısından — bu farklı kullanıcılar. Her birinin kotası neredeyse tükenmez, bu nedenle engelleme gerçekleşmez.
Proxy olmadan ve bir proxy havuzuyla çalışmanın farkını belirli bir örnekle inceleyelim. Diyelim ki, sunucu bir IP'den dakikada 10 istek izni veriyor:
| Senaryo | Dakikada istek sayısı | Engelleme | 10.000 istek için süre |
|---|---|---|---|
| Bir IP, proxy olmadan | 10 | Evet, 10 istektan sonra | ~16 saat |
| 10 proxy, döngüleme | 100 | Hayır | ~1.7 saat |
| 100 proxy, döngüleme | 1000 | Hayır | ~10 dakika |
Bant genişliğini ölçeklendirmenin yanı sıra, proxy'ler rate limiting ile çalışırken birkaç avantaj daha sunar:
- Oturumların izolasyonu — bir IP engellendiğinde, diğerleri çalışmaya devam eder
- Coğrafi dağılım — istekler farklı bölgelerden gelir, bu da şüpheyi azaltır
- Sticky sessions — çok aşamalı senaryolar (yetkilendirme + eylem) için bir IP'ye "yapışma" imkanı
- Yük kontrolü — her IP için istekleri tam olarak dozlayabilir, limiti aşmazsınız
Göreviniz için hangi proxy türünü seçmelisiniz
Tüm proxy'ler rate limiting'e karşı eşit derecede etkili değildir. Tür seçimi, hedef siteye, istek hacmine ve bütçeye bağlıdır. Üç ana türü inceleyelim:
Konut Proxy'leri
Bunlar gerçek ev kullanıcılarının IP adresleridir. Normal internet trafiği gibi görünürler ve nadiren engellenirler. Konut proxy'leri — agresif koruma olan siteler için en iyi seçimdir: pazaryerleri (Wildberries, Ozon), sosyal medya, Cloudflare korumalı kaynaklar. Ana dezavantajı — veri merkezi proxy'lerine göre daha yüksek fiyatıdır.
Mobil Proxy'ler
Mobil operatörlerin IP adresleri (3G/4G/5G). Özelliği, bir IP'nin aynı anda binlerce gerçek abone tarafından kullanılabilmesidir, bu nedenle bu tür adresleri engellemek siteler için son derece istenmeyen bir durumdur. Mobil proxy'ler, konut proxy'lerinin engellenmeye başladığı yerlerde en iyi sonuçları verir — örneğin, Instagram'da yüksek frekanslı veri çekme veya bağlantı türünü analiz eden platformların API'leri ile çalışırken.
Veri Merkezi Proxy'leri
Hızlı ve ucuz IP'ler, sunucu veri merkezlerinden gelir. Ciddi koruma gerektirmeyen siteleri veri çekmek için idealdir: açık API'ler, haber agregatörleri, kamuya açık veritabanları. Rate limiting ile ilgili görevler için daha fazla proxy'ye ihtiyaç vardır (çünkü daha sık kara listeye alınırlar), ancak doğru döngüleme ile büyük istek hacimleriyle başa çıkabilirler. Daha fazla bilgi için veri merkezi proxy'leri sayfasına göz atın.
| Proxy Türü | Anonimlik | Hız | Fiyat | En iyi senaryo |
|---|---|---|---|---|
| Konut | Çok yüksek | Orta | $$ | Pazaryerleri, sosyal medya, Cloudflare |
| Mobil | Maksimum | Orta | $$$ | Instagram API, yüksek frekanslı veri çekme |
| Veri Merkezleri | Orta | Yüksek | $ | Açık API'ler, kamu verileri |
IP döngüleme stratejileri: per-request, sticky sessions, round-robin
Proxy'lerin mevcut olması sorunu çözmez — onları doğru bir şekilde yönetmek önemlidir. Her biri kendi senaryolarına uygun birkaç döngüleme stratejisi vardır.
Per-request döngüleme (her istek için yeni IP)
Her HTTP isteği yeni bir IP adresi üzerinden gider. Bu, rate limiting'i aşmanın en agresif stratejisidir — sunucu fiziksel olarak bir IP için sayaç biriktirmeye yetişemez. Aşağıdaki durumlar için uygundur:
- Ürün kartlarının veri çekimi (her kart ayrı bir istek)
- Arama motorlarından veri toplama
- Oturum gerektirmeyen herhangi bir stateless istek
Sticky sessions (oturum başına sabit IP)
Bir IP, oturum süresince (genellikle 1-30 dakika) kullanılır. Yetkilendirme gereken senaryolar için kritik öneme sahiptir: bir hesaba giriş yapmak, bir eylem gerçekleştirmek, çıkış yapmak. Eğer IP adımları arasında değişirse — sunucu oturumu şüpheli olarak engelleyebilir.
Round-robin ile IP başına istek limiti
En doğru stratejidir. Sunucunun limitini biliyorsunuz (örneğin, dakikada 10 istek) ve istekleri proxy havuzuna dağıtıyorsunuz, böylece her IP bu eşiği asla aşmaz. Her IP için son isteğin zamanını dikkate alarak bir kuyruk uygulaması gerektirir.
Gerekli proxy sayısını hesaplama formülü:
N proxy = (Hedef istek hızı/dakika) ÷ (Sunucu limiti/dakika IP başına)
Örnek: 500 istek/dakika gerekiyor, sunucu limiti — 10/dakika → en az 50 proxy gerekir.
Engellemeler için %20 yedek ekleyin: toplamda 60 proxy.
Python kod örnekleri: requests, aiohttp, Scrapy
Uygulamaya geçelim. Aşağıda, en popüler üç Python aracı için hazır şablonlar bulunmaktadır.
1. requests + manuel proxy döngüleme
En basit seçenek — proxy listesinden her istek için rastgele seçim yapmak:
import requests
import random
import time
PROXIES = [
"http://user:[email protected]:8080",
"http://user:[email protected]:8080",
"http://user:[email protected]:8080",
# ... gerekli sayıda ekleyin
]
def get_random_proxy():
proxy = random.choice(PROXIES)
return {"http": proxy, "https": proxy}
def fetch_with_retry(url, max_retries=3):
for attempt in range(max_retries):
proxy = get_random_proxy()
try:
response = requests.get(
url,
proxies=proxy,
timeout=10,
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
)
if response.status_code == 429:
print(f"{proxy} üzerinde rate limit uygulandı, değiştiriliyor...")
time.sleep(1)
continue
return response
except requests.RequestException as e:
print(f"Girişim {attempt+1} başarısız: {e}")
time.sleep(2)
return None
# Kullanım
urls = ["https://example.com/item/1", "https://example.com/item/2"]
for url in urls:
result = fetch_with_retry(url)
if result:
print(f"OK: {url} — {len(result.text)} bayt")
2. Rate limit dikkate alınarak akıllı proxy havuzu
Daha gelişmiş bir seçenek — ProxyPool sınıfı, her IP'nin son kullanım zamanını takip eder ve belirlenen limiti aşmaz:
import requests
import time
from collections import defaultdict
from threading import Lock
class ProxyPool:
def __init__(self, proxies, rate_limit=10, window=60):
"""
proxies: 'http://user:pass@host:port' formatında bir dizi
rate_limit: bir IP'den belirli bir süre içinde maksimum istek sayısı
window: saniye cinsinden zaman dilimi
"""
self.proxies = proxies
self.rate_limit = rate_limit
self.window = window
self.usage = defaultdict(list) # proxy -> [timestamps]
self.lock = Lock()
def get_available_proxy(self):
now = time.time()
with self.lock:
for proxy in self.proxies:
# Eski zaman damgalarını temizle
self.usage[proxy] = [
t for t in self.usage[proxy]
if now - t < self.window
]
if len(self.usage[proxy]) < self.rate_limit:
self.usage[proxy].append(now)
return {"http": proxy, "https": proxy}
return None # Tüm proxy'ler limitini aştı
def fetch(self, url, **kwargs):
proxy = self.get_available_proxy()
if proxy is None:
print("Tüm proxy'ler rate-limited, bekleniyor...")
time.sleep(5)
return self.fetch(url, **kwargs)
try:
response = requests.get(url, proxies=proxy, timeout=10, **kwargs)
return response
except requests.RequestException as e:
print(f"İstek başarısız: {e}")
return None
# Kullanım
pool = ProxyPool(
proxies=[
"http://user:[email protected]:8080",
"http://user:[email protected]:8080",
],
rate_limit=10, # IP başına dakikada 10 istek
window=60
)
for i in range(100):
r = pool.fetch(f"https://example.com/page/{i}")
if r:
print(f"Sayfa {i}: {r.status_code}")
3. Asenkron veri çekimi için aiohttp
Asenkron yaklaşım, çok sayıda proxy'yi paralel olarak kullanmanıza olanak tanır ve thread'leri engellemez:
import asyncio
import aiohttp
import itertools
PROXIES = [
"http://user:[email protected]:8080",
"http://user:[email protected]:8080",
"http://user:[email protected]:8080",
]
proxy_cycle = itertools.cycle(PROXIES)
async def fetch(session, url, proxy):
try:
async with session.get(
url,
proxy=proxy,
timeout=aiohttp.ClientTimeout(total=10)
) as response:
if response.status == 429:
await asyncio.sleep(2)
return None
return await response.text()
except Exception as e:
print(f"Hata: {e}")
return None
async def main(urls):
connector = aiohttp.TCPConnector(limit=50)
async with aiohttp.ClientSession(connector=connector) as session:
tasks = [
fetch(session, url, next(proxy_cycle))
for url in urls
]
results = await asyncio.gather(*tasks)
return results
urls = [f"https://example.com/item/{i}" for i in range(200)]
results = asyncio.run(main(urls))
print(f"Toplanan: {sum(1 for r in results if r is not None)} sayfa")
4. Scrapy ile middleware üzerinden döngüleme
Scrapy için hazır bir çözüm vardır — scrapy-rotating-proxies. Ancak kendi middleware'inizi yazabilirsiniz:
# middlewares.py
import random
class RotatingProxyMiddleware:
def __init__(self, proxies):
self.proxies = proxies
@classmethod
def from_crawler(cls, crawler):
return cls(proxies=crawler.settings.getlist("PROXY_LIST"))
def process_request(self, request, spider):
proxy = random.choice(self.proxies)
request.meta["proxy"] = proxy
def process_response(self, request, response, spider):
if response.status == 429:
spider.logger.warning(f"Rate limit uygulandı, proxy: {request.meta.get('proxy')}")
# Sorunlu proxy'yi hariç tutma mantığı eklenebilir
return response
# settings.py
PROXY_LIST = [
"http://user:[email protected]:8080",
"http://user:[email protected]:8080",
]
DOWNLOADER_MIDDLEWARES = {
"myproject.middlewares.RotatingProxyMiddleware": 350,
}
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_TARGET_CONCURRENCY = 10
Node.js kod örnekleri: axios, got, Puppeteer
Node.js, tarayıcı otomasyonu ve API ile çalışmak için popüler bir seçimdir. İşte proxy'lerle çalışmak için hazır kalıplar.
1. axios ile proxy döngüleme
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const proxies = [
'http://user:[email protected]:8080',
'http://user:[email protected]:8080',
'http://user:[email protected]:8080',
];
let proxyIndex = 0;
function getNextProxy() {
const proxy = proxies[proxyIndex % proxies.length];
proxyIndex++;
return proxy;
}
async function fetchWithProxy(url, retries = 3) {
for (let i = 0; i < retries; i++) {
const proxyUrl = getNextProxy();
const agent = new HttpsProxyAgent(proxyUrl);
try {
const response = await axios.get(url, {
httpsAgent: agent,
httpAgent: agent,
timeout: 10000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
},
});
return response.data;
} catch (error) {
if (error.response?.status === 429) {
console.log(`Rate limit uygulandı, proxy değiştiriliyor...`);
await new Promise(r => setTimeout(r, 1000));
continue;
}
console.error(`Girişim ${i + 1} başarısız:`, error.message);
}
}
return null;
}
// Kullanım
(async () => {
const urls = Array.from({length: 50}, (_, i) => `https://example.com/item/${i}`);
const results = await Promise.allSettled(
urls.map(url => fetchWithProxy(url))
);
const successful = results.filter(r => r.status === 'fulfilled' && r.value).length;
console.log(`Başarı: ${successful}/${urls.length}`);
})();
2. Puppeteer ile proxy ve rate limiting aşma
JavaScript ile render edilen ve Cloudflare korumalı siteler için headless bir tarayıcı gereklidir:
const puppeteer = require('puppeteer');
const proxies = [
'proxy1.example.com:8080',
'proxy2.example.com:8080',
];
async function scrapeWithProxy(url, proxyHost) {
const browser = await puppeteer.launch({
args: [
`--proxy-server=${proxyHost}`,
'--no-sandbox',
'--disable-setuid-sandbox',
],
headless: true,
});
const page = await browser.newPage();
// Proxy yetkilendirmesi
await page.authenticate({
username: 'user',
password: 'pass',
});
// Gerçekçi bir User-Agent ayarlama
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
);
try {
await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
// Rate limit kontrolü
const status = await page.evaluate(() => document.title);
if (status.includes('429') || status.includes('Too Many')) {
console.log('Rate limit uygulandı, proxy değiştirilmeli');
return null;
}
const data = await page.evaluate(() => {
return document.querySelector('.price')?.textContent || null;
});
return data;
} finally {
await browser.close();
}
}
// Görev başına döngüleme
(async () => {
const urls = ['https://example.com/product/1', 'https://example.com/product/2'];
for (let i = 0; i < urls.length; i++) {
const proxy = proxies[i % proxies.length];
const result = await scrapeWithProxy(urls[i], proxy);
console.log(`${urls[i]}: ${result}`);
await new Promise(r => setTimeout(r, 500)); // küçük bir gecikme
}
})();
Gelişmiş teknikler: başlıklar, fingerprint, Cloudflare'ı aşma
IP değişimi gerekli, ancak her zaman yeterli değildir. Modern koruma sistemleri, isteklerin onlarca parametresini analiz eder. Ne dikkate almanız gerektiğini inceleyelim.
HTTP başlıkları: minimum zorunlu set
Normal başlıklar olmadan yapılan bir istek, IP değişse bile bot gibi görünür. Her zaman ekleyin:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Cache-Control": "max-age=0",
}
Retry-After başlığının işlenmesi
429 yanıtında sunucu genellikle ne kadar beklemeniz gerektiğini belirtir. Bu başlığın doğru bir şekilde işlenmesi, istekleri boşa harcamamanızı sağlar:
def handle_rate_limit(response):
if response.status_code == 429:
retry_after = response.headers.get("Retry-After")
if retry_after:
wait_time = int(retry_after)
print(f"Rate limit uygulandı. {wait_time} saniye bekleniyor...")
time.sleep(wait_time + 1) # +1 saniye tampon
else:
# Başlık yoksa üstel gecikme
time.sleep(min(2 ** attempt, 60))
return True
return False
TLS fingerprinting ve nasıl aşılacağı
Gelişmiş sistemler (Cloudflare, Akamai, PerimeterX) TLS fingerprint'i analiz eder — TLS bağlantınızın benzersiz "parmak izi". Standart requests kütüphanesi kolayca tanınabilir bir fingerprint'e sahiptir. Çözümler:
- curl_cffi (Python) — TLS seviyesinde Chrome/Firefox fingerprint'ini taklit eder
- tls-client (Go/Python) — farklı tarayıcı profilleri desteği ile benzer bir araç
- Playwright/Puppeteer — gerçek bir tarayıcı, varsayılan olarak mükemmel fingerprint
# pip install curl-cffi
from curl_cffi import requests as cffi_requests
response = cffi_requests.get(
"https://cloudflare-protected-site.com/api/data",
impersonate="chrome120", # Chrome 120'yi taklit et
proxies={"https": "http://user:[email protected]:8080"}
)
print(response.json())
Çerezler ve oturumların yönetimi
Eğer site oturumları izlemek için çerezler kullanıyorsa, IP değişimi çerez değişimi olmadan anlamsızdır. Proxy değiştirirken her zaman yeni bir oturum oluşturun:
import requests
def create_fresh_session(proxy_url):
"""Her proxy için temiz çerezlerle yeni bir oturum oluşturur"""
session = requests.Session()
session.proxies = {"http": proxy_url, "https": proxy_url}
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
})
# Çerezler önceki oturumdan taşınmaz
return session
# Her yeni IP için — yeni bir oturum
for proxy in proxies:
session = create_fresh_session(proxy)
response = session.get("https://example.com/protected-page")
# Yanıtı işleyin...
Proxy ve rate limiting ile çalışırken yaygın hatalar
Doğru yapılandırılmış proxy'lerle bile, geliştiriciler sık sık aynı hatalara düşer. İşte en yaygın hatalar ve bunlardan nasıl kaçınılacağı.
Kontrol listesi: parser'ı başlatmadan önce neyi kontrol etmelisiniz
- ☐ Gerçekçi HTTP başlıkları eklendi (User-Agent, Accept, Accept-Language)
- ☐ Proxy değiştirildiğinde yeni bir oturum oluşturuluyor (yeni çerezler)
- ☐ 429, 503, 403 durumları retry mantığı ile işleniyor
- ☐ İstekler arasında gecikme uygulanıyor (en az 100–500 ms)
- ☐ Proxy sayısı hedef istek hızına uygun
- ☐ Başlatmadan önce proxy'lerin çalıştığı kontrol edildi (health check)
- ☐ Hatalar ve her proxy için istatistikler kaydediliyor
- ☐ İstekler için zaman aşımı ayarlandı (en fazla 15–30 saniye)
Hata 1: "Ölü" proxy kullanımı
Proxy'leri havuza eklemeden önce her zaman kontrol edin ve çalışma sırasında periyodik olarak kontrol edin. Bir çalışmayan proxy döngüde — kaybedilen istekler ve zaman aşımı demektir:
def check_proxy(proxy_url, test_url="https://httpbin.org/ip", timeout=5):
try:
r = requests.get(
test_url,
proxies={"http": proxy_url, "https": proxy_url},
timeout=timeout
)
return r.status_code == 200
except:
return False
# Başlatmadan önce çalışan proxy'leri filtrele
working_proxies = [p for p in PROXIES if check_proxy(p)]
print(f"Çalışan proxy'ler: {len(working_proxies)}/{len(PROXIES)}")
Hata 2: Protokol türünü göz ardı etme
HTTP proxy'leri doğrudan HTTPS trafiğini proxyleyemez (yalnızca CONNECT üzerinden). SOCKS5 proxy'leri, taşıma katmanında çalışır ve her türlü protokolü destekler. Çoğu modern site için SOCKS5 veya HTTPS proxy kullanın:
# SOCKS5 proxy requests içinde (pip install requests[socks] gerektirir)
proxies = {
"http": "socks5://user:[email protected]:1080",
"https": "socks5://user:[email protected]:1080",
}
# HTTPS proxy
proxies = {
"http": "https://user:[email protected]:8080",
"https": "https://user:[email protected]:8080",
}
Hata 3: Üstel geri dönüşün olmaması
Eğer 429'dan sonra hemen isteği tekrar ederseniz — durumu daha da kötüleştirirsiniz. Doğru strateji — üstel gecikme ile jitter (rastgele sapma):
import random
def exponential_backoff(attempt, base=1, max_wait=60):
"""
attempt: girişim numarası (0'dan başlayarak)
base: saniye cinsinden temel gecikme
max_wait: maksimum gecikme
"""
wait = min(base * (2 ** attempt), max_wait)
# Jitter ±%25, thundering herd'i önlemek için
jitter = wait * 0.25 * random.uniform(-1, 1)
return wait + jitter
# Retry mantığında kullanım
for attempt in range(5):
response = requests.get(url, proxies=proxy)
if response.status_code == 429:
wait = exponential_backoff(attempt)
print(f"Rate limit uygulandı. {wait:.1f}s bekleniyor (girişim {attempt+1})")
time.sleep(wait)
else:
break
Hata 4: Tüm proxy'ler için tek bir thread kullanımı
Eğer 50 proxy'niz varsa ama sadece bir yürütme thread'i varsa — aynı anda en fazla 1 proxy kullanıyorsunuz. ThreadPoolExecutor veya asenkron yaklaşım kullanarak tüm havuzu paralel olarak kullanın:
from concurrent.futures import ThreadPoolExecutor, as_completed
def fetch_url(args):
url, proxy = args
try:
r = requests.get(url, proxies={"https": proxy}, timeout=10)
return url, r.status_code, len(r.text)
except Exception as e:
return url, None, str(e)
# Tüm proxy'leri paralel olarak kullan
tasks = [(url, proxies[i % len(proxies)]) for i, url in enumerate(urls)]
with ThreadPoolExecutor(max_workers=len(proxies)) as executor:
futures = {executor.submit(fetch_url, task): task for task in tasks}
for future in as_completed(futures):
url, status, size = future.result()
print(f"{url}: {status} ({size})")
Sonuç ve öneriler
Rate limiting — sistematik bir şekilde yaklaşıldığında çözülebilir bir problemdir. Bu kılavuzdan ana çıkarımlar:
- Proxy havuzu, tek bir proxy değil — ciddi bir çalışma için minimum birimdir. Proxy sayısı, formül ile belirlenir: hedef hız ÷ sunucu limiti IP başına.
- Döngüleme stratejisi önemlidir — stateless istekler için per-request, yetkilendirilmiş senaryolar için sticky sessions.
- IP — tek parametre değildir — başlıklar, çerezler, TLS fingerprint ve davranış kalıpları da koruma sistemleri tarafından analiz edilir.
- 429'u doğru bir şekilde işleyin — üstel geri dönüş, Retry-After başlığı, engelleme durumunda proxy değişimi.
- Proxy türü amaca bağlıdır — açık API'ler için veri merkezi, pazaryerleri için konut, maksimum koruma için mobil.
Eğer pazaryerleri (Wildberries, Ozon) ile veri çekme, korumalı API'lerden veri toplama veya yüksek hızlarda otomasyon ile çalışıyorsanız — konut proxy'leri ile başlamanızı öneririz: anonimlik ve hız arasında optimal dengeyi sağlarlar ve IP adresleri neredeyse hiç kara listeye alınmaz. Yüksek istek frekansında engellemelere karşı maksimum dayanıklılık gerektiren görevler için mobil proxy'leri düşünmelisiniz — bu IP'ler binlerce gerçek kullanıcı tarafından paylaşılır, bu da herhangi bir site için engellemeyi son derece istenmeyen hale getirir.