Вызывайте solvethree из бэкенда FastAPI

Автор: solvethree4 мин на чтение

Возвращайте задачу после создания, а не после полного завершения решения. Вызывающий клиент получает ее статус, пока он не станет ready или failed, а затем отправляет токен целевому сайту, если решение завершилось успешно.

На этой странице

Настройте сервер и целевой сайт

Используйте Python 3.10 или более позднюю версию. Установите FastAPI командой python -m pip install "fastapi[standard]", затем установите официальный SDK командой python -m pip install https://solvethree.com/downloads/solvethree_sdk-0.1.0-py3-none-any.whl.

Перед запуском приложения задайте в серверном процессе следующие переменные окружения:

  • SOLVETHREE_API_KEY: API-ключ вашего рабочего пространства. Храните его на сервере; SDK использует его для аутентификации в solvethree.
  • INTEGRATION_KEY: отдельный секрет, который клиенты отправляют в заголовке X-Integration-Key для аутентификации в ваших маршрутах FastAPI.
  • CAPTCHA_SITE: имя целевого хоста, а не полный URL.
  • SOLVETHREE_PROXY: URL HTTP- или HTTPS-прокси, используемого для этой задачи, без пути, строки запроса и фрагмента.

Перед вызовом маршрута создайте в рабочем пространстве активный профиль для целевого сайта. В примере зафиксировано действие login, поэтому профиль и предполагаемый запрос к целевому сайту должны соответствовать этому сценарию. Передача имени хоста не создает профиль; см. настройку профиля сайта.

Добавьте и запустите маршруты FastAPI

Сохраните этот пример как main.py. Оба маршрута требуют X-Integration-Key. Маршрут создания формирует задачу полностью из серверной конфигурации; клиенты не передают сайт, действие или прокси в теле запроса.

FastAPI · запуск синхронного SDK в пуле потоков
# pip install "fastapi[standard]" and the official solvethree SDK wheel.
import hmac
import os
from fastapi import FastAPI, HTTPException, Request
from fastapi.concurrency import run_in_threadpool
from solvethree import Solvethree, SolvethreeError

app = FastAPI()

def authorize(request):
    if not hmac.compare_digest(request.headers.get("x-integration-key", ""), os.environ["INTEGRATION_KEY"]):
        raise HTTPException(status_code=401, detail="Unauthorized")

@app.post("/captcha/tasks")
async def create(request: Request):
    authorize(request)
    task = {"site": os.environ["CAPTCHA_SITE"], "action": "login", "proxy": os.environ["SOLVETHREE_PROXY"]}
    if request.headers.get("x-request-id"):
        task["requestId"] = request.headers["x-request-id"]
    def submit():
        return Solvethree(os.environ["SOLVETHREE_API_KEY"]).create_task(task, wait_ms=0, timeout=20)
    try:
        return await run_in_threadpool(submit)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid task input")
    except SolvethreeError as error:
        raise HTTPException(status_code=502, detail={"requestId": error.request_id, "taskId": error.task_id})

@app.get("/captcha/tasks/{task_id}")
async def retrieve(task_id: str, request: Request):
    authorize(request)
    def fetch():
        return Solvethree(os.environ["SOLVETHREE_API_KEY"]).get_task(task_id, wait_ms=15000, timeout=25)
    try:
        return await run_in_threadpool(fetch)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid task ID")
    except SolvethreeError as error:
        raise HTTPException(status_code=502, detail={"requestId": error.request_id, "taskId": error.task_id})

По умолчанию задача использует reCAPTCHA Enterprise v3. Она отправляет site, action и один proxy, без полей type и url.

Python SDK синхронный. Его прямой вызов внутри async def заблокировал бы цикл событий, поэтому оба обработчика используют run_in_threadpool. При создании используется wait_ms=0 с тайм-аутом запроса SDK 20 секунд; при получении допускается ожидание 15 секунд с тайм-аутом запроса SDK 25 секунд. Ни один обработчик не ожидает полного завершения решения через client.solve.

Для локальной разработки выполните fastapi dev main.py из каталога с файлом. Маршруты: POST http://127.0.0.1:8000/captcha/tasks и GET http://127.0.0.1:8000/captcha/tasks/{task_id}. FastAPI обнаруживает объект app; отдельный URLconf регистрировать не нужно.

Создание и получение задачи, восстановление прерванных запросов

  1. 1.

    Создавайте задачу один раз со стабильным ID запроса

    Отправьте POST /captcha/tasks с X-Integration-Key и X-Request-ID, который вы сохраните для этой логической задачи. ID запроса должен содержать 1–64 ASCII-буквы, цифры, символы подчеркивания или дефисы. Маршрут передает его в solvethree как requestId. Сохраните возвращенный id задачи.

  2. 2.

    Проверяйте HTTP-статус перед чтением статуса задачи

    Обертка возвращает 401 при ошибке аутентификации, 400 при ошибках входных данных ValueError и 502 при перехваченных исключениях SolvethreeError. Поле detail ответа 502 содержит requestId и taskId из ошибки SDK. Обработайте эту HTTP-ошибку, прежде чем рассматривать ответ как задачу.

  3. 3.

    Получение существующей задачи

    Вызывайте GET /captcha/tasks/{task_id} с X-Integration-Key. Проверяйте status после каждого успешного HTTP-ответа. Запрос получения может вернуть задачу в незавершенном состоянии даже после окончания ожидания; повторно запросите ту же задачу вместо создания новой.

  4. 4.

    Восстановление создания с неизвестным результатом

    Если время ожидания создания истекло и у вас есть ID задачи, запросите ее. В противном случае повторите POST с исходным X-Request-ID и неизменными серверными входными данными задачи. Повторное использование этого ID с той же задачей возвращает существующую задачу; измененные входные данные вызывают конфликт. Храните исходный ID отдельно, не заменяя его значением requestId из ответа с ошибкой.

Что делать после успешного HTTP-ответа
Что делать после успешного HTTP-ответа
Статус задачиДействие клиента
pending или solvingПродолжайте запрашивать ту же задачу. Пригодного для использования решения пока нет.
готовоПрочитайте solution и подготовьте запрос к целевому сайту.
failedПрекратите опрос. Проверьте errorCode и error, прежде чем решать, есть ли смысл создавать новую задачу; средства за неудачные решения возвращаются.

Отправьте токен с исходным прокси и возвращенными идентификационными данными

Эти маршруты возвращают данные задачи; они ничего не отправляют на целевой сайт. Когда status станет ready, компонент, выполняющий запрос к целевому сайту, должен использовать solution.token, а не ID задачи.

Выполняйте отправку через тот же прокси, который использовался при создании задачи, с возвращенными идентификационными данными браузера solution.userAgent и solution.secChUa. Сохраняйте исходную конфигурацию задачи, а не полагайтесь на то, что в текущем окружении по-прежнему указан тот же прокси. Вспомогательная функция SDK successful_proxy(original_task, ready_result) выбирает прокси из этой исходной задачи.

Сохраняйте привязку отправки к нужному целевому сайту и действию. Задача со статусом ready означает, что solvethree сгенерировал решение; только ответ целевого сайта показывает, был ли принят запрос приложения.

Запустите первую задачу.

Начните с $5 на балансе рабочего пространства.

Создать рабочее пространство
Вызывайте solvethree из бэкенда FastAPI · solvethree