Integrasi

Bangun Microservice Solve CAPTCHA dengan FastAPI dan CaptchaAI

Ketika beberapa layanan atau anggota tim memerlukan solve CAPTCHA, memusatkannya ke dalam microservice menghindari duplikasi logika di seluruh proyek. Dukungan async FastAPI membuatnya sangat cocok — solve CAPTCHA melibatkan menunggu respons API eksternal, yang ditangani async secara efisien tanpa blocking thread.

Panduan ini membangun microservice FastAPI yang menerima request solve CAPTCHA via REST dan mengembalikan token yang di-solve melalui CaptchaAI.


Yang Anda Butuhkan

Kebutuhan Detail
API Key CaptchaAI captchaai.com
Python 3.9+
FastAPI + httpx Untuk penanganan HTTP async

Instal dependensi:

pip install fastapi uvicorn httpx

Struktur Proyek

captcha-service/
├── main.py          # FastAPI app with endpoints
├── solver.py        # CaptchaAI solving logic
└── requirements.txt

Modul Solver CaptchaAI

# solver.py
import httpx
import asyncio

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://ocr.captchaai.com"


async def submit_task(params: dict) -> str:
    """Submit a CAPTCHA task and return the task ID."""
    params["key"] = API_KEY
    params["json"] = 1

    async with httpx.AsyncClient() as client:
        response = await client.post(f"{BASE_URL}/in.php", data=params)
        data = response.json()

    if data.get("status") != 1:
        raise ValueError(f"Submit error: {data.get('request')}")
    return data["request"]


async def poll_result(task_id: str, initial_wait: int = 15, max_attempts: int = 30) -> dict:
    """Poll for the CAPTCHA result."""
    await asyncio.sleep(initial_wait)

    async with httpx.AsyncClient() as client:
        for _ in range(max_attempts):
            response = await client.get(f"{BASE_URL}/res.php", params={
                "key": API_KEY, "action": "get", "id": task_id, "json": 1
            })
            data = response.json()

            if data.get("status") == 1:
                return {
                    "token": data["request"],
                    "user_agent": data.get("user_agent", "")
                }
            if data.get("request") != "CAPCHA_NOT_READY":
                raise ValueError(f"Solve error: {data['request']}")

            await asyncio.sleep(5)

    raise TimeoutError("Solve timed out")


async def solve_recaptcha_v2(sitekey: str, pageurl: str, enterprise: bool = False) -> dict:
    params = {"method": "userrecaptcha", "googlekey": sitekey, "pageurl": pageurl}
    if enterprise:
        params["enterprise"] = 1
    task_id = await submit_task(params)
    return await poll_result(task_id, initial_wait=20)


async def solve_recaptcha_v3(sitekey: str, pageurl: str, action: str, enterprise: bool = False) -> dict:
    params = {
        "method": "userrecaptcha", "version": "v3",
        "googlekey": sitekey, "pageurl": pageurl, "action": action
    }
    if enterprise:
        params["enterprise"] = 1
    task_id = await submit_task(params)
    return await poll_result(task_id, initial_wait=20)


async def solve_turnstile(sitekey: str, pageurl: str) -> dict:
    task_id = await submit_task({"method": "turnstile", "sitekey": sitekey, "pageurl": pageurl})
    return await poll_result(task_id, initial_wait=10)


async def solve_image(image_base64: str) -> dict:
    task_id = await submit_task({"method": "base64", "body": image_base64})
    return await poll_result(task_id, initial_wait=5, max_attempts=15)

Aplikasi FastAPI

# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional
import solver

app = FastAPI(title="CaptchaAI Solver Service")


class RecaptchaV2Request(BaseModel):
    sitekey: str
    pageurl: str
    enterprise: bool = False


class RecaptchaV3Request(BaseModel):
    sitekey: str
    pageurl: str
    action: str
    enterprise: bool = False


class TurnstileRequest(BaseModel):
    sitekey: str
    pageurl: str


class ImageRequest(BaseModel):
    image_base64: str


class SolveResponse(BaseModel):
    token: str
    user_agent: Optional[str] = ""


@app.post("/solve/recaptcha-v2", response_model=SolveResponse)
async def solve_recaptcha_v2(req: RecaptchaV2Request):
    try:
        result = await solver.solve_recaptcha_v2(req.sitekey, req.pageurl, req.enterprise)
        return SolveResponse(**result)
    except (ValueError, TimeoutError) as e:
        raise HTTPException(status_code=502, detail=str(e))


@app.post("/solve/recaptcha-v3", response_model=SolveResponse)
async def solve_recaptcha_v3(req: RecaptchaV3Request):
    try:
        result = await solver.solve_recaptcha_v3(req.sitekey, req.pageurl, req.action, req.enterprise)
        return SolveResponse(**result)
    except (ValueError, TimeoutError) as e:
        raise HTTPException(status_code=502, detail=str(e))


@app.post("/solve/turnstile", response_model=SolveResponse)
async def solve_turnstile(req: TurnstileRequest):
    try:
        result = await solver.solve_turnstile(req.sitekey, req.pageurl)
        return SolveResponse(**result)
    except (ValueError, TimeoutError) as e:
        raise HTTPException(status_code=502, detail=str(e))


@app.post("/solve/image", response_model=SolveResponse)
async def solve_image(req: ImageRequest):
    try:
        result = await solver.solve_image(req.image_base64)
        return SolveResponse(**result)
    except (ValueError, TimeoutError) as e:
        raise HTTPException(status_code=502, detail=str(e))


@app.get("/health")
async def health():
    return {"status": "ok"}

Jalankan Service

uvicorn main:app --host 0.0.0.0 --port 8000

Contoh Penggunaan

Solve reCAPTCHA v2

curl -X POST http://localhost:8000/solve/recaptcha-v2 \
  -H "Content-Type: application/json" \
  -d '{"sitekey": "6Le-wvkS...", "pageurl": "https://staging.example.com/qa-login"}'

Solve Cloudflare Turnstile

curl -X POST http://localhost:8000/solve/turnstile \
  -H "Content-Type: application/json" \
  -d '{"sitekey": "0x4AAAA...", "pageurl": "https://example.com/form"}'

Respon:

{
  "token": "03AGdBq24PBCqLmOx2V4...",
  "user_agent": "Mozilla/5.0..."
}

Catatan Hardening Deployment

  • Baca API key dari environment variable dan fail cepat saat startup jika secret tidak ada.
  • Pisahkan validasi request dari eksekusi solver agar payload yang tidak valid tidak pernah mencapai jalur outbound call.
  • Tampilkan respons error terstruktur yang membedakan kegagalan validasi, kegagalan solver, dan penolakan upstream.

Pemecahan Masalah

Masalah Penyebab Perbaikan
Response 502 CaptchaAI mengembalikan error Periksa field detail untuk error spesifik
Timeout solve CAPTCHA memakan waktu terlalu lama Tingkatkan max_attempts atau periksa status CaptchaAI
Connection refused Service tidak berjalan Pastikan uvicorn berjalan di port yang benar
Response lambat Blocking I/O Pastikan httpx.AsyncClient digunakan, bukan requests

Pertanyaan Umum

Mengapa menggunakan FastAPI untuk service solve CAPTCHA?

FastAPI menangani async I/O secara native, ideal untuk solve CAPTCHA di mana sebagian besar waktu dihabiskan menunggu respons CaptchaAI. Beberapa request dapat diproses secara concurrent tanpa threading.

Bisakah saya menambahkan autentikasi ke endpoint?

Ya. Tambahkan dependency injection FastAPI dengan validasi header API key atau OAuth2 untuk membatasi akses.

Berapa banyak concurrent request yang dapat ditangani?

Dibatasi oleh batas concurrent task paket CaptchaAI Anda. FastAPI sendiri dapat menangani ribuan koneksi secara bersamaan.

Haruskah saya menjalankannya dalam Docker?

Ya. Tambahkan Dockerfile dengan FROM python:3.11-slim, instal dependensi, dan expose port 8000.

Bisakah saya menambahkan rate limiting?

Ya. Gunakan slowapi atau reverse proxy (nginx, Traefik) untuk membatasi request per client.


Mulai Sekarang

Dapatkan API key Anda di captchaai.com. Sentralisasi solve CAPTCHA dengan microservice FastAPI.


Panduan Terkait

  • Cara Solve reCAPTCHA v2 Menggunakan API
  • Cara Solve Cloudflare Turnstile Menggunakan API
  • Async CaptchaAI dengan aiohttp
Komentar dinonaktifkan untuk artikel ini.