Appeler solvethree depuis un backend FastAPI

Par solvethree5 min de lecture

Renvoyez la tâche après sa création, sans attendre la fin de toute la résolution. L’appelant récupère son statut jusqu’à ce qu’il soit ready ou failed, puis soumet le jeton à la cible si la résolution a réussi.

Sur cette page

Configurez le serveur et la cible

Utilisez Python 3.10 ou une version ultérieure. Installez FastAPI avec python -m pip install "fastapi[standard]", puis installez le SDK officiel avec python -m pip install https://solvethree.com/downloads/solvethree_sdk-0.1.0-py3-none-any.whl.

Définissez ces variables d’environnement dans le processus serveur avant de démarrer l’application :

  • SOLVETHREE_API_KEY : la clé API de votre espace de travail. Conservez-la sur le serveur ; le SDK l’utilise pour s’authentifier auprès de solvethree.
  • INTEGRATION_KEY : un secret distinct que les appelants envoient dans l’en-tête X-Integration-Key pour s’authentifier auprès de vos routes FastAPI.
  • CAPTCHA_SITE : le nom d’hôte cible, pas une URL complète.
  • SOLVETHREE_PROXY : l’URL du proxy HTTP ou HTTPS utilisé pour cette tâche, sans chemin, paramètres de requête ni fragment.

Créez un profil actif pour la cible dans votre espace de travail avant d’appeler la route. L’exemple fixe l’action à login ; le profil et la requête prévue vers la cible doivent donc correspondre à cet usage. Fournir un nom d’hôte ne crée pas de profil ; consultez la configuration d’un profil de site.

Ajouter et exécuter les routes FastAPI

Enregistrez cet exemple dans main.py. Les deux routes exigent X-Integration-Key. La route de création construit entièrement sa tâche à partir de la configuration du serveur ; les appelants ne fournissent ni le site, ni l’action, ni le proxy dans le corps de la requête.

FastAPI · exécuter le SDK synchrone dans un pool de threads
# 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})

La tâche utilise reCAPTCHA Enterprise v3 par défaut. Elle envoie site, action et un seul proxy, sans champ type ni url.

Le SDK Python est synchrone. L’appeler directement dans async def bloquerait la boucle d’événements ; les deux gestionnaires utilisent donc run_in_threadpool. La création utilise wait_ms=0 avec un délai d’expiration des requêtes SDK de 20 secondes ; la récupération autorise une attente de 15 secondes avec un délai d’expiration des requêtes SDK de 25 secondes. Aucun des deux gestionnaires n’attend la fin de toute la résolution avec client.solve.

Pour le développement local, exécutez fastapi dev main.py depuis le répertoire contenant le fichier. Les routes sont POST http://127.0.0.1:8000/captcha/tasks et GET http://127.0.0.1:8000/captcha/tasks/{task_id}. FastAPI détecte l’objet app ; il n’y a pas de URLconf distinct à enregistrer.

Créer une tâche, la récupérer et reprendre les requêtes interrompues

  1. 1.

    Créer une seule fois avec un ID de requête stable

    Envoyez POST /captcha/tasks avec X-Integration-Key et un X-Request-ID que vous conservez pour cette tâche logique. L’ID de requête doit contenir 1–64 lettres ASCII, chiffres, traits de soulignement ou traits d’union. La route le transmet à solvethree sous le nom requestId. Enregistrez l’ID de tâche renvoyé.

  2. 2.

    Vérifier le statut HTTP avant de lire le statut de la tâche

    La couche d’intégration renvoie 401 en cas d’échec d’authentification, 400 pour les erreurs de saisie ValueError et 502 pour les exceptions SolvethreeError interceptées. Le détail de sa réponse 502 contient requestId et taskId issus de l’erreur du SDK. Traitez cette erreur HTTP avant de considérer la réponse comme une tâche.

  3. 3.

    Récupérer la tâche existante

    Appelez GET /captcha/tasks/{task_id} avec X-Integration-Key. Vérifiez status après chaque réponse HTTP réussie. Une récupération peut renvoyer une tâche dans un état non terminal même après la fin de son attente ; récupérez à nouveau cette même tâche plutôt que d’en créer une autre.

  4. 4.

    Reprendre une création au résultat incertain

    Si la création expire et que vous avez un ID de tâche, récupérez la tâche. Sinon, répétez le POST avec votre X-Request-ID d’origine et les paramètres de tâche côté serveur inchangés. Réutiliser cet ID avec la même tâche renvoie la tâche existante ; des paramètres modifiés provoquent un conflit. Conservez l’ID d’origine séparément plutôt que de le remplacer par le requestId d’une réponse d’erreur.

Que faire après une réponse HTTP réussie
Que faire après une réponse HTTP réussie
Statut de la tâcheAction de l’appelant
pending ou solvingContinuez à récupérer la même tâche. Aucune solution utilisable n’est encore disponible.
readyLisez solution et préparez la requête vers la cible.
failedArrêtez l’interrogation. Examinez errorCode et error avant de décider s’il est pertinent de créer une nouvelle tâche ; les résolutions échouées sont remboursées.

Soumettre le jeton avec le proxy d’origine et l’identité renvoyée

Ces routes renvoient les données des tâches ; elles ne soumettent rien au site web cible. Une fois que status vaut ready, le composant qui effectue la requête vers la cible doit utiliser solution.token, et non l’ID de tâche.

Effectuez la soumission via le même proxy que celui utilisé pour créer cette tâche, avec l’identité de navigateur solution.userAgent et solution.secChUa renvoyée. Conservez la configuration d’origine de la tâche plutôt que de supposer que l’environnement actuel contient toujours le même proxy. La fonction utilitaire successful_proxy(original_task, ready_result) du SDK sélectionne le proxy dans cette tâche d’origine.

Gardez la soumission associée à la cible et à l’action prévues. Une tâche ready signifie que solvethree a généré une solution ; seule la réponse de la cible vous indique si la requête de l’application a été acceptée.

Lancez votre première tâche.

Démarrez avec $5 de crédit dans votre espace de travail.

Créer un espace de travail
Appeler solvethree depuis un backend FastAPI · solvethree