פתרון ושליחה של reCAPTCHA באמצעות aiohttp

מאת solvethree3 דקות קריאה

השתמשו ב-aiohttp ישירות מול REST API: צרו משימה אחת, בדקו את מצבה עד שהיא מוכנה ואז שלחו את solution.token ליעד. הפרידו בין בקשות ה-API לבקשות היעד באמצעות סשנים נפרדים, כדי שטוקן ה-Bearer של סביבת העבודה שלכם לעולם לא יגיע ליעד.

הדוגמה דורשת Python 3.11+ ומבצעת את היצירה, בדיקות המצב והשליחה ליעד במסגרת מגבלת זמן כוללת של 180 שניות. זו מגבלת זמן של היישום, לא זמן פתרון מובטח.

בדף הזה

הגדירו את האתר, הפרוקסי ובקשת היעד

  • הגדירו את SOLVETHREE_API_KEY למפתח ה-API של סביבת העבודה שלכם. שמרו אותו בשרת.
  • הגדירו את SOLVETHREE_PROXY לכתובת ה-URL של הפרוקסי שבו השירות ישתמש לפתרון. השליחה ליעד משתמשת באותו פרוקסי.
  • החליפו את accounts.example.com ואת הפעולה login בשם המארח ובפעולה שבהם האינטגרציה שלכם משתמשת. לאתר נדרש פרופיל פעיל שזמין לסביבת העבודה שלכם; הגדירו את הפרופיל לפני יצירת משימות.
  • החליפו את כתובת ה-URL לכניסה ליעד ואת נתוני הטופס בבקשה האמיתית של היישום. הדוגמה שולחת רק g-recaptcha-response; הוסיפו את שאר השדות שהיעד דורש והשתמשו בשדה הטוקן שהוא מצפה לו.

המשימה שולחת site, action ו-proxy יחיד. ברירת המחדל שלה היא reCAPTCHA Enterprise v3; אל תוסיפו שדות type או url. אם התהליך ביעד זקוק לעוגיות מבקשה קודמת, בצעו את הבקשות האלה דרך סשן היעד — הדוגמה מתחילה בסשן חדש.

צרו פעם אחת, בדקו את המצב ואז שלחו

aiohttp · יצירה פעם אחת, תשאול ושליחה
# pip install aiohttp
import asyncio
import os
import uuid
from urllib.parse import urlsplit, unquote
import aiohttp

async def main():
    api = "https://api.solvethree.com/v1"
    proxy = os.environ["SOLVETHREE_PROXY"]
    task = {"site": "accounts.example.com", "action": "login", "proxy": proxy, "requestId": str(uuid.uuid4())}
    task_id = None
    try:
        async with asyncio.timeout(180):
            async with aiohttp.ClientSession(headers={"Authorization": "Bearer " + os.environ["SOLVETHREE_API_KEY"]}) as client:
                async with client.post(api + "/tasks", params={"waitMs": 0}, json=task, allow_redirects=False) as response:
                    response.raise_for_status()
                    if response.status >= 300: raise RuntimeError("Unexpected API redirect")
                    result = await response.json()
                task_id = result["id"]
                while result["status"] in ("pending", "solving"):
                    async with client.get(api + "/tasks/" + task_id, params={"waitMs": 15000}, allow_redirects=False) as response:
                        response.raise_for_status()
                        if response.status >= 300: raise RuntimeError("Unexpected API redirect")
                        result = await response.json()
                    if result["status"] in ("pending", "solving"): await asyncio.sleep(1)
                if result["status"] != "ready":
                    raise RuntimeError("Task failed: " + str(result.get("errorCode", "unknown")))
            solution = result["solution"]
            # A separate session prevents the API Bearer header reaching the target.
            proxy_url = urlsplit(proxy)
            netloc = proxy_url.netloc.rsplit("@", 1)[-1]
            server = f"{proxy_url.scheme}://{netloc}"
            auth = aiohttp.BasicAuth(unquote(proxy_url.username), unquote(proxy_url.password or "")) if proxy_url.username else None
            async with aiohttp.ClientSession() as target:
                async with target.post("https://accounts.example.com/login", proxy=server, proxy_auth=auth,
                    headers={"User-Agent": solution["userAgent"], "sec-ch-ua": solution["secChUa"]},
                    data={"g-recaptcha-response": solution["token"]}, allow_redirects=False) as response:
                    print("Application HTTP status:", response.status)
    except TimeoutError:
        print("Timed out; recover requestId", task["requestId"], "taskId", task_id)
        raise

asyncio.run(main())

זהו שימוש אסינכרוני ישיר ב-REST, ולא מתודה אסינכרונית ב-SDK הרשמי של Python. הוא שולח בקשת POST אחת ליצירה אל /v1/tasks, שומר את ה-id שהוחזר ומשתמש בבקשות GET לבדיקת מצב המשימה. pending ו-solving ממשיכים את הלולאה; ready מאפשר שליחה; משימה בסטטוס failed עוצרת את הלולאה.

ה-proxy בגוף המשימה מורה ל-solvethree באיזה פרוקסי להשתמש. הארגומנטים proxy ו-proxy_auth של aiohttp מופיעים רק בקריאת ה-HTTP ליעד — לא בקריאות ל-API. הדוגמה מפרידה בין פרטי ההזדהות לפרוקסי לבין כתובת ה-URL של שרת הפרוקסי, ושולחת את הטוקן עם userAgent ו-secChUa שהוחזרו.

הסשנים נפרדים במכוון: רק לסשן ה-API יש כותרת Authorization. הפניות מושבתות, והפניות מה-API מטופלות כשגיאות במקום לעבור אליהן.

בקשת API מחזירה שגיאת HTTP.

הדוגמה בודקת את סטטוס ה-HTTP לפני קריאת תוכן תגובת הצלחה.

כדאי לנסות: טפלו בשגיאת ה-HTTP בנפרד מכישלון המשימה. תקנו קלט לא תקין או בעיות הרשאה לפני ניסיון חוזר.

המשימה מגיעה לסטטוס failed.

עיינו ב-errorCode וב-error בתגובת המשימה. הדוגמה מעלה חריגה עם errorCode בלבד.

כדאי לנסות: הפסיקו לבדוק את מצב המשימה הזו וטפלו בגורם שדווח. תקנו את הגורם שדווח לפני ניסיון נוסף.

המשימה בסטטוס ready, אבל היישום דוחה את הבקשה.

בדקו את שדה הטוקן שנשלח, את כתובת ה-URL של היעד, את זהות הדפדפן והפרוקסי שהוחזרו, וכן את כל שדות הטופס או העוגיות הנדרשים.

כדאי לנסות: שלחו את solution.token עם הזהות שהוחזרה דרך אותו פרוקסי. קראו את תגובת היישום לפי קריטריוני ההצלחה של אותו יעד — סטטוס ה-HTTP שמודפס לבדו לא מוכיח שהבקשה התקבלה.

התאוששו מחריגה ממגבלת הזמן בלי לרכוש פתרון נוסף

חריגה ממגבלת הזמן בעת יצירה לא מוכיחה שהיצירה נכשלה. הדוגמה שומרת את הקלט המקורי ב-task ומדפיסה את ה-requestId שלו ואת task_id כשמגבלת הזמן מסתיימת. המשתנים האלה נשמרים רק כל עוד התהליך פועל; המזהים המודפסים אינם תיעוד מלא להתאוששות.

  1. 1.

    שמרו את הבקשה המקורית לפני היצירה

    כדי לאפשר התאוששות לאחר הפעלה מחדש, שמרו באופן מאובטח את גוף המשימה המלא, כולל ה-requestId וה-proxy שלו. הדוגמה יוצרת UUID חדש בכל הרצה, ולכן הרצה חוזרת שלה פשוט יוצרת בקשה לוגית חדשה.

  2. 2.

    המשיכו את המשימה הקיימת

    אם יש לכם task_id, אחזרו את המשימה הזו. אם היצירה חרגה ממגבלת הזמן לפני שקיבלתם מזהה, חזרו על היצירה עם גוף המשימה וה-requestId השמורים, ללא שינוי. ה-API מחזיר את המשימה הקיימת; שינוי הקלט תוך שימוש חוזר במזהה יוצר התנגשות.

  3. 3.

    בדקו אם השליחה כבר התבצעה

    מגבלת הזמן כוללת גם את בקשת ה-POST ליעד. אם הבקשה הזו חרגה ממגבלת הזמן, בדקו את התוצאה ביישום לפני שתשלחו שוב: ייתכן שהוא קיבל את הבקשה אף שהלקוח שלכם לא קיבל תגובה. שחזור משימת solvethree לא קובע מה קרה ביעד.

הפעלת המשימה הראשונה שלך.

התחילו עם $5 בקרדיט לסביבת העבודה.

יצירת סביבת עבודה
פתרון ושליחה של reCAPTCHA באמצעות aiohttp · solvethree