Bloga geri dön

Proxy Kullanırken Timeout Hatalarını Düzeltme Yöntemi

Proxy üzerinden timeout hataları - parsing ve otomasyon sırasında yaygın bir sorun. Nedenleri analiz ediyoruz ve çalışan çözümleri kod örnekleriyle sunuyoruz.

📅15 Aralık 2025
```html

Proksiler aracılığıyla timeout hatalarını nasıl düzeltilir

İstek asılı kaldı, betik TimeoutError hatası ile çöktü, veriler alınamadı. Tanıdık bir durum mu? Proksiler aracılığıyla timeout hataları — ayrıştırma ve otomasyon sırasında en sık karşılaşılan sorunlardan biridir. Nedenleri analiz edelim ve somut çözümler sunalım.

Timeout hataları neden oluşur

Timeout — tek bir sorun değil, bir semptom. Tedavi etmeden önce, nedeni anlamalıyız:

Yavaş proksiler sunucusu. Aşırı yüklü bir sunucu veya coğrafi olarak uzak bir proksiler her istekte gecikme ekler. Timeout'unuz 10 saniye ise ve proksiler 12 saniyede yanıt verirse — hata oluşur.

Hedef sitede engelleme. Site, açık bir reddetme yerine şüpheli istekleri kasıtlı olarak "asılı" bırakabilir. Bu botlara karşı bir taktiktir — bağlantıyı sonsuza kadar açık tutmak.

DNS sorunları. Proksiler alanı çözümlemesi gerekir. Proksinin DNS sunucusu yavaş veya erişilemez ise — istek bağlantı aşamasında asılı kalır.

Yanlış timeout ayarları. Tüm şeyler için tek bir genel timeout — sık yapılan bir hata. Connect timeout ve read timeout — farklı şeylerdir ve ayrı ayrı ayarlanmalıdır.

Ağ sorunları. Paket kaybı, proksinin kararsız bağlantısı, yönlendirme sorunları — tüm bunlar timeout'lara neden olur.

Timeout türleri ve ayarlanması

Çoğu HTTP kütüphanesi birkaç timeout türünü destekler. Aralarındaki farkı anlamak — doğru ayarlamanın anahtarıdır.

Connect timeout

Proksiler ve hedef sunucu ile TCP bağlantısı kurma süresi. Proksiler erişilemez veya sunucu yanıt vermiyorsa — bu timeout tetiklenir. Önerilen değer: 5-10 saniye.

Read timeout

Bağlantı kurulduktan sonra veri bekleme süresi. Sunucu bağlandı ama sessiz — read timeout tetiklenir. Normal sayfalar için: 15-30 saniye. Ağır API'ler için: 60+ saniye.

Total timeout

Başından sonuna kadar tüm istek için geçen süre. Asılı bağlantılara karşı sigorta. Genellikle: connect + read + yedek.

Python'da requests kütüphanesi ile ayarlama örneği:

import requests

proxies = {
    "http": "http://user:pass@proxy.example.com:8080",
    "https": "http://user:pass@proxy.example.com:8080"
}

# Tuple: (connect_timeout, read_timeout)
timeout = (10, 30)

try:
    response = requests.get(
        "https://target-site.com/api/data",
        proxies=proxies,
        timeout=timeout
    )
except requests.exceptions.ConnectTimeout:
    print("Proksiler veya sunucuya bağlanılamadı")
except requests.exceptions.ReadTimeout:
    print("Sunucu zamanında veri göndermedi")

aiohttp (asenkron Python) için:

import aiohttp
import asyncio

async def fetch_with_timeout():
    timeout = aiohttp.ClientTimeout(
        total=60,      # Genel timeout
        connect=10,    # Bağlantı için
        sock_read=30   # Veri okuma için
    )
    
    async with aiohttp.ClientSession(timeout=timeout) as session:
        async with session.get(
            "https://target-site.com/api/data",
            proxy="http://user:pass@proxy.example.com:8080"
        ) as response:
            return await response.text()

Retry-mantığı: doğru yaklaşım

Timeout — her zaman ölümcül bir hata değildir. Çoğu zaman tekrarlanan istek başarılı olur. Ancak retry akıllıca yapılmalıdır.

Üstel gecikme

Sunucuyu duraklamadan tekrarlanan isteklerle bombardıman etmeyin. Üstel backoff kullanın: her sonraki deneme — artan gecikme ile.

import requests
import time
import random

def fetch_with_retry(url, proxies, max_retries=3):
    """Retry ve üstel gecikme ile istek"""
    
    for attempt in range(max_retries):
        try:
            response = requests.get(
                url,
                proxies=proxies,
                timeout=(10, 30)
            )
            response.raise_for_status()
            return response
            
        except (requests.exceptions.Timeout, 
                requests.exceptions.ConnectionError) as e:
            
            if attempt == max_retries - 1:
                raise  # Son deneme — hatayı fırlat
            
            # Üstel gecikme: 1s, 2s, 4s...
            # + istek dalgalarını oluşturmamak için rastgele jitter
            delay = (2 ** attempt) + random.uniform(0, 1)
            print(f"Deneme {attempt + 1} başarısız: {e}")
            print(f"{delay:.1f} saniye sonra yeniden dene...")
            time.sleep(delay)

tenacity kütüphanesi

Production kodu için hazır çözümleri kullanmak daha uygun:

from tenacity import retry, stop_after_attempt, wait_exponential
from tenacity import retry_if_exception_type
import requests

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=1, max=10),
    retry=retry_if_exception_type((
        requests.exceptions.Timeout,
        requests.exceptions.ConnectionError
    ))
)
def fetch_data(url, proxies):
    response = requests.get(url, proxies=proxies, timeout=(10, 30))
    response.raise_for_status()
    return response.json()

Timeout'larda proksinin rotasyonu

Bir proksiler sürekli timeout veriyorsa — sorun onun içinde. Mantıklı çözüm: başka birine geç.

import requests
from collections import deque
from dataclasses import dataclass, field
from typing import Optional
import time

@dataclass
class ProxyManager:
    """Başarısız denemeleri izleyen proksiler yöneticisi"""
    
    proxies: list
    max_failures: int = 3
    cooldown_seconds: int = 300
    _failures: dict = field(default_factory=dict)
    _cooldown_until: dict = field(default_factory=dict)
    
    def get_proxy(self) -> Optional[str]:
        """Çalışan proksiler al"""
        current_time = time.time()
        
        for proxy in self.proxies:
            # Cooldown'daki proksileri atla
            if self._cooldown_until.get(proxy, 0) > current_time:
                continue
            return proxy
        
        return None  # Tüm proksiler cooldown'da

    def report_failure(self, proxy: str):
        """Başarısız istek hakkında bildir"""
        self._failures[proxy] = self._failures.get(proxy, 0) + 1
        
        if self._failures[proxy] >= self.max_failures:
            # Proksiler cooldown'a gönder
            self._cooldown_until[proxy] = time.time() + self.cooldown_seconds
            self._failures[proxy] = 0
            print(f"Proksiler {proxy} cooldown'a gönderildi")
    
    def report_success(self, proxy: str):
        """Başarı durumunda hata sayacını sıfırla"""
        self._failures[proxy] = 0


def fetch_with_rotation(url, proxy_manager, max_attempts=5):
    """Hatalar durumunda otomatik proksiler değişimi ile istek"""
    
    for attempt in range(max_attempts):
        proxy = proxy_manager.get_proxy()
        
        if not proxy:
            raise Exception("Kullanılabilir proksiler yok")
        
        proxies = {"http": proxy, "https": proxy}
        
        try:
            response = requests.get(url, proxies=proxies, timeout=(10, 30))
            response.raise_for_status()
            proxy_manager.report_success(proxy)
            return response
            
        except (requests.exceptions.Timeout, 
                requests.exceptions.ConnectionError):
            proxy_manager.report_failure(proxy)
            print(f"{proxy} üzerinden timeout, başka bir tane dene...")
            continue
    
    raise Exception(f"{max_attempts} denemeden sonra veri alınamadı")

Konut proksilerini otomatik rotasyon ile kullanırken bu mantık basitleşir — sağlayıcı her istek veya belirtilen aralıkta IP'yi kendisi değiştirir.

Timeout kontrolü ile asenkron istekler

Toplu ayrıştırma sırasında senkron istekler verimsizdir. Asenkron yaklaşım yüzlerce URL'yi paralel olarak işlemeyi sağlar, ancak timeout'larla dikkatli çalışmayı gerektirir.

import aiohttp
import asyncio
from typing import List, Tuple

async def fetch_one(
    session: aiohttp.ClientSession, 
    url: str,
    semaphore: asyncio.Semaphore
) -> Tuple[str, str | None, str | None]:
    """Timeout işleme ile bir URL'nin yüklenmesi"""
    
    async with semaphore:  # Paralelliği sınırla
        try:
            async with session.get(url) as response:
                content = await response.text()
                return (url, content, None)
                
        except asyncio.TimeoutError:
            return (url, None, "timeout")
        except aiohttp.ClientError as e:
            return (url, None, str(e))


async def fetch_all(
    urls: List[str],
    proxy: str,
    max_concurrent: int = 10
) -> List[Tuple[str, str | None, str | None]]:
    """Timeout ve paralellik kontrolü ile toplu yükleme"""
    
    timeout = aiohttp.ClientTimeout(total=45, connect=10, sock_read=30)
    semaphore = asyncio.Semaphore(max_concurrent)
    
    connector = aiohttp.TCPConnector(
        limit=max_concurrent,
        limit_per_host=5  # Bir ana bilgisayara en fazla 5 bağlantı
    )
    
    async with aiohttp.ClientSession(
        timeout=timeout,
        connector=connector
    ) as session:
        # Tüm istekler için proksiler ayarla
        tasks = [
            fetch_one(session, url, semaphore) 
            for url in urls
        ]
        results = await asyncio.gather(*tasks)
    
    # İstatistikler
    success = sum(1 for _, content, _ in results if content)
    timeouts = sum(1 for _, _, error in results if error == "timeout")
    print(f"Başarılı: {success}, Timeout'lar: {timeouts}")
    
    return results


# Kullanım
async def main():
    urls = [f"https://example.com/page/{i}" for i in range(100)]
    results = await fetch_all(
        urls, 
        proxy="http://user:pass@proxy.example.com:8080",
        max_concurrent=10
    )

asyncio.run(main())

Önemli: Çok yüksek paralellik ayarlamayın. Bir proksiler üzerinden 50-100 eşzamanlı istek — zaten çoktur. 10-20 ile birkaç proksiler daha iyidir.

Tanı: nedeni nasıl bulunur

Ayarları değiştirmeden önce sorunun kaynağını belirleyin.

Adım 1: Proksileri doğrudan kontrol edin

# Curl ile basit test ve zaman ölçümü
curl -x http://user:pass@proxy:8080 \
     -w "Bağlan: %{time_connect}s\nToplam: %{time_total}s\n" \
     -o /dev/null -s \
     https://httpbin.org/get

Eğer time_connect 5 saniyeden fazla ise — proksiler veya ona kadar olan ağ ile sorun var.

Adım 2: Doğrudan istek ile karşılaştırın

import requests
import time

def measure_request(url, proxies=None):
    start = time.time()
    try:
        r = requests.get(url, proxies=proxies, timeout=30)
        elapsed = time.time() - start
        return f"TAMAM: {elapsed:.2f}s, durum: {r.status_code}"
    except Exception as e:
        elapsed = time.time() - start
        return f"BAŞARISIZ: {elapsed:.2f}s, hata: {type(e).__name__}"

url = "https://target-site.com"
proxy = {"http": "http://proxy:8080", "https": "http://proxy:8080"}

print("Doğrudan:", measure_request(url))
print("Proksiler aracılığıyla:", measure_request(url, proxy))

Adım 3: Farklı proksiler türlerini kontrol edin

Timeout'lar proksiler türüne bağlı olabilir:

Proksiler türü Tipik gecikme Önerilen timeout
Veri merkezi 50-200 ms Bağlan: 5s, Oku: 15s
Konut 200-800 ms Bağlan: 10s, Oku: 30s
Mobil 300-1500 ms Bağlan: 15s, Oku: 45s

Adım 4: Ayrıntıları günlüğe kaydedin

import logging
import requests
from requests.adapters import HTTPAdapter

# Debug-günlüğünü etkinleştir
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.DEBUG)

# Şimdi istekle ilgili tüm aşamaları göreceksiniz:
# - DNS çözümleme
# - Bağlantı kurma
# - İstek gönderme
# - Yanıt alma

Timeout hatalarını çözmek için kontrol listesi

Timeout hataları oluştuğunda eylem algoritması:

  1. Timeout türünü belirleyin — connect mi yoksa read mi? Bunlar farklı sorunlardır.
  2. Proksileri ayrı kontrol edin — çalışıyor mu? Gecikme ne kadar?
  3. Timeout'ları artırın — değerler proksiler türü için çok agresif olabilir.
  4. Backoff ile retry ekleyin — tek timeout'lar normaldir, önemli olan dayanıklılıktır.
  5. Rotasyonu ayarlayın — sorunlar durumunda başka proksilere otomatik geçiş yapın.
  6. Paralelliği sınırlandırın — çok fazla eşzamanlı istek proksileri aşırı yükler.
  7. Hedef siteyi kontrol edin — muhtemelen isteklerinizi engelliyor veya throttle ediyor.

Sonuç

Proksiler aracılığıyla timeout hataları — çözülebilir bir sorundur. Çoğu durumda proksiler türü için timeout'ları doğru ayarlamak, retry-mantığı eklemek ve hata durumunda rotasyon uygulamak yeterlidir. Yüksek güvenilirlik gereksinimleri olan görevler için otomatik rotasyonlu konut proksilerini kullanın — daha fazla bilgi için proxycove.com'u ziyaret edin.

```