> ## Documentation Index
> Fetch the complete documentation index at: https://docs.olostep.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Olostep Python SDK

> Offizielles Python SDK zum Suchen, Extrahieren und Strukturieren von Daten aus dem Web

<Note>
  **PyPI-Paket**: [olostep](https://pypi.org/project/olostep/) | **Anforderungen**: Python 3.11+
</Note>

## Installation

<CodeGroup>
  ```bash pip theme={null}
  pip install olostep
  ```

  ```bash pip3 theme={null}
  pip3 install olostep
  ```

  ```bash poetry theme={null}
  poetry add olostep
  ```

  ```bash uv theme={null}
  uv pip install olostep
  ```
</CodeGroup>

## Authentifizierung

Hole dir deinen API-Schlüssel vom [Olostep Dashboard](https://www.olostep.com/dashboard/).

## Schnellstart

Das SDK bietet zwei Client-Optionen, je nach Anwendungsfall:

<CardGroup cols={2}>
  <Card title="Sync Client (`Olostep`)" href="/sdks/python#sync-client-olostep" icon="sync">
    Am besten geeignet für: Skripte und einfache Anwendungsfälle, bei denen du blockierende Operationen bevorzugst.<br /><br />
    Der Sync-Client bietet eine einfachere, blockierende Schnittstelle, die leichter zu verwenden ist, wenn du neu bei async/await bist.
  </Card>

  <Card title="Async Client (`AsyncOlostep`)" href="/sdks/python#async-client-asyncolostep" icon="zap">
    Am besten geeignet für: Produktionsanwendungen und die Verarbeitung vieler gleichzeitiger Anfragen.<br /><br />
    Der Async-Client bietet nicht-blockierende Operationen und ist die empfohlene Wahl für Produktionsanwendungen, die hohe Durchsätze benötigen.
  </Card>
</CardGroup>

# Sync Client (Olostep)

Der Sync-Client (`Olostep`) bietet eine blockierende Schnittstelle, die perfekt für Skripte und einfache Anwendungsfälle geeignet ist.

```python theme={null}
from olostep import Olostep

# Gib den API-Schlüssel entweder über den 'api_key'-Parameter an oder
# setze die Umgebungsvariable OLOSTEP_API_KEY

# Der Sync-Client verwaltet Ressourcen automatisch
# Kein explizites Schließen nötig - Ressourcen werden nach jeder Operation bereinigt
client = Olostep(api_key="YOUR_REAL_KEY")
scrape_result = client.scrapes.create(url_to_scrape="https://example.com")
```

### Einfaches Web-Scraping

```python theme={null}
from olostep import Olostep

client = Olostep(api_key="your-api-key")

# Einfaches Scraping
result = client.scrapes.create(url_to_scrape="https://example.com")
print(f"Scraped {len(result.html_content)} Zeichen")

# Mehrere Formate
result = client.scrapes.create(
    url_to_scrape="https://example.com",
    formats=["html", "markdown"]
)
print(f"HTML: {len(result.html_content)} Zeichen")
print(f"Markdown: {len(result.markdown_content)} Zeichen")
```

### Batch-Verarbeitung

```python theme={null}
from olostep import Olostep

client = Olostep(api_key="your-api-key")

# Verarbeite mehrere URLs effizient
batch = client.batches.create(
    urls=[
        "https://www.google.com/search?q=python",
        "https://www.google.com/search?q=javascript",
        "https://www.google.com/search?q=typescript"
    ]
)

# Warte auf Abschluss und verarbeite Ergebnisse
for item in batch.items():
    content = item.retrieve(["html"])
    print(f"Verarbeitet {item.url}: {len(content.html_content)} Bytes")
```

### Intelligentes Web-Crawling

```python theme={null}
from olostep import Olostep

client = Olostep(api_key="your-api-key")

# Crawle mit intelligentem Filtern
crawl = client.crawls.create(
    start_url="https://www.bbc.com",
    max_pages=100,
    include_urls=["/articles/**", "/blog/**"],
    exclude_urls=["/admin/**"]
)

for page in crawl.pages():
    content = page.retrieve(["html"])
    print(f"Gecrawlt: {page.url}")
```

### Site-Mapping

```python theme={null}
from olostep import Olostep

client = Olostep(api_key="your-api-key")

# Extrahiere alle Links von einer Website
maps = client.maps.create(url="https://example.com")

# Hole alle entdeckten URLs
urls = []
for url in maps.urls():
    urls.append(url)
    if len(urls) >= 10:  # Limit für Demo
        break

print(f"Gefundene URLs: {len(urls)}")
```

### KI-gestützte Antworten

```python theme={null}
from olostep import Olostep

client = Olostep(api_key="your-api-key")

# Hole Antworten von Webseiten mit KI
answer = client.answers.create(
    task="What is the main topic of https://example.com?"
)
print(f"Antwort: {answer.answer}")
```

# Async Client (AsyncOlostep)

Der Async-Client (`AsyncOlostep`) ist der empfohlene Client für Hochleistungsanwendungen, Backend-Dienste und wenn du viele gleichzeitige Anfragen verarbeiten musst.

```python theme={null}
from olostep import AsyncOlostep

# Gib den API-Schlüssel entweder über den 'api_key'-Parameter an oder
# setze die Umgebungsvariable OLOSTEP_API_KEY

# RESSOURCENVERWALTUNG
# ===================
# Das SDK unterstützt zwei Nutzungsmuster für die Ressourcenverwaltung:

# 1. Kontext-Manager (Empfohlen für einmalige Nutzung):
#    Handhabt die Ressourcenbereinigung automatisch
async with AsyncOlostep(api_key="YOUR_REAL_KEY") as client:
    scrape_result = await client.scrapes.create(url_to_scrape="https://example.com")
# Transport wird hier automatisch geschlossen

# 2. Explizites Schließen (Für langlebige Dienste):
#    Erfordert manuelle Ressourcenbereinigung
client = AsyncOlostep(api_key="YOUR_REAL_KEY")
try:
    scrape_result = await client.scrapes.create(url_to_scrape="https://example.com")
finally:
    await client.close()  # Transport manuell schließen
```

### Einfaches Web-Scraping

```python theme={null}
import asyncio
from olostep import AsyncOlostep

async def main():
    async with AsyncOlostep(api_key="your-api-key") as client:
        # Einfaches Scraping
        result = await client.scrapes.create(url_to_scrape="https://example.com")
        print(f"Scraped {len(result.html_content)} Zeichen")

        # Mehrere Formate
        result = await client.scrapes.create(
            url_to_scrape="https://example.com",
            formats=["html", "markdown"]
        )
        print(f"HTML: {len(result.html_content)} Zeichen")
        print(f"Markdown: {len(result.markdown_content)} Zeichen")

asyncio.run(main())
```

### Batch-Verarbeitung

```python theme={null}
import asyncio
from olostep import AsyncOlostep

async def main():
    async with AsyncOlostep(api_key="your-api-key") as client:
        # Verarbeite mehrere URLs effizient
        batch = await client.batches.create(
            urls=[
                "https://www.google.com/search?q=python",
                "https://www.google.com/search?q=javascript",
                "https://www.google.com/search?q=typescript"
            ]
        )

        # Warte auf Abschluss und verarbeite Ergebnisse
        async for item in batch.items():
            content = await item.retrieve(["html"])
            print(f"Verarbeitet {item.url}: {len(content.html_content)} Bytes")

asyncio.run(main())
```

### Intelligentes Web-Crawling

```python theme={null}
import asyncio
from olostep import AsyncOlostep

async def main():
    async with AsyncOlostep(api_key="your-api-key") as client:
        # Crawle mit intelligentem Filtern
        crawl = await client.crawls.create(
            start_url="https://www.bbc.com",
            max_pages=100,
            include_urls=["/articles/**", "/blog/**"],
            exclude_urls=["/admin/**"]
        )

        async for page in crawl.pages():
            content = await page.retrieve(["html"])
            print(f"Gecrawlt: {page.url}")

asyncio.run(main())
```

### Site-Mapping

```python theme={null}
import asyncio
from olostep import AsyncOlostep

async def main():
    async with AsyncOlostep(api_key="your-api-key") as client:
        # Extrahiere alle Links von einer Website
        maps = await client.maps.create(url="https://example.com")

        # Hole alle entdeckten URLs
        urls = []
        async for url in maps.urls():
            urls.append(url)
            if len(urls) >= 10:  # Limit für Demo
                break

        print(f"Gefundene URLs: {len(urls)}")

asyncio.run(main())
```

### KI-gestützte Antworten

```python theme={null}
import asyncio
from olostep import AsyncOlostep

async def main():
    async with AsyncOlostep(api_key="your-api-key") as client:
        # Hole Antworten von Webseiten mit KI
        answer = await client.answers.create(
            task="What is the main topic of https://example.com?"
        )
        print(f"Antwort: {answer.answer}")

asyncio.run(main())
```

## SDK-Referenz

### Methodenstruktur

Beide SDK-Clients bieten die gleiche saubere, pythonische Schnittstelle, die in logische Namensräume organisiert ist:

| Namensraum | Zweck                   | Schlüsselmethoden               |
| ---------- | ----------------------- | ------------------------------- |
| `scrapes`  | Einzel-URL-Extraktion   | `create()`, `get()`             |
| `batches`  | Multi-URL-Verarbeitung  | `create()`, `info()`, `items()` |
| `crawls`   | Website-Durchlauf       | `create()`, `info()`, `pages()` |
| `maps`     | Link-Extraktion         | `create()`, `urls()`            |
| `answers`  | KI-gestützte Extraktion | `create()`, `get()`             |
| `retrieve` | Inhaltsabruf            | `get()`                         |

Jede Operation gibt zustandsbehaftete Objekte mit ergonomischen Methoden für Folgeoperationen zurück.

## Fehlerbehandlung

Fange alle SDK-Fehler mit der Basisklasse der Ausnahmen:

```python theme={null}
from olostep import Olostep, Olostep_BaseError

client = Olostep(api_key="your-api-key")

try:
    result = client.scrapes.create(url_to_scrape="https://example.com")
except Olostep_BaseError as e:
    print(f"Ein Fehler ist aufgetreten: {type(e).__name__}")
    print(f"Fehlermeldung: {e}")
```

Für detaillierte Informationen zur Fehlerbehandlung, einschließlich der vollständigen Ausnahmehierarchie und granularer Fehlerbehandlungsoptionen, siehe [Detaillierte Fehlerbehandlung](/sdks/python#detailed-error-handling).

## Automatische Wiederholungen

Das SDK wiederholt automatisch bei vorübergehenden Fehlern (Netzwerkprobleme, temporäre Serverprobleme) basierend auf der `RetryStrategy`-Konfiguration. Du kannst das Wiederholungsverhalten anpassen, indem du eine `RetryStrategy`-Instanz beim Erstellen des Clients übergibst:

```python theme={null}
from olostep import Olostep, RetryStrategy

retry_strategy = RetryStrategy(
    max_retries=3,
    initial_delay=1.0,
    jitter_min=0.2,
    jitter_max=0.8
)

client = Olostep(api_key="your-api-key", retry_strategy=retry_strategy)
result = client.scrapes.create("https://example.com")
```

Für detaillierte Optionen zur Wiederholungskonfiguration und bewährte Praktiken siehe [Retry Strategy](/sdks/python#retry-strategy-configuration).

## Erweiterte Funktionen

### Intelligente Eingabekonvertierung

Das SDK verarbeitet intelligent verschiedene Eingabeformate für maximalen Komfort:

```python theme={null}
from olostep import Olostep, Country

client = Olostep(api_key="your-api-key")

# Formate: String, Liste oder Enum
client.scrapes.create(url_to_scrape="https://example.com", formats="html")
client.scrapes.create(url_to_scrape="https://example.com", formats=["html", "markdown"])

# Länder: nicht case-sensitive Strings oder Enums
client.scrapes.create(url_to_scrape="https://example.com", country="us")
client.scrapes.create(url_to_scrape="https://example.com", country=Country.US)

# Listen: Einzelwerte oder Listen
client.batches.create(urls="https://example.com")    # Einzelne URL
client.batches.create(urls=["https://a.com", "https://b.com"])  # Mehrere URLs
```

### Erweiterte Scraping-Optionen

```python theme={null}
from olostep import Olostep, Format, Country, WaitAction, FillInputAction

client = Olostep(api_key="your-api-key")

# Volle Kontrolle über das Scraping-Verhalten
result = client.scrapes.create(
    url_to_scrape="https://news.google.com/",
    wait_before_scraping=3000,
    formats=[Format.HTML, Format.MARKDOWN],
    remove_css_selectors=["script", ".popup"],
    actions=[
        WaitAction(milliseconds=1500),
        FillInputAction(selector="searchbox", value="olostep")
    ],
    parser="@olostep/google-news",
    country=Country.US,
    remove_images=True
)
```

### Caching

Standardmäßig holt jede Scrape-Anfrage die Seite frisch ab (`max_age=0`). Gib `max_age` an, um ein kürzliches Ergebnis mit denselben Parametern wiederzuverwenden und die Antwortzeit zu verbessern. Der Wert ist in **Sekunden**; das Maximum beträgt 7 Tage (`604800`). Siehe [Caching](/features/scrapes#caching) für Details.

```python theme={null}
# Opt-in für Caching: Akzeptiere Ergebnisse bis zu 1 Tag (86400 Sekunden) alt
result = client.scrapes.create(
    url_to_scrape="https://example.com",
    formats=["markdown"],
    max_age=86400
)
```

### Batch-Verarbeitung mit benutzerdefinierten IDs

```python theme={null}
from olostep import Olostep, Country

client = Olostep(api_key="your-api-key")

batch = client.batches.create([
    {"url": "https://www.google.com/search?q=python", "custom_id": "search_1"},
    {"url": "https://www.google.com/search?q=javascript", "custom_id": "search_2"},
    {"url": "https://www.google.com/search?q=typescript", "custom_id": "search_3"}
],
country=Country.US,
parser="@olostep/google-search"
)

# Verarbeite Ergebnisse nach benutzerdefinierter ID
# Beim Verwenden eines Parsers, hole JSON-Inhalt statt HTML
for item in batch.items():
    if item.custom_id == "search_2":
        content = item.retrieve(["json"])
        print(f"Suchergebnis: {content.json_content}")
```

### Intelligentes Crawling

```python theme={null}
from olostep import Olostep

client = Olostep(api_key="your-api-key")

# Crawle mit intelligentem Filtern
crawl = client.crawls.create(
    start_url="https://www.bbc.com",
    max_pages=1000,
    max_depth=3,
    include_urls=["/articles/**", "/news/**"],
    exclude_urls=["/ads/**", "/tracking/**"],
    include_external=False,
    include_subdomain=True,
)

for page in crawl.pages():
    content = page.retrieve(["html"])
    print(f"Gecrawlt: {page.url}")
```

### Site-Mapping mit Filtern

```python theme={null}
from olostep import Olostep

client = Olostep(api_key="your-api-key")

# Extrahiere alle Links mit erweitertem Filtern
maps = client.maps.create(
    url="https://www.bbc.com",
    include_subdomain=True,
    include_urls=["/articles/**", "/news/**"],
    exclude_urls=["/ads/**", "/tracking/**"]
)

# Hole gefilterte URLs
urls = []
for url in maps.urls():
    urls.append(url)

print(f"Gefundene relevante URLs: {len(urls)}")
```

### Antworten abrufen

```python theme={null}
from olostep import Olostep

client = Olostep(api_key="your-api-key")

# Erstelle zuerst eine Antwort
created_answer = client.answers.create(
    task="What is the main topic of https://example.com?"
)

# Dann rufe sie mit der ID ab
answer = client.answers.get(answer_id=created_answer.id)
print(f"Antwort: {answer.answer}")
```

### Inhaltsabruf

```python theme={null}
from olostep import Olostep

client = Olostep(api_key="your-api-key")

# Hole Inhalt nach Abruf-ID
result = client.retrieve.get(retrieve_id="ret_123")

# Hole mehrere Formate
result = client.retrieve.get(retrieve_id="ret_123", formats=["html", "markdown", "text", "json"])
```

## Logging

Aktiviere Logging, um Probleme zu debuggen:

```python theme={null}
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("olostep")
logger.setLevel(logging.INFO)  # Verwende DEBUG für ausführliche Ausgabe
```

**Log-Level**: `INFO` (empfohlen), `DEBUG` (ausführlich), `WARNING`, `ERROR`

## Konfiguration der Wiederholungsstrategie

Die `RetryStrategy`-Klasse steuert, wie das Olostep SDK vorübergehende API-Fehler durch automatische Wiederholungen mit exponentiellem Backoff und Jitter behandelt. Dies hilft, einen zuverlässigen Betrieb in Produktionsumgebungen sicherzustellen, in denen temporäre Netzwerkprobleme, Ratenlimits und Serverüberlastungen zu intermittierenden Fehlern führen können.

### Standardverhalten

Standardmäßig verwendet das SDK die folgende Wiederholungskonfiguration:

* **Maximale Wiederholungen**: 5 Versuche
* **Anfängliche Verzögerung**: 2 Sekunden
* **Backoff**: Exponentiell (2^Versuch)
* **Jitter**: 10-90% der Verzögerung (zufällig)

Das bedeutet:

* Versuch 1: Sofort
* Versuch 2: \~2-3,6s Verzögerung
* Versuch 3: \~4-7,2s Verzögerung
* Versuch 4: \~8-14,4s Verzögerung
* Versuch 5: \~16-28,8s Verzögerung

Maximale Dauer: \~57 Sekunden für alle Wiederholungen (schlechtester Fall)

### Benutzerdefinierte Konfiguration

```python theme={null}
from olostep import AsyncOlostep, RetryStrategy

# Erstelle benutzerdefinierte Wiederholungsstrategie
retry_strategy = RetryStrategy(
    max_retries=3,
    initial_delay=1.0,
    jitter_min=0.2,  # 20% minimale Jitter
    jitter_max=0.8,  # 80% maximale Jitter
)

# Verwende mit Client
async with AsyncOlostep(
    api_key="your-api-key",
    retry_strategy=retry_strategy
) as client:
    result = await client.scrapes.create("https://example.com")
```

### Wann Wiederholungen stattfinden

Das SDK wiederholt automatisch bei:

* **Vorübergehenden Serverproblemen** (`OlostepServerError_TemporaryIssue`)
* **Timeout-Antworten** (`OlostepServerError_NoResultInResponse`)

Andere Fehler (Authentifizierung, Validierung, Ressource nicht gefunden, etc.) schlagen sofort ohne Wiederholung fehl.

### Transport- vs. Anrufer-Wiederholungen

Das SDK hat zwei Wiederholungsebenen:

1. **Transportschicht**: Handhabt netzwerkbezogene Verbindungsfehler (DNS, Timeouts, etc.)
2. **Anrufer-Schicht**: Handhabt API-bezogene vorübergehende Fehler (gesteuert durch `RetryStrategy`)

Beide Ebenen sind unabhängig und haben separate Konfigurationen. Die gesamte maximale Dauer ist die Summe beider Ebenen.

### Berechnung der maximalen Dauer

```python theme={null}
retry_strategy = RetryStrategy(max_retries=5, initial_delay=2.0)
max_duration = retry_strategy.max_duration()
print(f"Maximale Aufrufdauer: {max_duration:.2f}s")
```

### Konfigurationsbeispiele

Hier sind einige Beispiele, wie du die Wiederholungsstrategie für verschiedene Anwendungsfälle konfigurieren kannst.

#### Konservative Strategie

```python theme={null}
# Weniger Wiederholungen, kürzere Verzögerungen
retry_strategy = RetryStrategy(
    max_retries=3,
    initial_delay=1.0,
    jitter_min=0.2,
    jitter_max=0.8
)
# Maximale Dauer: ~12,6s
```

#### Aggressive Strategie

```python theme={null}
# Mehr Wiederholungen für kritische Operationen
retry_strategy = RetryStrategy(
    max_retries=10,
    initial_delay=0.5
)
# Maximale Dauer: ~969,75s
```

#### Keine Wiederholungen (Schnelles Scheitern)

```python theme={null}
# Deaktiviere Wiederholungen für sofortiges Feedback bei Fehlern
retry_strategy = RetryStrategy(max_retries=0)

client = AsyncOlostep(api_key="your-api-key", retry_strategy=retry_strategy)
```

#### Strategie für hohen Durchsatz

```python theme={null}
# Optimiert für hochvolumige Operationen
retry_strategy = RetryStrategy(
    max_retries=2,
    initial_delay=0.5,
    jitter_min=0.1,
    jitter_max=0.3  # Niedrigerer Jitter für vorhersehbarere Zeiten
)
# Maximale Dauer: ~1,95s
```

### Verständnis von Jitter

Jitter fügt eine Zufälligkeit hinzu, um "thundering herd"-Probleme zu verhindern, wenn viele Clients gleichzeitig wiederholen. Der Jitter wird wie folgt berechnet:

```python theme={null}
base_delay = initial_delay * (2 ** attempt)
jitter_range = base_delay * (jitter_max - jitter_min)
jitter = random.uniform(base_delay * jitter_min, base_delay * jitter_min + jitter_range)
final_delay = base_delay + jitter
```

Zum Beispiel, mit `initial_delay=2.0`, `jitter_min=0.1`, `jitter_max=0.9`:

* Versuch 0: Basis=2.0s, Jitter=0.2-1.8s, End=2.2-3.8s
* Versuch 1: Basis=4.0s, Jitter=0.4-3.6s, End=4.4-7.6s
* Versuch 2: Basis=8.0s, Jitter=0.8-7.2s, End=8.8-15.2s

### Beste Praktiken

#### Für Produktionsanwendungen

```python theme={null}
# Ausgewogener Ansatz für die Produktion
retry_strategy = RetryStrategy(
    max_retries=5,
    initial_delay=2.0,
    jitter_min=0.1,
    jitter_max=0.9
)
```

#### Für Entwicklung/Test

```python theme={null}
# Schnelles Feedback für die Entwicklung
retry_strategy = RetryStrategy(
    max_retries=2,
    initial_delay=0.5,
    jitter_min=0.1,
    jitter_max=0.3
)
```

#### Für Batch-Operationen

```python theme={null}
# Konservativ für große Batch-Jobs
retry_strategy = RetryStrategy(
    max_retries=3,
    initial_delay=1.0,
    jitter_min=0.2,
    jitter_max=0.8
)
```

### Überwachung und Debugging

Das SDK protokolliert Wiederholungsinformationen auf DEBUG-Ebene:

```
DEBUG: Vorübergehendes Problem, Wiederholung in 2,34s
DEBUG: Kein Ergebnis in Antwort, Wiederholung in 4,67s
```

Aktiviere Debug-Logging, um das Wiederholungsverhalten zu überwachen:

```python theme={null}
import logging
logging.getLogger("olostep").setLevel(logging.DEBUG)
```

### Fehlerbehandlung

Wenn alle Wiederholungen erschöpft sind, wird der ursprüngliche Fehler ausgelöst:

```python theme={null}
try:
    result = await client.scrapes.create("https://example.com")
except OlostepServerError_TemporaryIssue as e:
    print(f"Fehlgeschlagen nach allen Wiederholungen: {e}")
    # Behandle das dauerhafte Scheitern
```

### Leistungsüberlegungen

* **Speicher**: Jeder Wiederholungsversuch verwendet zusätzlichen Speicher für Anfrage-/Antwortobjekte
* **Zeit**: Die gesamte Betriebszeit kann mit aktivierten Wiederholungen erheblich länger sein
* **API-Limits**: Wiederholungen zählen gegen deine API-Nutzungslimits
* **Netzwerk**: Mehr Netzwerkverkehr aufgrund von Wiederholungsversuchen

Wähle deine Wiederholungsstrategie basierend auf den Anforderungen deiner Anwendung an Zuverlässigkeit vs. Leistung.

## Detaillierte Fehlerbehandlung

### Ausnahmehierarchie

Das Olostep SDK bietet eine umfassende Ausnahmehierarchie für verschiedene Fehlerszenarien. Alle Ausnahmen erben von `Olostep_BaseError`.

Es gibt drei Hauptfehlerarten, die direkt von `Olostep_BaseError` erben:

1. **`Olostep_APIConnectionError`** - Netzwerkbezogene Verbindungsfehler
2. **`OlostepServerError_BaseError`** - Fehler, die (irgendwie) vom API-Server ausgelöst werden
3. **`OlostepClientError_BaseError`** - Fehler, die vom Client-SDK ausgelöst werden

### Warum Verbindungsfehler separat sind

`Olostep_APIConnectionError` ist von Serverfehlern getrennt, da es netzwerkbezogene Fehler darstellt, die auftreten, bevor die API die Anfrage verarbeiten kann. Dies sind Transportebenenprobleme (DNS- oder HTTP-Fehler, Timeouts, Verbindung verweigert, etc.) und keine API-Ebene-Fehler. HTTP-Statuscodes (4xx, 5xx) werden als API-Antworten betrachtet und als Serverfehler kategorisiert, auch wenn sie Probleme anzeigen.

```
Olostep_BaseError
├── Olostep_APIConnectionError
├── OlostepServerError_BaseError
│   ├── OlostepServerError_TemporaryIssue
│   │   ├── OlostepServerError_NetworkBusy
│   │   └── OlostepServerError_InternalNetworkIssue
│   ├── OlostepServerError_RequestUnprocessable
│   │   ├── OlostepServerError_ParserNotFound
│   │   └── OlostepServerError_OutOfResources
│   ├── OlostepServerError_BlacklistedDomain
│   ├── OlostepServerError_FeatureApprovalRequired
│   ├── OlostepServerError_AuthFailed
│   ├── OlostepServerError_CreditsExhausted
│   ├── OlostepServerError_InvalidEndpointCalled
│   ├── OlostepServerError_ResourceNotFound
│   ├── OlostepServerError_NoResultInResponse
│   └── OlostepServerError_UnknownIssue
└── OlostepClientError_BaseError
    ├── OlostepClientError_RequestValidationFailed
    ├── OlostepClientError_ResponseValidationFailed
    ├── OlostepClientError_NoAPIKey
    ├── OlostepClientError_AsyncContext
    ├── OlostepClientError_BetaFeatureAccessRequired
    └── OlostepClientError_Timeout
```

### Empfohlene Fehlerbehandlung

Für die meisten Anwendungsfälle fange den Basisfehler ab und gib den Fehlernamen aus:

```python theme={null}
from olostep import AsyncOlostep, Olostep_BaseError

try:
    result = await client.scrapes.create(url_to_scrape="https://example.com")
except Olostep_BaseError as e:
    print(f"Ein Fehler ist aufgetreten: {type(e).__name__}")
    print(f"Fehlermeldung: {e}")
```

Dieser Ansatz fängt alle SDK-Fehler ab und liefert klare Informationen darüber, was schiefgelaufen ist. Der Fehlername (z.B. `OlostepServerError_AuthFailed`) ist aussagekräftig genug, um das Problem zu verstehen.

### Granulare Fehlerbehandlung

Wenn du eine spezifischere Fehlerbehandlung benötigst, fange die spezifischen Fehlertypen direkt ab. **Vermeide die Verwendung von `OlostepServerError_BaseError` oder `OlostepClientError_BaseError`** - diese Basisklassen zeigen nur an, wer den Fehler ausgelöst hat (Server vs. Client), nicht wer für die Behebung verantwortlich ist. Dies ist ein Implementierungsdetail, das bei der Fehlerbehandlungslogik nicht hilft.

Stattdessen fange spezifische Fehlertypen ab, die das tatsächliche Problem anzeigen:

```python theme={null}
from olostep import (
    AsyncOlostep,
    Olostep_BaseError,
    Olostep_APIConnectionError,
    OlostepServerError_AuthFailed,
    OlostepServerError_CreditsExhausted,
    OlostepClientError_NoAPIKey,
)

try:
    result = await client.scrapes.create(url_to_scrape="https://example.com")
except Olostep_APIConnectionError as e:
    print(f"Netzwerkfehler: {type(e).__name__}")
except OlostepServerError_AuthFailed:
    print("Ungültiger API-Schlüssel")
except OlostepServerError_CreditsExhausted:
    print("Credits erschöpft")
except OlostepClientError_NoAPIKey:
    print("API-Schlüssel nicht angegeben")
except Olostep_BaseError as e:
    print(f"Ein Fehler ist aufgetreten: {type(e).__name__}")
```

## Konfiguration

### Umgebungsvariablen

| Variable               | Beschreibung                     | Standard                     |
| ---------------------- | -------------------------------- | ---------------------------- |
| `OLOSTEP_API_KEY`      | Dein API-Schlüssel               | Erforderlich                 |
| `OLOSTEP_BASE_API_URL` | API-Basis-URL                    | `https://api.olostep.com/v1` |
| `OLOSTEP_API_TIMEOUT`  | Anforderungszeitlimit (Sekunden) | `150`                        |

## Hilfe erhalten

* [Vollständige Dokumentation](https://docs.olostep.com)
* [Community Slack](https://join.slack.com/t/olostep-users/shared_invite/zt-2pn2ce0uu-~591qIdhAfJy~LXCWQS5UQ)
* [Support E-Mail](mailto:info@olostep.com)

## Ressourcen

<CardGroup cols={2}>
  <Card title="PyPI-Paket" icon="python" href="https://pypi.org/project/olostep/">
    Auf PyPI ansehen
  </Card>

  <Card title="API-Schlüssel erhalten" icon="key" href="https://www.olostep.com/auth">
    Kostenlos anmelden
  </Card>
</CardGroup>
