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

# Python SDK

> 面向 Decodo Web Data API 的官方 Python SDK，提供类型化目标、IDE 自动补全，以及同步、异步和批量抓取方法。

> [!NOTE]
>
> 最新的安装说明、示例和源代码请查看 [Python SDK GitHub 仓库](https://github.com/Decodo/sdk-python)。

使用官方 Decodo Python SDK，为搜索引擎、电商平台、社交媒体、AI 工具等构建类型化的抓取工作流。

* 完整类型化的目标和参数，支持 IDE 自动补全
* 同步、异步和批量抓取方法
* 通过 Web Data API 提供网页搜索、站点地图和爬取功能
* 基于 `httpx` 构建；需要 Python 3.12 或更高版本
* 类型化的错误层级，让集成更安全

## 什么是 Decodo Python SDK？

Decodo Python SDK 为 Google、Amazon、TikTok、YouTube、ChatGPT、Perplexity 等 Decodo 目标提供类型化接口。您无需手动构造 HTTP 请求和校验载荷，而是直接在编辑器中使用完整类型化的方法和特定目标的参数类。

## 为什么使用该 SDK？

* **类型化与自动补全**：目标参数完整类型化，带来更好的编辑器支持和更少的错误。
* **统一的抓取接口**：通过同一个 SDK 使用搜索引擎、电商平台、社交媒体和 AI 工具。
* **异步与批量工作流**：创建抓取任务、轮询任务状态，并大规模处理批量请求。
* **类型化错误**：安全地处理身份验证、参数校验、超时和速率限制等失败情况。
* **配置极简**：仅依赖 `httpx`，无需额外的 HTTP 客户端。

## 要求

* Python 3.12 及以上版本

## 安装

```bash theme={null}
pip install decodo-sdk
```

## 快速开始

创建一个新项目：

```bash theme={null}
mkdir scrape-with-decodo
cd scrape-with-decodo
pip install decodo-sdk
touch main.py
```

在 [**Decodo 控制面板**](https://dashboard.decodo.com/web-data/playground)中，从您的 Web Data API 订阅复制 Web Data API 密钥。请将其存储在环境变量中，避免写入源代码：

```bash theme={null}
export DECODO_API_KEY=your_api_key
```

> [!NOTE]
>
> 较旧的计划只有基本身份验证令牌。请将其作为 `token` 传入，而不是 `api_key`——详见下文的"配置"一节。

每个目标都有对应的参数类。导入您需要的那个，填入字段，然后传给 `scrape()`：

```python theme={null}
# main.py
import os

from decodo import (
    DecodoClient,
    DecodoConfig,
    GoogleSearchParams,
    WebScrapingApiConfig,
)

client = DecodoClient(
    DecodoConfig(
        web_scraping_api=WebScrapingApiConfig(
            api_key=os.environ["DECODO_API_KEY"],
        ),
    )
)

result = client.web_scraping_api.scrape(
    GoogleSearchParams(
        query="coffee shops",
        geo="United States",
        parse=True,
    )
)

print(result)
```

运行脚本：

```bash theme={null}
python main.py
```

参数类随软件包一起提供，因此执行 `pip install decodo-sdk` 之后无需额外步骤。

每个类都固定了自己的目标，并且只接受该目标支持的字段——您的 IDE 会标出拼写错误或不受支持的字段，运行时校验也会在请求发出之前捕获它们。

### 另一种方式：字典载荷

抓取方法也接受普通的 Python 字典，并会在请求发出之前根据随包提供的 schema 进行校验。编写代码时不会有任何检查，因此拼写错误只会在运行时暴露：

```python theme={null}
result = client.web_scraping_api.scrape({
    "target": "google_search",
    "query": "coffee shops",
    "geo": "United States",
    "parse": True,
})
print(result)
```

请使用 `Target` 枚举而不是原始字符串，以避免写错目标名称。除快速试验之外的场景，均推荐使用类型化参数类。

### 将类型更新到更新的 schema

软件包内置的类型反映的是发布时的 schema。若要在不等待新版本的情况下更新它们，请运行类型生成器：

```bash theme={null}
python -m decodo.codegen.codegen --out-dir ./decodo_generated
```

然后改为从该目录导入：

```python theme={null}
from decodo_generated.targets import GoogleSearchParams
```

传给 `--out-dir` 的目录名会成为导入命名空间，因此 `./decodo_generated` 对应 `from decodo_generated.targets import ...`。任何名称都可以，但请在整个项目中保持一致。

## 配置

```python theme={null}
from decodo import (
    DecodoClient,
    DecodoConfig,
    WebScrapingApiConfig,
)

client = DecodoClient(
    DecodoConfig(
        web_scraping_api=WebScrapingApiConfig(
            api_key="<api_key>",
        ),
        timeout_ms=120_000,  # optional, request timeout in ms (default: 180000)
    )
)
```

请传入 `api_key` 或 `token` 之一，切勿同时传入：

```python theme={null}
# Basic authentication token (older plans)
client = DecodoClient(
    DecodoConfig(
        web_scraping_api=WebScrapingApiConfig(
            token="<basic_auth_token>",
        ),
    )
)
```

| 参数 | 说明 |
| - | - |
| `api_key` | 控制面板中订阅所对应的 Web Data API 密钥。**推荐** |
| `token` | 较旧计划的基本身份验证令牌——即控制面板中 base64 编码的 `user:password` 字符串。请用它替代 `api_key` |
| `timeout_ms` | 请求超时毫秒数（默认：180000） |

> [!NOTE]
>
> 同时设置两者会抛出 `ValueError: web_scraping_api accepts either token or api_key, not both. Provide only one.`；两者都不设置会抛出 `ValueError: web_scraping_api requires api_key or token in DecodoConfig.`
>
> 您传入的凭据还决定了 SDK 调用哪个 API。`api_key` 使用位于 `data.decodo.com` 的 Web Data API，这也是使用搜索、站点地图和爬取功能的唯一途径。`token` 使用位于 `scraper-api.decodo.com` 的旧版 Web Scraping API，该 API 仅支持抓取。

## 抓取

通过 `client.web_scraping_api` 访问该 API。

### 同步抓取

等待抓取结果返回后再继续：

```python theme={null}
from decodo import AmazonProductParams

result = client.web_scraping_api.scrape(
    AmazonProductParams(
        query="B09H74FXNW",
        parse=True,
    )
)
print(result)
```

### 异步抓取

创建抓取任务并立即返回。之后您需要轮询其状态和结果：

```python theme={null}
import time
from decodo import GoogleSearchParams

task = client.web_scraping_api.scrape_async(
    GoogleSearchParams(query="laptop reviews", parse=True)
)
task_id = task["id"]

while True:
    status = client.web_scraping_api.get_status(task_id)["status"]
    if status == "done":
        break
    if status == "faulted":
        raise RuntimeError(f"Scraping task {task_id} failed.")
    time.sleep(2)

result = client.web_scraping_api.get_results(task_id)
print(result)
```

`get_status` 会返回 `pending`、`done` 或 `faulted`。

### 批量抓取

使用某个目标参数类的批量变体，在单个请求中发送多个输入。主输入参数接受列表：

```python theme={null}
import time
from decodo import GoogleSearchBatchParams

batch = client.web_scraping_api.scrape_batch(
    GoogleSearchBatchParams(query=["coffee", "tea", "juice"], parse=True)
)

for task in batch["queries"]:
    task_id = task["id"]
    while True:
        status = client.web_scraping_api.get_status(task_id)["status"]
        if status == "done":
            break
        if status == "faulted":
            raise RuntimeError(f"Scraping task {task_id} failed.")
        time.sleep(2)
    result = client.web_scraping_api.get_results(task_id)
    print(result)
```

## Web Data API：搜索、站点地图和爬取

这些方法由位于 `data.decodo.com` 的 Web Data API 提供，**需要 `api_key`**。在配置了基本身份验证 `token` 的客户端上调用它们会抛出 `ValueError`。它们与抓取方法同属 `client.web_scraping_api` 命名空间。

参数为普通字典。`SearchRequest`、`MapRequest` 和 `CrawlRequest` 是 `TypedDict`，可用于编辑器补全——它们始终可以导入，无需代码生成。请求体同样会在发出之前根据随包提供的 schema 进行校验，与 `scrape` 一致。

### 搜索

运行一次网页搜索并返回解析后的结果文档：

```python theme={null}
from decodo import SearchRequest

result = client.web_scraping_api.search(
    SearchRequest(query="coffee shops", geo="United States", page=1)
)

for item in result.get("organic", []):
    print(item["rank"], item["title"], item["link"])
```

> [!NOTE]
>
> 已经执行但未能成功抓取的搜索，仍会以 HTTP 200 返回，并带有 `status: "failed"` 和一条 `message`。请先检查 `result["status"]`，再读取其他字段。

### 站点地图

从站点的页面及其站点地图中发现链接：

```python theme={null}
from decodo import MapRequest

result = client.web_scraping_api.map(
    MapRequest(url="https://www.example.com", limit=100, sitemap="include")
)

for link in result["results"][0]["content"]["links"]:
    print(link["url"])
```

### 爬取

`crawl()` 会启动爬取、等待其完成，并返回每个页面及其内容：

```python theme={null}
from decodo import (
    CrawlError,
    CrawlRequest,
    CrawlTimeoutError,
)

try:
    pages = client.web_scraping_api.crawl(
        CrawlRequest(url="https://www.example.com", limit=20, max_depth=2),
        poll_interval=5,
        timeout=600,
    )
except CrawlTimeoutError as err:
    print(f"Still running, fetch it later with get_crawl_results({err.crawl_id!r})")
except CrawlError as err:
    print(f"Crawl {err.crawl_id} ended {err.status}: {err.reason}")
else:
    for page in pages:
        print(page["url"], page["status"], page.get("content", "")[:80])
```

因 `max_duration` 或服务端限制而提前停止的爬取，最终状态为 `truncated`，此时 `crawl()` 会返回已收集到的页面。每个页面都带有自己的 `status`（`pending`、`done` 或 `faulted`）；当抓取失败时，返回的是 `content_error` 而不是 `content`。

更底层的方法可让您自行控制爬取流程——例如在一个进程中启动，在另一个进程中收集：

```python theme={null}
started = client.web_scraping_api.start_crawl(
    CrawlRequest(url="https://www.example.com")
)
crawl_id = started["crawl_id"]

status = client.web_scraping_api.get_crawl_status(crawl_id)
print(status["status"], status["completed"], status["in_flight"])

pages = client.web_scraping_api.get_crawl_results(crawl_id)

client.web_scraping_api.cancel_crawl(crawl_id)
```

`get_crawl_status` 会返回 `pending`、`done`、`faulted`、`cancelled` 或 `truncated`；当爬取提前停止时，还会带上 `reason`。

| 方法 | 说明 |
| - | - |
| `search(params)` | 运行网页搜索并返回解析后的结果 |
| `map(params)` | 列出站点上的链接，而不获取其内容 |
| `crawl(params, *, poll_interval=5, timeout=None)` | 启动爬取、等待其完成，并返回所有页面 |
| `start_crawl(params)` | 启动爬取并立即返回其 `crawl_id` |
| `get_crawl_status(crawl_id)` | 报告进度和当前状态 |
| `get_crawl_results(crawl_id, *, content=True)` | 获取已爬取的页面；传入 `content=False` 则只返回元数据 |
| `cancel_crawl(crawl_id)` | 停止正在运行的爬取；此前已收集的页面仍可读取 |

## 目标与参数类

`Target` 枚举中的每个目标都有一个与之对应的参数类。类名是枚举成员名后加 `Params`——例如 `Target.GoogleSearch` → `GoogleSearchParams`，`Target.Chatgpt` → `ChatgptParams`。批量调用则在 `Params` 之前插入 `Batch`，例如 `GoogleSearchBatchParams`。

您无需显式传入目标，因为每个参数类都已固定了自己的目标。例如，单独写 `GoogleSearchParams(query="coffee shops")` 就足够了。`Target` 枚举在使用字典载荷，以及从响应中读取 `target` 字段时仍然有用。

> [!NOTE]
>
> 有一个目标不符合该命名规则：`Target.Target` 对应的是 `TargetStoreParams`（而不是 `TargetParams`），以避免名称冲突。其余目标均遵循该模式。

每个目标接受一个主输入参数（`url`、`query`、`product_id` 或 `prompt`），以及可选的配置项。

### 搜索引擎

| 目标 | 参数类 | 说明 | 示例输入 |
| - | - | - | - |
| `Target.GoogleSearch` | `GoogleSearchParams` | 某个查询的 Google 搜索结果 | `query="coffee shops"` |
| `Target.GoogleLens` | `GoogleLensParams` | Google Lens 以图搜图 | `query="https://example.com/cat.jpg"` |
| `Target.GoogleTravelHotels` | `GoogleTravelHotelsParams` | Google Travel 酒店列表 | `query="hotels in paris"` |
| `Target.GoogleAds` | `GoogleAdsParams` | 某个查询的 Google Ads 结果 | `query="laptop"` |
| `Target.BingSearch` | `BingSearchParams` | Bing 搜索结果 | `query="electric vehicles"` |
| `Target.Bing` | `BingParams` | 原始 Bing URL 抓取 | `url="https://bing.com/search?q=laptop"` |

### 电商

| 目标 | 参数类 | 说明 | 示例输入 |
| - | - | - | - |
| `Target.AmazonProduct` | `AmazonProductParams` | 按 ASIN 获取 Amazon 商品详情页 | `query="B09H74FXNW"` |
| `Target.AmazonSearch` | `AmazonSearchParams` | Amazon 搜索结果 | `query="laptop"` |
| `Target.AmazonPricing` | `AmazonPricingParams` | Amazon 价格和报价 | `query="B09H74FXNW"` |
| `Target.AmazonSellers` | `AmazonSellersParams` | Amazon 卖家列表 | `query="B09H74FXNW"` |
| `Target.AmazonBestsellers` | `AmazonBestsellersParams` | 按类目获取 Amazon 畅销榜 | `query="electronics"` |
| `Target.WalmartProduct` | `WalmartProductParams` | 按商品 ID 获取 Walmart 商品页面 | `product_id="15296401808"` |
| `Target.WalmartSearch` | `WalmartSearchParams` | Walmart 搜索结果 | `query="laptop"` |
| `Target.Walmart` | `WalmartParams` | 原始 Walmart URL 抓取 | `url="https://walmart.com/ip/15296401808"` |
| `Target.TargetProduct` | `TargetProductParams` | 按商品 ID 获取 Target.com 商品页面 | `product_id="92186007"` |
| `Target.TargetSearch` | `TargetSearchParams` | Target.com 搜索结果 | `query="laptop"` |
| `Target.Target` | `TargetStoreParams` | 原始 Target.com URL 抓取 | `url="https://target.com/p/-/A-92186007"` |

### 社交媒体

| 目标 | 参数类 | 说明 | 示例输入 |
| - | - | - | - |
| `Target.YoutubeSearch` | `YoutubeSearchParams` | YouTube 搜索结果 | `query="ambient music"` |
| `Target.YoutubeMetadata` | `YoutubeMetadataParams` | 按 ID 获取 YouTube 视频元数据 | `query="dFu9aKJoqGg"` |
| `Target.YoutubeSubtitles` | `YoutubeSubtitlesParams` | 按 ID 获取 YouTube 视频字幕 | `query="dFu9aKJoqGg"` |
| `Target.YoutubeChannel` | `YoutubeChannelParams` | 按 handle 或 ID 获取 YouTube 频道 | `query="@decodo_official"` |
| `Target.TiktokPost` | `TiktokPostParams` | 按 URL 获取 TikTok 帖子 | `url="https://www.tiktok.com/@nba/video/..."` |
| `Target.TiktokShopSearch` | `TiktokShopSearchParams` | TikTok Shop 搜索结果 | `query="wireless earbuds"` |
| `Target.TiktokShopProduct` | `TiktokShopProductParams` | 按商品 ID 获取 TikTok Shop 商品页面 | `product_id="7100000000000000000"` |
| `Target.Tiktok` | `TiktokParams` | 原始 TikTok URL 抓取 | `url="https://www.tiktok.com/@nba"` |

### AI 工具

| 目标 | 参数类 | 说明 | 示例输入 |
| - | - | - | - |
| `Target.Chatgpt` | `ChatgptParams` | 针对某个提示词的 ChatGPT 回答 | `prompt="What are the top three dog breeds?"` |
| `Target.Perplexity` | `PerplexityParams` | 针对某个提示词的 Perplexity 回答 | `prompt="What causes seasonal allergies?"` |
| `Target.Gemini` | `GeminiParams` | 针对某个提示词的 Gemini 回答 | `prompt="What are the top three dog breeds?"` |
| `Target.GoogleAiMode` | `GoogleAiModeParams` | Google AI 模式的回答 | `query="What are the top three dog breeds?"` |

### 其他

| 目标 | 参数类 | 说明 | 示例输入 |
| - | - | - | - |
| `Target.Bbb` | `BbbParams` | 按 URL 获取 Better Business Bureau 条目 | `url="https://bbb.org/us/ny/new-york/..."` |
| `Target.Autotrader` | `AutotraderParams` | 按 URL 获取 Autotrader 条目 | `url="https://autotrader.com/cars-for-sale/..."` |
| `Target.Mobile` | `MobileParams` | 按 URL 获取 Mobile.de 条目 | `url="https://mobile.de/auto/..."` |
| `Target.Airbnb` | `AirbnbParams` | 按 URL 获取 Airbnb 房源 | `url="https://airbnb.com/rooms/12345"` |
| `Target.AppleAppStore` | `AppleAppStoreParams` | 按 URL 获取 Apple App Store 应用 | `url="https://apps.apple.com/app/id12345"` |

### 通用抓取

| 目标 | 参数类 | 说明 | 示例输入 |
| - | - | - | - |
| `Target.Universal` | `UniversalParams` | 通过通用抓取器抓取任意 URL | `url="https://example.com"` |
| `Target.Google` | `GoogleParams` | 原始 Google URL 抓取 | `url="https://google.com/search?q=laptop"` |
| `Target.Amazon` | `AmazonParams` | 原始 Amazon URL 抓取 | `url="https://amazon.com/dp/B09H74FXNW"` |

完整的目标列表和参数详情，请参阅[**目标列表**](https://help.decodo.com/docs/cn/web-scraping-api-targets.md)和[**参数**](https://help.decodo.com/docs/web-scraping-api-parameters-overview.md)。

## 错误处理

该 SDK 会抛出与 API 错误码对应的类型化错误：

```python theme={null}
import time
from decodo import (
    AuthenticationError,
    DecodoError,
    GoogleSearchParams,
    RateLimitError,
    TimeoutError,
    ValidationError,
)

params = GoogleSearchParams(query="coffee shops", geo="United States", parse=True)

try:
    response = client.web_scraping_api.scrape(params)
except AuthenticationError:
    raise SystemExit("Invalid API key or token. Check your credentials in the dashboard.")
except RateLimitError:
    time.sleep(5)
    response = client.web_scraping_api.scrape(params)
except ValidationError as err:
    print("Payload rejected:", err.errors or err)
except TimeoutError:
    print("Timed out. Increase timeout_ms or switch to scrape_async for slow targets.")
except DecodoError as err:
    print(f"Request failed with {err.status_code}: {err}")
```

| 错误 | 抛出时机 | 常用属性 |
| - | - | - |
| `AuthenticationError` | API 返回 `401` 或 `403` | `status_code` |
| `RateLimitError` | API 返回 `429` | `status_code` |
| `ValidationError` | 载荷未通过本地 schema 校验，或 API 返回 `422` | `errors`、`status_code` |
| `TimeoutError` | 请求超过 `timeout_ms` | 无 |
| `CrawlTimeoutError` | `crawl()` 超过其 `timeout`。它是 `TimeoutError` 的子类；爬取仍会继续运行 | `crawl_id` |
| `CrawlError` | `crawl()` 以 `faulted` 或 `cancelled` 结束。它是 `DecodoError` 的子类 | `crawl_id`、`status`、`reason` |
| `CrawlInterruptedError` | 爬取启动后，状态或结果请求失败。它是 `DecodoError` 的子类 | `crawl_id` |
| `DecodoError` | 其他任何失败响应——上述错误的基类 | `status_code`、`api_status` |

> [!NOTE]
>
> `TimeoutError` 不在 `DecodoError` 的层级之内，因此 `except DecodoError` 捕获不到它，请单独处理。此外，从 `decodo` 导入它会在该模块中遮蔽内置的 `TimeoutError`。
>
> 类型化参数也可能在请求发出之前就失败。创建参数对象时，若字段未知或类型不正确，会抛出 `pydantic.ValidationError`。

***

## 相关内容

* [**CLI**](https://help.decodo.com/docs/cn/cli.md)：在命令行中运行 Decodo 抓取工作流。
* [**TypeScript SDK**](https://help.decodo.com/docs/cn/typescript-sdk.md)：将 Decodo API 集成到 TypeScript 和 JavaScript 项目中。
* [**Go SDK**](https://help.decodo.com/docs/cn/go-sdk.md)：将 Decodo API 集成到 Go 项目中。
* [**MCP 服务器**](https://help.decodo.com/docs/cn/mcp.md)：将 AI 智能体和兼容 MCP 的工具连接到 Decodo。
* [GitHub 仓库](https://github.com/Decodo/sdk-python)：查看 Python SDK 的源代码、示例和最新版本。

***

> [card] [支持](https://direct.lc.chat/12092754)
>
> 需要帮助或只是想打个招呼？我们的支持团队全天候为您服务。 \
> 您也可以随时通过电子邮件 [support@decodo.com](mailto:support@decodo.com) 联系我们。

> [card] [反馈](mailto:feedback@decodo.com)
>
> 找不到您要找的内容？请求一篇文章！ \
> 有反馈意见？分享您对我们如何改进的想法。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.