שימוש ב-solvethree ברכיב תווכה להורדה של Scrapy
השתמשו ב-middleware אסינכרוני להורדה כדי לפתור רק בקשות שה-spider שלכם מסמן במפורש. הריצו את ה-SDK הסינכרוני של solvethree בתהליכון עבודה, ואז החזירו FormRequest שמכיל את הטוקן, הפרוקסי וזהות הדפדפן שהוחזרה.
הדוגמה מטפלת בנקודת קצה מוגדרת אחת של טופס reCAPTCHA Enterprise. היא אינה מזהה אתגרים ואינה מגלה כיצד אתר שרירותי מצפה לקבל את הטוקן שלו.
בדף הזה
הגדרת היעד לפני הפעלת ה-middleware
- השתמשו ב-Scrapy 2.19+, ב-Python 3.10+ וב-SDK הרשמי של solvethree ל-Python. ה-SDK סינכרוני; אין לו לקוח אסינכרוני מובנה.
- צרו בקונסולה פרופיל אתר פעיל לסביבת העבודה שלכם. שליחת שם מארח ופעולה אינה יוצרת פרופיל. ראו הגדרת פרופיל אתר.
- הגדירו את TARGET_URL לכתובת המדויקת לשליחת הטופס, את SOLVETHREE_PROXY לפרוקסי המשמש לבקשת היישום הזו, ואת SOLVETHREE_API_KEY למפתח סביבת העבודה שלכם. שמרו את המפתח בצד השרת.
- הפעילו את AsyncioSelectorReactor ורשמו את ה-middleware בעדיפות 740, כפי שמוצג בהמשך. כך הוא ימוקם לפני HttpProxyMiddleware בעדיפות 750.
פתרון רק עבור בקשות שסומנו במפורש
# middlewares.py; Scrapy 2.19+, Python 3.10+, official solvethree SDK.
import asyncio
import os
from urllib.parse import urlsplit
from scrapy.http import FormRequest
from solvethree import Solvethree
class CaptchaMiddleware:
async def process_request(self, request):
if not request.meta.get("solvethree_form") or request.meta.get("solvethree_applied"):
return None
target = os.environ["TARGET_URL"]
if request.url != target:
raise ValueError("Only the configured form target may use this middleware")
proxy = os.environ["SOLVETHREE_PROXY"]
def solve():
return Solvethree(os.environ["SOLVETHREE_API_KEY"]).solve({
"site": urlsplit(target).hostname, "action": "login", "proxy": proxy,
"requestId": request.meta["solvethree_request_id"],
}, timeout=180)
result = await asyncio.to_thread(solve)
solution = result["solution"]
fields = dict(request.meta["solvethree_fields"])
fields["g-recaptcha-response"] = solution["token"]
meta = {**request.meta, "proxy": proxy, "solvethree_applied": True,
"dont_retry": True, "dont_redirect": True}
return FormRequest(target, formdata=fields, callback=request.callback,
errback=request.errback, headers={"User-Agent": solution["userAgent"],
"sec-ch-ua": solution["secChUa"]}, meta=meta, dont_filter=True)
# settings.py:
# TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
# DOWNLOADER_MIDDLEWARES = {"myproject.middlewares.CaptchaMiddleware": 740}
# The spider first loads its form/CSRF data with the same proxy and cookiejar.
# Then yield a Request(TARGET_URL, callback=your_result_handler, meta={
# "solvethree_form": True, "solvethree_request_id": one_saved_logical_job_id,
# "solvethree_fields": {"csrf": token_from_the_form, "email": "your-test-value"},
# "cookiejar": your_cookiejar_id,
# })
# Inspect the final response in your_result_handler; a ready task is not that response.המתודה process_request של ה-middleware מקבלת רק request, ללא הארגומנט המיושן spider. בקשות שלא סומנו עוברות ללא שינוי. בקשה מסומנת חייבת להתאים בדיוק ל-TARGET_URL; אי-התאמה גורמת לשגיאה במקום לשלוח טוקן לנקודת קצה אחרת.
asyncio.to_thread מריץ את קריאות הרשת והתשאול של ה-SDK הסינכרוני מחוץ לתהליכון של לולאת האירועים. הכרזה על process_request כאסינכרונית בלבד לא הייתה עושה זאת. ה-SDK יוצר משימה וממתין לתוצאה מוכנה או זורק חריגה; לאחר מכן ה-middleware בונה את בקשת שליחת הטופס.
התאמה לטופס שהיישום שלכם שולח בפועל
- 1.
הגדרת הפעולה ושדה הטוקן הנכונים
הדוגמה משתמשת בפעולה login ומכניסה את solution.token אל g-recaptcha-response. שנו אותם כך שיתאימו לשילוב של היעד. השדה site של המשימה נגזר משם המארח של TARGET_URL; משימות reCAPTCHA אינן מקבלות שדות type או url. השמטת recaptchaType בוחרת ב-enterprise-v3.
- 2.
אספקת שדות הטופס הקיימים
ה-spider חייב למלא את solvethree_fields בשדות הנדרשים של נקודת הקצה, כולל ערך ה-CSRF הנוכחי שלה. ה-middleware מעתיק את השדות האלה ומוסיף את הטוקן; הוא אינו טוען את הטופס או מחלץ שדות קלט מוסתרים.
- 3.
שמירה על עקביות הסשן
טענו את הטופס הראשוני דרך אותו פרוקסי ועם זהות הדפדפן שהיישום דורש. העבירו את מזהה ה-cookiejar שלו במטא-נתונים של הבקשה המסומנת. ה-FormRequest המוחזר שומר על אותו cookiejar ומשתמש ב-solution.userAgent וב-solution.secChUa, אך הדוגמה אינה מכינה או מתקנת את הסשן הקודם.
- 4.
טיפול בתגובת היישום
ספקו callback שבודק אם שליחת הטופס הצליחה ו-errback לכשלים בבקשה. משימה מוכנה פירושה שנוצר פתרון, ולא שהאתר קיבל את הבקשה שבאה לאחר מכן.
הדוגמה משתמשת בכוונה בפרוקסי אחד לפתרון ולשליחה. אל תחליפו אותו בפרוקסי לא קשור לאחר הפתרון. בדקו גם כל middleware מותאם אישית להורדה שמשכתב את User-Agent או את רמזי הלקוח: אסור לו לדרוס את הזהות שהוחזרה עם הפתרון.
מניעת יצירת פתרון נוסף בניסיונות חוזרים
שמרו את solvethree_request_id לפני העברת הבקשה המסומנת באמצעות yield, והמשיכו להשתמש בו עבור אותו פתרון לוגי. requestId מקבל 1–64 אותיות ASCII, ספרות, קווים תחתונים או מקפים. שימוש חוזר בו עם קלט משימה זהה מאחזר את המשימה הקיימת; שינוי הקלט תוך שמירה על המזהה יוצר התנגשות.
ה-FormRequest המוחזר מגדיר solvethree_applied כדי שלא יפעיל פתרון נוסף. הוא מגדיר גם dont_retry ו-dont_redirect, וכך מונע ניסיונות חוזרים והפניות אוטומטיים עבור אותה שליחה. הדגלים האלה אינם מונעים מה-callback או ממריץ העבודות שלכם להתחיל בקשה נוספת, לכן קבלו את ההחלטה הזו במפורש.
- תם הזמן הקצוב לקריאת הפתרון.
בדקו אם כבר נוצרה משימה. חריגה מזמן החיבור הקצוב אינה מוכיחה שהיצירה נכשלה.
כדאי לנסות: אחזרו את המשימה הידועה או שחזרו אותה באמצעות requestId שנשמר ואותם קלטי משימה, לפני יצירת בקשת פתרון לוגית חדשה.
- פעולת הפתרון מעלה חריגה במקום להחזיר תוצאה.
הבחינו בין שגיאה בבקשת HTTP לבין כשל סופי במשימה. במשימה שנכשלה, בדקו את errorCode ואת error.
כדאי לנסות: טפלו בכשל במקום להחזיר שוב ושוב את אותה בקשה מסומנת באמצעות yield. תקנו קלטים לא תקינים לפני ניסיון נוסף; אין להמשיך לתשאל משימות שנכשלו.
- האתר דוחה את הטופס שנשלח.
בדקו תחילה את שדה הטוקן היוצא, שדות CSRF, קובצי Cookie, הפרוקסי וזהות הדפדפן.
כדאי לנסות: תקנו את בקשת היישום לפני שתשלמו על פתרון נוסף. השדה חייב להכיל את solution.token, ולא את מזהה המשימה או טוקן ישן.
מקורות ותיעוד API
הפעלת המשימה הראשונה שלך.
התחילו עם $5 בקרדיט לסביבת העבודה.