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

# Bibliothèque cliente Python

> Installer, initialiser, mapper les méthodes aux endpoints et gérer les erreurs avec le SDK Python officiel octoparse-client.

`octoparse-client` est le client Python officiel pour Data Hub. Il encapsule uniquement l’API REST publique `/v1` et ne dépend que de `httpx`. Les méthodes correspondent une à une aux endpoints, les noms de paramètres suivent REST, et les valeurs renvoyées sont la charge utile `data` brute (`dict` / `list`). Version actuelle 0.2.9, Python 3.10+.

## Installation

```bash theme={null}
pip install octoparse-client
```

## Initialisation

```python theme={null}
from octoparse_client import Client

client = Client(api_key="<your API key>")
```

| Paramètre  | Description                                                                                                                                              |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api_key`  | Clé API Data Hub. Si omise, lit `OCTOPARSE_API_KEY`. Si elle manque encore, le client est anonyme et ne peut appeler que les endpoints anonymes.         |
| `base_url` | URL du service. Si omise, lit `OCTOPARSE_BASE_URL`, par défaut `https://api-datahub.octoparse.com`. Passez-la explicitement pour le local ou le staging. |
| `timeout`  | Timeout HTTP par requête en secondes. Défaut 90.                                                                                                         |

`Client` prend en charge l’instruction `with` et ferme les connexions à la sortie. Vous pouvez aussi appeler `client.close()`. Le SDK ne charge pas les fichiers `.env` ; chargez-les vous-même si besoin.

## Correspondance méthode-endpoint

| Méthode                                                                | Endpoint                                  | Notes                                                 |
| ---------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------- |
| `meta()`                                                               | `GET /v1/meta`                            | Constantes de la plateforme                           |
| `search(q, *, limit, offset, ...)`                                     | `GET /v1/data-apps`                       | Une page de cartes, avec `pagination`                 |
| `get_app(app_id)`                                                      | `GET /v1/data-apps/{app_id}`              | Détail complet de l’app                               |
| `run(app_id, inputs, *, wait, max_records, version, build)`            | `POST /v1/data-apps/{app_id}/runs`        | Démarrer une exécution                                |
| `call(app_id, inputs, *, max_records, timeout, raise_on_failure, ...)` | `POST` + sondage                          | Aide bloquante : attend l’état terminal ou le timeout |
| `get_run(run_id, *, wait)`                                             | `GET /v1/runs/{run_id}`                   | Statut et snapshot de facturation                     |
| `list_runs_page(filters)`                                              | `GET /v1/runs`                            | Une page d’exécutions, avec `pagination`              |
| `list_runs(filters)`                                                   | `GET /v1/runs`                            | Une page d’exécutions, items uniquement               |
| `iterate_runs(filters)`                                                | `GET /v1/runs`                            | Itérateur qui pagine automatiquement                  |
| `cancel(run_id)`                                                       | `POST /v1/runs/{run_id}/cancel`           | Annuler une exécution                                 |
| `get_records(run_id, *, offset, limit, fields)`                        | `GET /v1/runs/{run_id}/records`           | Une page d’enregistrements de résultat                |
| `iterate_records(run_id, *, batch, fields)`                            | `GET /v1/runs/{run_id}/records`           | Itérateur qui pagine automatiquement                  |
| `export_records(run_id, format)`                                       | `GET /v1/runs/{run_id}/records`           | Export complet en texte `jsonl` / `csv`               |
| `list_datasets(*, offset, limit)`                                      | `GET /v1/datasets`                        | Liste des datasets                                    |
| `set_dataset_retention(dataset_id, retained)`                          | `PUT /v1/datasets/{dataset_id}/retention` | Définir le flag de rétention                          |
| `get_dataset_records(dataset_id, *, offset, limit, fields)`            | `GET /v1/datasets/{dataset_id}/records`   | Une page d’enregistrements du dataset                 |
| `iterate_dataset_records(dataset_id, *, batch, fields)`                | `GET /v1/datasets/{dataset_id}/records`   | Itérateur qui pagine automatiquement                  |
| `account()`                                                            | `GET /v1/account`                         | Infos du compte et dépenses cumulées                  |
| `billing(*, group_by, created_from, created_to, tz_offset)`            | `GET /v1/billing`                         | Agrégation de facturation                             |

Les `filters` de liste d’exécutions acceptent `status`, `data_app`, `triggered_by`, `run_kind`, `credential`, `created_from`, `created_to`, plus `offset` / `limit`. Les endpoints de publication, d’opérations et de secrets ne sont pas encapsulés ; appelez REST directement.

## Usage typique

```python theme={null}
from octoparse_client import Client, ApiError, RunFailed

with Client(api_key="<your API key>") as client:
    # Découvrir
    page = client.search("reviews", limit=5)
    for card in page["items"]:
        print(card["app_id"], card["namespace"], card["app_name"])
    detail = client.get_app("carol/reviews-query")

    # Exécuter et consommer. Les timeouts sont en secondes. TimeoutError n’annule pas l’exécution côté serveur.
    run = client.call(
        "carol/reviews-query",
        {"product": "p-9001"},
        max_records=100,
        timeout=120,
        raise_on_failure=True,
    )
    for record in client.iterate_records(run["run_id"]):
        print(record)

    # Non bloquant : démarrez, puis sondez vous-même
    started = client.run("carol/reviews-query", {"product": "p-9002"}, wait=0)
    polled = client.get_run(started["run_id"], wait=60)

    # Rapprocher les dépenses
    print(client.billing(group_by="data_app", tz_offset=480))
    for r in client.iterate_runs(created_from="2026-09-01T00:00:00+08:00"):
        print(r["run_id"], r["status"], r["billing"]["total"])

    # Les résultats sont conservés 90 jours par défaut ; marquez les datasets à garder plus longtemps
    client.set_dataset_retention(run["dataset_id"], True)
```

## Gestion des erreurs

Les réponses d’erreur de l’API lèvent `ApiError`. Les champs correspondent à l’objet REST `error` :

| Attribut      | Signification                                                                      |
| ------------- | ---------------------------------------------------------------------------------- |
| `status_code` | Statut HTTP                                                                        |
| `code`        | Id d’erreur stable pour brancher                                                   |
| `category`    | Classe large                                                                       |
| `message`     | Description en anglais                                                             |
| `retryable`   | Si la même requête peut être retentée                                              |
| `details`     | Problèmes au niveau des champs en cas d’échec de validation d’entrée, sinon `None` |

```python theme={null}
from octoparse_client import ApiError

try:
    client.run("carol/reviews-query", {})
except ApiError as e:
    if e.code == "invalid-input":
        for d in e.details or []:
            print(d["path"], d["message"])
    elif e.retryable:
        # backoff puis réessai
        ...
    else:
        raise
```

`RunFailed` est levé quand `call(..., raise_on_failure=True)` se termine en `FAILED` / `CANCELLED` / `EXPIRED`. Son attribut `run` contient l’objet d’exécution complet.

## Références d’app

`get_app()`, `run()`, `call()` et le filtre `data_app` de la liste d’exécutions acceptent les deux formes : deux segments `<namespace>/<app_name>` (lisible, cassé après renommage) et `app_id` stable (`app_<hex>`, survit au renommage). Pour les intégrations durables, stockez `app_id`. Les apps partagées point à point sont absentes de la recherche marketplace ; utilisez `search("", shared_with="me")`.
