# Python

> YesCaptcha 的 Python 示例：查询余额、识别图片验证码、可复用的客户端类（创建任务、每 5 秒轮询）、asyncio 并发控制，以及 requests 和 Selenium 提交 reCAPTCHA。

Source: https://docs.yescaptcha.com/zh/samples/python/ · Last verified: 2026-10-15

运行环境：Python 3.8 以上，`pip install requests`。运行前设置环境变量：

```bash
export YESCAPTCHA_CLIENT_KEY=你的clientKey
```

## 查询余额

不扣点，用来确认 clientKey 正确：

get_balance.py

```python
"""Check the balance. getBalance is free and is a quick way to verify your clientKey."""
import os

import requests

CLIENT_KEY = os.environ["YESCAPTCHA_CLIENT_KEY"]

r = requests.post(
    "https://api.yescaptcha.com/getBalance",
    json={"clientKey": CLIENT_KEY},
    timeout=30,
)
data = r.json()
if data.get("errorId"):
    # e.g. ERROR_KEY_DOES_NOT_EXIST when the clientKey is wrong
    print("error:", data.get("errorCode"), data.get("errorDescription"))
else:
    print("balance (points):", data["balance"])
```

## 识别一张图片验证码

同步类型 `ImageToTextTaskOcrBase`，一次请求拿到结果。示例图片：[captcha.jpg](https://docs.yescaptcha.com/samples/captcha.jpg)。

quickstart.py

```python
"""First request: read an alphanumeric image captcha with ImageToTextTaskOcrBase
(synchronous, 2 points per image).

Usage:
    export YESCAPTCHA_CLIENT_KEY=your_client_key
    python quickstart.py captcha.png
"""
import base64
import os
import sys

import requests

CLIENT_KEY = os.environ["YESCAPTCHA_CLIENT_KEY"]
image_path = sys.argv[1] if len(sys.argv) > 1 else "captcha.png"

with open(image_path, "rb") as f:
    body = base64.b64encode(f.read()).decode()  # no "data:" prefix

r = requests.post(
    "https://api.yescaptcha.com/createTask",
    json={
        "clientKey": CLIENT_KEY,
        "task": {"type": "ImageToTextTaskOcrBase", "body": body},
    },
    timeout=30,
)
data = r.json()
if data.get("errorId"):
    raise SystemExit(f"{data.get('errorCode')}: {data.get('errorDescription')}")
print("text:", data["solution"]["text"])
```

## 可复用的客户端

把下面的文件复制进你的项目，同步和异步类型都能用：

yescaptcha.py

```python
"""A small client you can copy into your project: create tasks, poll results, check the balance.

    from yescaptcha import YesCaptcha
    client = YesCaptcha(os.environ["YESCAPTCHA_CLIENT_KEY"])
    solution = client.solve({
        "type": "NoCaptchaTaskProxyless",
        "websiteURL": "https://www.google.com/recaptcha/api2/demo",
        "websiteKey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
    })
    print(solution["gRecaptchaResponse"])
"""
import os
import time

import requests

class YesCaptchaError(Exception):
    def __init__(self, code, description):
        super().__init__(f"{code}: {description}")
        self.code = code
        self.description = description

class YesCaptcha:
    def __init__(self, client_key, endpoint="https://api.yescaptcha.com", poll_interval=5, timeout=180):
        self.client_key = client_key
        self.endpoint = endpoint.rstrip("/")
        self.poll_interval = poll_interval  # 5 s: polling the same taskId more often only returns "processing"
        self.timeout = timeout
        self.session = requests.Session()

    def call(self, method, payload=None):
        body = {"clientKey": self.client_key, **(payload or {})}
        data = self.session.post(f"{self.endpoint}/{method}", json=body, timeout=30).json()
        if data.get("errorId"):
            raise YesCaptchaError(data.get("errorCode"), data.get("errorDescription"))
        return data

    def balance(self):
        return self.call("getBalance")["balance"]

    def solve(self, task):
        created = self.call("createTask", {"task": task})
        if created.get("status") == "ready":  # synchronous types return the solution directly
            return created["solution"]
        task_id = created["taskId"]
        deadline = time.time() + self.timeout
        while time.time() < deadline:
            time.sleep(self.poll_interval)
            result = self.call("getTaskResult", {"taskId": task_id})
            if result.get("status") == "ready":
                return result["solution"]
        raise TimeoutError(f"task {task_id} not ready after {self.timeout}s")

if __name__ == "__main__":
    client = YesCaptcha(os.environ["YESCAPTCHA_CLIENT_KEY"])
    print("balance:", client.balance())
```

```python
from yescaptcha import YesCaptcha

client = YesCaptcha(os.environ["YESCAPTCHA_CLIENT_KEY"])
solution = client.solve({
    "type": "HCaptchaTaskProxyless",
    "websiteURL": "https://accounts.hcaptcha.com/demo",
    "websiteKey": "a5f74b19-9e45-40e0-b45d-47ff91b7a6c2",
})
print(solution["gRecaptchaResponse"])
```

出错时抛出 `YesCaptchaError`，`e.code` 是错误码，含义见 [错误码](https://docs.yescaptcha.com/zh/api/errors/)。

## 控制并发

批量发任务时限制同时在处理中的请求数，收到 `ERROR_THREADS_MAXIMUM` 稍等再试（需要 `pip install aiohttp`），说明见 [并发限制与自动暂停](https://docs.yescaptcha.com/zh/api/rate-limits/)：

concurrency.py

```python
"""Limit concurrency: keep the number of requests waiting for a result below your limit, and back off
on ERROR_THREADS_MAXIMUM (rejected requests are not charged). Requires: pip install aiohttp"""
import asyncio
import os

import aiohttp

CLIENT_KEY = os.environ["YESCAPTCHA_CLIENT_KEY"]
LIMIT = 15  # below your concurrency limit
sem = asyncio.Semaphore(LIMIT)

async def solve(session, task):
    async with sem:  # at most LIMIT requests in progress at a time
        result = {}
        for attempt in range(5):
            async with session.post(
                "https://api.yescaptcha.com/createTask",
                json={"clientKey": CLIENT_KEY, "task": task},
            ) as resp:
                result = await resp.json()
            if result.get("errorCode") != "ERROR_THREADS_MAXIMUM":
                return result
            await asyncio.sleep(1 + attempt)  # over the limit: wait and retry
        return result

async def main(tasks):
    async with aiohttp.ClientSession() as session:
        return await asyncio.gather(*(solve(session, t) for t in tasks))

if __name__ == "__main__":
    print(asyncio.run(main([])))
```

## 提交 reCAPTCHA token

-   用 requests 直接提交：见 [用 token 完成 reCAPTCHA](https://docs.yescaptcha.com/zh/guides/submit-recaptcha-token/#%E6%96%B9%E6%B3%95%E4%B8%80%E7%9B%B4%E6%8E%A5%E5%8F%91%E8%AF%B7%E6%B1%82%E6%8F%90%E4%BA%A4%E6%8E%A8%E8%8D%90)
-   用 Selenium 在浏览器里填入：见 [用 token 完成 reCAPTCHA](https://docs.yescaptcha.com/zh/guides/submit-recaptcha-token/#%E6%96%B9%E6%B3%95%E4%BA%8C%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E9%87%8C%E5%A1%AB%E5%85%A5selenium-%E7%AD%89)
-   用 Selenium 模拟点击图片题：见 [reCAPTCHA v2 图像识别模拟点击](https://docs.yescaptcha.com/zh/guides/recaptcha-click-selenium/)、[hCaptcha 图像识别模拟点击](https://docs.yescaptcha.com/zh/guides/hcaptcha-click-selenium/)
