عندما تحتاج خدمات أو أعضاء فريق متعددون إلى حل اختبار CAPTCHA، فإن مركزيته في خدمة صغيرة يتجنب تكرار المنطق عبر المشاريع. إن الدعم غير المتزامن لـ FastAPI يجعله مناسبًا تمامًا - يتضمن حل اختبار CAPTCHA انتظار استجابات واجهة برمجة التطبيقات الخارجية، والتي تتعامل بشكل غير متزامن بكفاءة دون حظر سلاسل الرسائل.
ينشئ هذا الدليل خدمة FastAPI الصغيرة التي تقبل طلبات حل اختبار CAPTCHA عبر REST وتعيد الرموز المميزة التي تم حلها عبر CaptchaAI.
متى تبني خدمة صغيرة، ومتى يكفي دمج مباشر؟
| السيناريو | خدمة FastAPI صغيرة | دمج مباشر داخل التطبيق |
|---|---|---|
| أكثر من خدمة أو فريق يحتاج نفس منطق الحل | أفضل | يكرر المنطق في أكثر من مكان |
| تطبيق واحد بسيط وتجربة أولية | ممكن لكنه زائد غالبًا | أبسط |
| تحتاج مراقبة موحدة وحدود معدل ومصادقة داخلية | أفضل | أصعب في التوحيد |
| تحتاج أقل زمن إضافي ممكن داخل خدمة واحدة | قد يضيف hop داخليًا | أفضل إذا كانت البساطة أهم |
ما تحتاجه
| المتطلبات | التفاصيل |
|---|---|
| مفتاح CaptchaAI API | captchaai.com |
| بايثون 3.9+ | |
| ** FastAPI + httpx ** | للتعامل مع HTTP غير المتزامن |
تثبيت التبعيات:
pip install fastapi uvicorn httpx
هيكل المشروع
captcha-service/
├── main.py # FastAPI app with endpoints
├── solver.py # CaptchaAI solving logic
└── requirements.txt
وحدة حل 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)
تطبيق 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"}
قم بتشغيل الخدمة
uvicorn main:app --host 0.0.0.0 --port 8000
أمثلة الاستخدام
حل reCAPTCHA v2
curl -X POST http://localhost:8000/solve/recaptcha-v2 \
-H "Content-Type: application/json" \
-d '{"sitekey": "6Le-wvkS...", "pageurl": "https://example.com/login"}'
حل Cloudflare Turnstile
curl -X POST http://localhost:8000/solve/turnstile \
-H "Content-Type: application/json" \
-d '{"sitekey": "0x4AAAA...", "pageurl": "https://example.com/form"}'
الرد:
{
"token": "03AGdBq24PBCqLmOx2V4...",
"user_agent": "Mozilla/5.0..."
}
استكشاف الأخطاء وإصلاحها
| المشكلة | السبب | الإجراء |
|---|---|---|
| رد 502 | قام CaptchaAI بإرجاع خطأ | تحقق من الحقل detail بحثًا عن الخطأ المحدد |
| مهلة على الحل | استغرق اختبار CAPTCHA وقتًا طويلاً | قم بزيادة max_attempts أو تحقق من حالة CaptchaAI |
| تم رفض الاتصال | الخدمة لا تعمل | تحقق من تشغيل uvicorn على المنفذ المتوقع |
| ردود بطيئة | حظر I/O | تأكد من استخدام httpx.AsyncClient، وليس requests |
الأسئلة الشائعة
لماذا نستخدم FastAPI لخدمة حل اختبار CAPTCHA؟
يتعامل FastAPI مع I/O غير المتزامن محليًا، وهو مثالي لحل اختبار CAPTCHA حيث يتم قضاء معظم الوقت في انتظار استجابة CaptchaAI. يمكن معالجة طلبات متعددة بشكل متزامن دون الحاجة إلى ترابط.
هل يمكنني إضافة المصادقة إلى نقاط النهاية؟
نعم. أضف حقنة تبعية FastAPI مع التحقق من صحة رأس مفتاح API أو OAuth2 لتقييد الوصول.
كم عدد الطلبات المتزامنة التي يمكن لهذا التعامل معها؟
محدودة بحد المهام المتزامنة لخطة CaptchaAI. يمكن لـ FastAPI نفسه التعامل مع آلاف الاتصالات المتزامنة.
هل يجب علي إرساء هذا؟
نعم. أضف Dockerfile مع FROM python:3.11-slim، وقم بتثبيت التبعيات، واكشف عن المنفذ 8000.
هل يمكنني إضافة حد للسعر؟
نعم. استخدم slowapi أو الوكيل العكسي (nginx، Traefik) للحد من الطلبات لكل عميل.
إذا كنت تريد توحيد منطق الحل ومراقبته في مكان واحد، فخدمة FastAPI الصغيرة تمنحك طبقة داخلية مستقرة يمكن لبقية الأنظمة استدعاؤها بدل تكرار التكامل في كل مشروع.