קריאה ל-solvethree מצד שרת של FastAPI
החזירו את המשימה לאחר יצירתה, ולא לאחר סיום הפתרון כולו. הפונה מאחזר את הסטטוס שלה עד שהוא 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. נתיב היצירה בונה את המשימה כולה מתצורת השרת; הפונים אינם מספקים את האתר, הפעולה או הפרוקסי בגוף הבקשה.
# 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.
ה־SDK של Python הוא סינכרוני. קריאה ישירה אליו מתוך async def תחסום את לולאת האירועים, ולכן שני המטפלים משתמשים ב־run_in_threadpool. היצירה משתמשת ב־wait_ms=0 עם זמן קצוב של 20 שניות לבקשת ה־SDK; האחזור מאפשר המתנה של 15 שניות עם זמן קצוב של 25 שניות לבקשת ה־SDK. אף אחד מהמטפלים אינו ממתין לסיום הפתרון כולו באמצעות 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.
יצירה פעם אחת עם מזהה בקשה קבוע
שלחו POST /captcha/tasks עם X-Integration-Key ועם X-Request-ID שתשמרו עבור המשימה הלוגית הזאת. מזהה הבקשה חייב להכיל 1–64 אותיות ASCII, ספרות, קווים תחתונים או מקפים. הנתיב מעביר אותו ל־solvethree בתור requestId. שמרו את מזהה המשימה שהוחזר.
- 2.
בדיקת סטטוס HTTP לפני קריאת סטטוס המשימה
המעטפת מחזירה 401 במקרה של כשל באימות, 400 במקרה של כשלי קלט מסוג ValueError, ו־502 עבור חריגות SolvethreeError שנתפסו. פרטי שגיאת 502 כוללים requestId ו־taskId משגיאת ה־SDK. טפלו בשגיאת ה־HTTP הזאת לפני שתתייחסו לתגובה כאל משימה.
- 3.
אחזור המשימה הקיימת
קראו ל־GET /captcha/tasks/{task_id} עם X-Integration-Key. בדקו את status לאחר כל תגובת HTTP מוצלחת. אחזור עשוי להחזיר משימה שטרם הגיעה למצב סופי גם לאחר שההמתנה הסתיימה; אחזרו שוב את אותה משימה במקום ליצור אחרת.
- 4.
שחזור יצירה שתוצאתה אינה ודאית
אם הזמן הקצוב ליצירה מסתיים ויש בידיכם מזהה משימה, אחזרו אותה. אחרת, חזרו על בקשת ה־POST עם ה־X-Request-ID המקורי ובלי לשנות את קלט המשימה בצד השרת. שימוש חוזר במזהה הזה עם אותה משימה מחזיר את המשימה הקיימת; שינוי הקלט גורם להתנגשות. שמרו את המזהה המקורי בנפרד במקום להחליפו ב־requestId מתגובת שגיאה.
| סטטוס משימה | פעולת הפונה |
|---|---|
| pending או solving | המשיכו לאחזר את אותה משימה. עדיין אין פתרון שניתן להשתמש בו. |
| מוכן | קראו את solution והכינו את הבקשה ליעד. |
| failed | הפסיקו את התשאול. בדקו את errorCode ואת error לפני שתחליטו אם יש טעם במשימה חדשה; עלות פתרונות שנכשלו מוחזרת. |
שליחת הטוקן עם הפרוקסי המקורי והזהות שהוחזרה
הנתיבים האלה מחזירים נתוני משימה; הם אינם שולחים דבר לאתר היעד. כאשר status הוא ready, הרכיב שמבצע את הבקשה ליעד חייב להשתמש ב־solution.token, ולא במזהה המשימה.
שלחו דרך אותו פרוקסי ששימש ליצירת המשימה, עם זהות הדפדפן שהוחזרה ב־solution.userAgent וב־solution.secChUa. שמרו את תצורת המשימה המקורית במקום להניח שהסביבה הנוכחית עדיין מכילה את אותו פרוקסי. פונקציית העזר successful_proxy(original_task, ready_result) של ה־SDK בוחרת את הפרוקסי מתוך המשימה המקורית הזאת.
שמרו על הקשר בין השליחה לבין היעד והפעולה המיועדים. משימה בסטטוס ready פירושה ש־solvethree יצר פתרון; רק תגובת היעד מעידה אם בקשת האפליקציה התקבלה.
מקורות ותיעוד API
הפעלת המשימה הראשונה שלך.
התחילו עם $5 בקרדיט לסביבת העבודה.