> ## 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.

# Biblioteca cliente de Python

> Instala, inicializa, mapea métodos a endpoints y gestiona errores con el SDK oficial de Python octoparse-client.

`octoparse-client` es el cliente oficial de Python para Data Hub. Solo encapsula la API REST pública `/v1` y depende únicamente de `httpx`. Los métodos se mapean uno a uno a los endpoints, los nombres de parámetros coinciden con REST y los valores devueltos son la carga útil `data` en bruto (`dict` / `list`). Versión actual 0.2.9, Python 3.10+.

## Instalar

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

## Inicializar

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

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

| Parámetro  | Descripción                                                                                                                                                                     |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api_key`  | API key de Data Hub. Si se omite, lee `OCTOPARSE_API_KEY`. Si sigue faltando, el cliente es anónimo y solo puede llamar endpoints anónimos.                                     |
| `base_url` | URL del servicio. Si se omite, lee `OCTOPARSE_BASE_URL`, con valor por defecto `https://api-datahub.octoparse.com`. Pásala de forma explícita en entornos locales o de staging. |
| `timeout`  | Timeout HTTP por petición en segundos. Por defecto 90.                                                                                                                          |

`Client` admite la sentencia `with` y cierra las conexiones al salir. También puedes llamar `client.close()`. El SDK no carga archivos `.env`; cárgalos tú si los necesitas.

## Mapa método-endpoint

| Método                                                                 | Endpoint                                  | Notas                                                       |
| ---------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------- |
| `meta()`                                                               | `GET /v1/meta`                            | Constantes de la plataforma                                 |
| `search(q, *, limit, offset, ...)`                                     | `GET /v1/data-apps`                       | Una página de tarjetas, con `pagination`                    |
| `get_app(app_id)`                                                      | `GET /v1/data-apps/{app_id}`              | Detalle completo de la app                                  |
| `run(app_id, inputs, *, wait, max_records, version, build)`            | `POST /v1/data-apps/{app_id}/runs`        | Iniciar una ejecución                                       |
| `call(app_id, inputs, *, max_records, timeout, raise_on_failure, ...)` | `POST` + sondeo                           | Ayudante bloqueante: espera hasta estado terminal o timeout |
| `get_run(run_id, *, wait)`                                             | `GET /v1/runs/{run_id}`                   | Estado y snapshot de facturación                            |
| `list_runs_page(filters)`                                              | `GET /v1/runs`                            | Una página de ejecuciones, con `pagination`                 |
| `list_runs(filters)`                                                   | `GET /v1/runs`                            | Una página de ejecuciones, solo ítems                       |
| `iterate_runs(filters)`                                                | `GET /v1/runs`                            | Iterador que pagina automáticamente                         |
| `cancel(run_id)`                                                       | `POST /v1/runs/{run_id}/cancel`           | Cancelar una ejecución                                      |
| `get_records(run_id, *, offset, limit, fields)`                        | `GET /v1/runs/{run_id}/records`           | Una página de registros de resultado                        |
| `iterate_records(run_id, *, batch, fields)`                            | `GET /v1/runs/{run_id}/records`           | Iterador que pagina automáticamente                         |
| `export_records(run_id, format)`                                       | `GET /v1/runs/{run_id}/records`           | Exportación completa como texto `jsonl` / `csv`             |
| `list_datasets(*, offset, limit)`                                      | `GET /v1/datasets`                        | Lista de datasets                                           |
| `set_dataset_retention(dataset_id, retained)`                          | `PUT /v1/datasets/{dataset_id}/retention` | Establecer el flag de retención                             |
| `get_dataset_records(dataset_id, *, offset, limit, fields)`            | `GET /v1/datasets/{dataset_id}/records`   | Una página de registros del dataset                         |
| `iterate_dataset_records(dataset_id, *, batch, fields)`                | `GET /v1/datasets/{dataset_id}/records`   | Iterador que pagina automáticamente                         |
| `account()`                                                            | `GET /v1/account`                         | Info de cuenta y gasto acumulado                            |
| `billing(*, group_by, created_from, created_to, tz_offset)`            | `GET /v1/billing`                         | Agregación de facturación                                   |

Los `filters` de listado de ejecuciones admiten `status`, `data_app`, `triggered_by`, `run_kind`, `credential`, `created_from`, `created_to`, más `offset` / `limit`. Los endpoints de publicación, operaciones y secrets no están encapsulados; llama a REST directamente.

## Uso típico

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

with Client(api_key="<your API key>") as client:
    # Descubrir
    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")

    # Ejecutar y consumir. Los timeouts son en segundos. TimeoutError no cancela la ejecución en el servidor.
    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)

    # No bloqueante: inicia y luego sondea tú mismo
    started = client.run("carol/reviews-query", {"product": "p-9002"}, wait=0)
    polled = client.get_run(started["run_id"], wait=60)

    # Conciliar el gasto
    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"])

    # Los resultados se conservan 90 días por defecto; marca los datasets que necesites más tiempo
    client.set_dataset_retention(run["dataset_id"], True)
```

## Gestión de errores

Las respuestas de error de la API lanzan `ApiError`. Los campos coinciden con el objeto REST `error`:

| Atributo      | Significado                                                                  |
| ------------- | ---------------------------------------------------------------------------- |
| `status_code` | Estado HTTP                                                                  |
| `code`        | Id estable del error para ramificar                                          |
| `category`    | Clase amplia                                                                 |
| `message`     | Descripción en inglés                                                        |
| `retryable`   | Si la misma petición se puede reintentar                                     |
| `details`     | Problemas a nivel de campo en fallos de validación de entrada; si no, `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:
        # retroceder y reintentar
        ...
    else:
        raise
```

`RunFailed` se lanza cuando `call(..., raise_on_failure=True)` termina en `FAILED` / `CANCELLED` / `EXPIRED`. Su atributo `run` contiene el objeto de ejecución completo.

## Referencias de app

`get_app()`, `run()`, `call()` y el filtro `data_app` del listado de ejecuciones aceptan ambas formas: dos segmentos `<namespace>/<app_name>` (legible, se rompe tras un renombre) e `app_id` estable (`app_<hex>`, sobrevive al renombre). En integraciones de larga duración, guarda `app_id`. Las apps compartidas punto a punto no aparecen en la búsqueda del marketplace; usa `search("", shared_with="me")`.
