Zurück zum Blog

Wie man Timeout-Fehler bei der Arbeit über Proxy behebt

Timeout-Fehler über Proxy — ein häufiges Problem beim Web-Scraping und der Automatisierung. Wir analysieren die Ursachen und bieten funktionierende Lösungen mit Code-Beispielen.

📅15. Dezember 2025
```html

Wie man Timeout-Fehler bei der Arbeit über einen Proxy behebt

Die Anfrage hängt fest, das Skript stürzt mit dem Fehler TimeoutError ab, die Daten werden nicht empfangen. Kommt dir das bekannt vor? Timeout-Fehler über einen Proxy sind eines der häufigsten Probleme beim Scraping und bei der Automatisierung. Lassen Sie uns die Ursachen analysieren und konkrete Lösungen geben.

Warum treten Timeout-Fehler auf

Ein Timeout ist nicht ein Problem, sondern ein Symptom. Bevor man behandelt, muss man die Ursache verstehen:

Langsamer Proxy-Server. Ein überladener Server oder ein geografisch entfernter Proxy fügt jeder Anfrage eine Verzögerung hinzu. Wenn Ihr Timeout 10 Sekunden beträgt, der Proxy aber 12 Sekunden antwortet – Fehler.

Blockierung durch die Zielwebsite. Die Website kann verdächtige Anfragen absichtlich „aufhängen", anstatt sie explizit abzulehnen. Dies ist eine Taktik gegen Bots – die Verbindung unendlich offen halten.

DNS-Probleme. Der Proxy muss die Domain auflösen. Wenn der DNS-Server des Proxys langsam oder nicht erreichbar ist – hängt die Anfrage in der Verbindungsphase fest.

Falsche Timeout-Konfiguration. Ein allgemeiner Timeout für alles – ein häufiger Fehler. Connect-Timeout und Read-Timeout sind unterschiedliche Dinge und müssen separat konfiguriert werden.

Netzwerkprobleme. Paketverlust, instabile Proxy-Verbindung, Routing-Probleme – all dies führt zu Timeouts.

Timeout-Typen und deren Konfiguration

Die meisten HTTP-Bibliotheken unterstützen mehrere Timeout-Typen. Das Verständnis der Unterschiede zwischen ihnen ist der Schlüssel zur richtigen Konfiguration.

Connect-Timeout

Zeit zum Aufbau einer TCP-Verbindung mit dem Proxy und dem Zielserver. Wenn der Proxy nicht erreichbar ist oder der Server nicht antwortet – dieser Timeout wird ausgelöst. Empfohlener Wert: 5-10 Sekunden.

Read-Timeout

Wartezeit auf Daten nach Verbindungsaufbau. Der Server hat sich verbunden, schweigt aber – Read-Timeout wird ausgelöst. Für normale Seiten: 15-30 Sekunden. Für schwere APIs: 60+ Sekunden.

Gesamt-Timeout

Gesamtzeit für die gesamte Anfrage von Anfang bis Ende. Versicherung gegen hängende Verbindungen. Normalerweise: Connect + Read + Reserve.

Beispiel der Konfiguration in Python mit der Bibliothek requests:

import requests

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

# Tupel: (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("Verbindung zum Proxy oder Server fehlgeschlagen")
except requests.exceptions.ReadTimeout:
    print("Server hat Daten nicht rechtzeitig gesendet")

Für aiohttp (asynchrones Python):

import aiohttp
import asyncio

async def fetch_with_timeout():
    timeout = aiohttp.ClientTimeout(
        total=60,      # Gesamt-Timeout
        connect=10,    # Zum Verbinden
        sock_read=30   # Zum Datenlesen
    )
    
    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-Logik: der richtige Ansatz

Ein Timeout ist nicht immer ein Fehler. Oft ist eine wiederholte Anfrage erfolgreich. Aber Retry muss intelligent durchgeführt werden.

Exponentielle Verzögerung

Bombardieren Sie den Server nicht ohne Pause mit wiederholten Anfragen. Verwenden Sie exponentiellen Backoff: jeder nächste Versuch – mit zunehmender Verzögerung.

import requests
import time
import random

def fetch_with_retry(url, proxies, max_retries=3):
    """Anfrage mit Retry und exponentieller Verzögerung"""
    
    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  # Letzter Versuch – Fehler werfen
            
            # Exponentielle Verzögerung: 1s, 2s, 4s...
            # + zufälliger Jitter um keine Anfragewellen zu erzeugen
            delay = (2 ** attempt) + random.uniform(0, 1)
            print(f"Versuch {attempt + 1} fehlgeschlagen: {e}")
            print(f"Wiederholung in {delay:.1f} Sekunden...")
            time.sleep(delay)

Bibliothek tenacity

Für Production-Code ist es bequemer, fertige Lösungen zu verwenden:

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()

Proxy-Rotation bei Timeouts

Wenn ein Proxy ständig Timeouts verursacht – liegt das Problem bei ihm. Logische Lösung: zu einem anderen wechseln.

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

@dataclass
class ProxyManager:
    """Proxy-Manager mit Verfolgung fehlgeschlagener Versuche"""
    
    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]:
        """Funktionierenden Proxy abrufen"""
        current_time = time.time()
        
        for proxy in self.proxies:
            # Proxys in Cooldown überspringen
            if self._cooldown_until.get(proxy, 0) > current_time:
                continue
            return proxy
        
        return None  # Alle Proxys in Cooldown
    
    def report_failure(self, proxy: str):
        """Über fehlgeschlagene Anfrage berichten"""
        self._failures[proxy] = self._failures.get(proxy, 0) + 1
        
        if self._failures[proxy] >= self.max_failures:
            # Proxy in Cooldown versetzen
            self._cooldown_until[proxy] = time.time() + self.cooldown_seconds
            self._failures[proxy] = 0
            print(f"Proxy {proxy} in Cooldown versetzt")
    
    def report_success(self, proxy: str):
        """Fehlerzähler bei Erfolg zurücksetzen"""
        self._failures[proxy] = 0


def fetch_with_rotation(url, proxy_manager, max_attempts=5):
    """Anfrage mit automatischem Proxy-Wechsel bei Fehlern"""
    
    for attempt in range(max_attempts):
        proxy = proxy_manager.get_proxy()
        
        if not proxy:
            raise Exception("Keine verfügbaren Proxys")
        
        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"Timeout über {proxy}, versuchen wir einen anderen...")
            continue
    
    raise Exception(f"Daten nach {max_attempts} Versuchen nicht abrufbar")

Bei Verwendung von Residential-Proxys mit automatischer Rotation vereinfacht sich diese Logik – der Anbieter wechselt die IP bei jedem Request oder nach einem festgelegten Intervall automatisch.

Asynchrone Anfragen mit Timeout-Kontrolle

Bei Massen-Scraping sind synchrone Anfragen ineffizient. Der asynchrone Ansatz ermöglicht die parallele Verarbeitung von Hunderten von URLs, erfordert aber sorgfältige Arbeit mit Timeouts.

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]:
    """Laden einer URL mit Timeout-Verarbeitung"""
    
    async with semaphore:  # Parallelität begrenzen
        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]]:
    """Massen-Download mit Timeout- und Parallelitätskontrolle"""
    
    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  # Nicht mehr als 5 Verbindungen pro Host
    )
    
    async with aiohttp.ClientSession(
        timeout=timeout,
        connector=connector
    ) as session:
        # Proxy für alle Anfragen setzen
        tasks = [
            fetch_one(session, url, semaphore) 
            for url in urls
        ]
        results = await asyncio.gather(*tasks)
    
    # Statistik
    success = sum(1 for _, content, _ in results if content)
    timeouts = sum(1 for _, _, error in results if error == "timeout")
    print(f"Erfolgreich: {success}, Timeouts: {timeouts}")
    
    return results


# Verwendung
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())

Wichtig: Setzen Sie nicht zu hohe Parallelität. 50-100 gleichzeitige Anfragen über einen Proxy – das ist bereits viel. Besser 10-20 mit mehreren Proxys.

Diagnose: Wie man die Ursache findet

Bevor Sie die Einstellungen ändern, bestimmen Sie die Fehlerquelle.

Schritt 1: Proxy direkt prüfen

# Einfacher Test über curl mit Zeitmessung
curl -x http://user:pass@proxy:8080 \
     -w "Connect: %{time_connect}s\nTotal: %{time_total}s\n" \
     -o /dev/null -s \
     https://httpbin.org/get

Wenn time_connect mehr als 5 Sekunden beträgt – Problem mit Proxy oder Netzwerk zu ihm.

Schritt 2: Mit direkter Anfrage vergleichen

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"OK: {elapsed:.2f}s, status: {r.status_code}"
    except Exception as e:
        elapsed = time.time() - start
        return f"FAIL: {elapsed:.2f}s, error: {type(e).__name__}"

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

print("Direkt:", measure_request(url))
print("Über Proxy:", measure_request(url, proxy))

Schritt 3: Verschiedene Proxy-Typen prüfen

Timeouts können vom Proxy-Typ abhängen:

Proxy-Typ Typische Verzögerung Empfohlener Timeout
Datacenter 50-200 ms Connect: 5s, Read: 15s
Residential 200-800 ms Connect: 10s, Read: 30s
Mobile 300-1500 ms Connect: 15s, Read: 45s

Schritt 4: Details protokollieren

import logging
import requests
from requests.adapters import HTTPAdapter

# Debug-Protokollierung aktivieren
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.DEBUG)

# Jetzt sehen Sie alle Phasen der Anfrage:
# - DNS-Auflösung
# - Verbindungsaufbau
# - Anfrage senden
# - Antwort erhalten

Checkliste zur Behebung von Timeout-Fehlern

Kurzer Aktionsalgorithmus bei Timeout-Fehlern:

  1. Timeout-Typ bestimmen – Connect oder Read? Das sind unterschiedliche Probleme.
  2. Proxy separat prüfen – Funktioniert er überhaupt? Welche Verzögerung?
  3. Timeouts erhöhen – Möglicherweise sind die Werte zu aggressiv für Ihren Proxy-Typ.
  4. Retry mit Backoff hinzufügen – Einzelne Timeouts sind normal, Stabilität ist wichtig.
  5. Rotation konfigurieren – Automatisch zu einem anderen Proxy wechseln bei Problemen.
  6. Parallelität begrenzen – Zu viele gleichzeitige Anfragen überlasten den Proxy.
  7. Zielwebsite prüfen – Möglicherweise blockiert oder drosselt sie Ihre Anfragen.

Fazit

Timeout-Fehler über einen Proxy sind ein lösbares Problem. In den meisten Fällen reicht es aus, die Timeouts richtig für den Proxy-Typ zu konfigurieren, Retry-Logik hinzuzufügen und Rotation bei Ausfällen zu implementieren. Für Aufgaben mit hohen Stabilitätsanforderungen verwenden Sie Residential-Proxys mit automatischer Rotation – mehr Details auf proxycove.com.

```