حل reCAPTCHA Enterprise باستخدام Go

بقلم solvethreeمدة القراءة: 2 دقيقة

ثبّت solvethree.com/sdk واستدعِ Solve مع اسم المضيف المستهدف والإجراء والوكيل. تنشئ حزمة SDK المهمة مرة واحدة وتستطلع النتيجة. ثم يرسل تطبيقك الرمز إلى الجهة المستهدفة.

في هذه الصفحة

ثبّت حزمة SDK واضبط إعداداتها

استخدم Go 1.22+. شغّل ما يلي في وحدة Go لديك:

تثبيت SDK الرسمي لـ Go
go get solvethree.com/sdk@v0.1.0
  • اضبط SOLVETHREE_API_KEY على مفتاح API لمساحة عملك، وSOLVETHREE_PROXY على عنوان URL لوكيل HTTP(S) لديك. احتفظ بكليهما في إعدادات الخادم.
  • أنشئ ملفًا تعريفيًا نشطًا لاسم المضيف المستهدف في مساحة عملك. راجع إعداد ملف الموقع التعريفي.
  • استبدل accounts.example.com وlogin باسم المضيف والإجراء اللذين تستخدمهما الجهة المستهدفة. يقبل Site اسم مضيف دون مخطط أو مسار.

حلّ مهمة واحدة

احفظ هذا باسم main.go وشغّل go run ..

Go · الإنشاء مرة واحدة والاستعلام الدوري
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"
    solvethree "solvethree.com/sdk"
)

func main() {
    client, err := solvethree.NewClient(os.Getenv("SOLVETHREE_API_KEY"), nil)
    if err != nil { log.Fatal(err) }
    ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
    defer cancel()
    input := solvethree.TaskRequest{Site: "accounts.example.com", Action: "login", Proxy: os.Getenv("SOLVETHREE_PROXY")}
    result, err := client.Solve(ctx, input, solvethree.SolveOptions{})
    if err != nil { log.Fatal(err) }
    fmt.Println("Ready task:", result.ID)
    // Submit result.Solution.Token with its browser identity and original proxy.
}

يحدّد السياق مدة الانتظار المحلي بـ 180 ثانية. تُرجع Solve نتيجة TaskResult جاهزة أو خطأ؛ ولا تحتاج إلى حلقة استطلاع أخرى حولها. يستخدم هذا الطلب وضع Enterprise v3 الافتراضي. لاستخدام v3 العادي، اضبط RecaptchaType: "v3". اترك Type وURL دون تعيين عند استخدام reCAPTCHA.

أرسل الرمز إلى الجهة المستهدفة

أرسل result.Solution.Token في حقل CAPTCHA بالتطبيق. يحدّد result.ID المطبوع هوية المهمة؛ وليس الرمز.

استخدم result.Solution.UserAgent لقيمة User-Agent وresult.Solution.SecChUA لقيمة sec-ch-ua. وجّه الطلب المستهدف عبر الوكيل الذي نجح في الحل، والمحدّد باستخدام solvethree.SuccessfulProxy(input, result).

أدرج حقول النموذج الأخرى وملفات تعريف الارتباط وقيمة CSRF الخاصة بالتطبيق، ثم تحقّق من استجابته. تُرجع حزمة SDK حلًا؛ ولا ترسل طلب التطبيق نيابةً عنك.

احتفظ بالمعرّفات إذا انقطع الانتظار

يؤدي إلغاء السياق إلى إيقاف الانتظار المحلي، وليس العمل البعيد. يتيح *solvethree.Error الوصول إلى RequestID وTaskID. استرجع مهمة معروفة باستخدام GetTask؛ وإذا لم يكن إنشاء المهمة مؤكدًا، فأعد إرسال المدخلات الأصلية نفسها تمامًا باستخدام RequestID نفسه.

للاستعادة بعد إعادة تشغيل العملية، عيّن RequestID واحفظه مع مدخلات المهمة قبل إنشائها. يشير *TaskFailedError إلى فشل نهائي: افحص ErrorCode واسترجع المهمة للاطلاع على نص الخطأ. عالج السبب قبل بدء عملية حل أخرى.

بديل: استدعِ REST باستخدام المكتبة القياسية

إذا كنت تفضّل إدارة استدعاءات HTTP بنفسك، فإن هذه النسخة تستخدم net/http مباشرةً. اختر هذه النسخة أو مثال SDK أعلاه؛ فتشغيل كليهما ينشئ مهمتين. بُنى الاستجابة هنا خاصة بهذا المثال المستقل، لذا تختلف أسماء حقولها عن أنواع SDK.

Go 1.22+ · main.go
package main

import (
    "bytes"
    "context"
    "encoding/json"
    "fmt"
    "net/http"
    "net/url"
    "os"
    "time"
)

type Task struct {
    ID string `json:"id"`
    Status string `json:"status"`
    ErrorCode string `json:"errorCode"`
    Error string `json:"error"`
    Solution struct {
        Token string `json:"token"`
        UserAgent string `json:"userAgent"`
        SecChUa string `json:"secChUa"`
    } `json:"solution"`
}

func main() {
    key, proxy := os.Getenv("SOLVETHREE_API_KEY"), os.Getenv("SOLVETHREE_PROXY")
    if key == "" || proxy == "" { panic("Set SOLVETHREE_API_KEY and SOLVETHREE_PROXY") }
    ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
    defer cancel()
    client := &http.Client{Timeout: 30*time.Second}
    api := func(method, path string, body []byte) (Task, error) {
        var task Task
        req, err := http.NewRequestWithContext(ctx, method, "https://api.solvethree.com/v1"+path, bytes.NewReader(body))
        if err != nil { return task, err }
        req.Header.Set("Authorization", "Bearer "+key)
        req.Header.Set("Content-Type", "application/json")
        response, err := client.Do(req)
        if err != nil { return task, err }
        defer response.Body.Close()
        if response.StatusCode < 200 || response.StatusCode >= 300 { return task, fmt.Errorf("API HTTP %d", response.StatusCode) }
        err = json.NewDecoder(response.Body).Decode(&task)
        return task, err
    }
    requestID := fmt.Sprintf("go-%d", time.Now().UnixNano())
    body, err := json.Marshal(map[string]string{
        "site":"accounts.example.com", "action":"login", "proxy":proxy, "requestId":requestID,
    })
    if err != nil { panic(err) }
    // Persist requestID and body before creation if this must survive a restart.
    task, err := api(http.MethodPost, "/tasks?waitMs=0", body)
    if err != nil { panic(fmt.Errorf("request %s: %w", requestID, err)) }
    for task.Status == "pending" || task.Status == "solving" {
        task, err = api(http.MethodGet, "/tasks/"+url.PathEscape(task.ID)+"?waitMs=15000", nil)
        if err != nil { panic(err) }
        if task.Status == "pending" || task.Status == "solving" {
            select { case <-ctx.Done(): panic(ctx.Err()); case <-time.After(time.Second): }
        }
    }
    if task.Status != "ready" { panic("Task failed: "+task.ErrorCode+": "+task.Error) }
    solution := task.Solution
    _ = solution // Apply token and returned browser identity using the same proxy.
    fmt.Println("Ready task:", task.ID)
}

شغّل مهمتك الأولى.

ابدأ برصيد قدره $5 في مساحة العمل.

إنشاء مساحة عمل
حل reCAPTCHA Enterprise باستخدام Go · solvethree