استخدام حزمة SDK لـ Go مع chromedp
نفّذ الحل أولًا، ثم شغّل Chrome باستخدام الوكيل نفسه وهوية المتصفح المُعادة. أدرج الرمز في نموذج التطبيق، وأرسله، وانتظر نتيجة التطبيق. تعني المهمة الجاهزة أن لديك حلًا، لا أن الموقع قد قبله.
في هذه الصفحة
إعداد الوحدات والملف التعريفي والوكيل
ثبّت solvethree.com/[email protected] وgithub.com/chromedp/[email protected] باستخدام go get. تتطلب حزمة SDK إصدار Go 1.22+، لكن هذا الإصدار من chromedp يتطلب Go 1.25+، لذا استخدمه للمثال الذي يجمع بينهما. تختلف واجهة API ذات الأنواع المحددة فيه عن أمثلة chromedp الأقدم.
أنشئ ملفًا تعريفيًا للموقع نشطًا لاسم المضيف المستهدف في مساحة عملك قبل تشغيل البرنامج. إرسال اسم مضيف وإجراء لا ينشئ ملفًا تعريفيًا.
TARGET_URL: عنوان URL الكامل عبر HTTPS للصفحة التي تحتوي على نموذجك. تستخدم المهمة اسم المضيف فيه بوصفهSite؛ وينتقل Chrome إلى عنوان URL الكامل.SOLVETHREE_PROXY: عنوان URL لوكيل HTTP أو HTTPS واحد. يتطلب هذا المثال وكيلًا يسمح بالوصول وفق قائمة بعناوين IP المسموح بها، دون بيانات اعتماد في عنوان URL.SOLVETHREE_API_KEY: مفتاح API لمساحة عملك. احتفظ به في عملية Go، لا في JavaScript الخاص بالصفحة.
يطلب المثال الإجراء login ويستخدم وضع reCAPTCHA الافتراضي Enterprise v3. غيّر الإجراء إلى القيمة التي يتوقعها تطبيقك.
الحل وتشغيل Chrome والإرسال
ينتظر البرنامج اكتمال الحل عبر حزمة SDK قبل إنشاء مُخصِّص Chrome. ويضبط Chrome لاستخدام الوكيل الواحد نفسه وresult.Solution.UserAgent، ثم يعيّن قيمة SecChUA المُعادة في الترويسة sec-ch-ua قبل الانتقال. لا تستبدل هوية المتصفح بأخرى غير مرتبطة بها، ولا تبدّل الوكلاء بين الحل والإرسال.
// go get github.com/chromedp/[email protected] (requires Go 1.25+)
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"time"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
solvethree "solvethree.com/sdk"
)
func main() { if err := run(); err != nil { log.Fatal(err) } }
func run() error {
target,err:=url.Parse(os.Getenv("TARGET_URL"));if err!=nil||target.Scheme!="https"||target.Hostname()=="" { return fmt.Errorf("set an HTTPS TARGET_URL") }
proxy,err:=url.Parse(os.Getenv("SOLVETHREE_PROXY"));if err!=nil||proxy.User!=nil { return fmt.Errorf("use an IP-allowlisted proxy without URL credentials") }
client,err:=solvethree.NewClient(os.Getenv("SOLVETHREE_API_KEY"),nil);if err!=nil { return err }
ctx,cancel:=context.WithTimeout(context.Background(),180*time.Second);defer cancel()
result,err:=client.Solve(ctx,solvethree.TaskRequest{Site:target.Hostname(),Action:"login",Proxy:proxy.String()},solvethree.SolveOptions{})
if err!=nil { return err }
options:=append(chromedp.DefaultExecAllocatorOptions[:],chromedp.ProxyServer(proxy.String()),chromedp.UserAgent(result.Solution.UserAgent))
allocator,closeAllocator:=chromedp.NewExecAllocator(context.Background(),options...);defer closeAllocator()
browser,closeBrowser:=chromedp.NewContext(allocator);defer closeBrowser()
browser,stop:=context.WithTimeout(browser,60*time.Second);defer stop()
tokenJSON,err:=json.Marshal(result.Solution.Token);if err!=nil { return err }
script:=`(token => {const field=document.querySelector('[name="g-recaptcha-response"]'); field.value=token; field.dispatchEvent(new Event('input',{bubbles:true}));})(`+string(tokenJSON)+`)`
_,err=chromedp.Call(browser,network.SetExtraHTTPHeaders,network.SetExtraHTTPHeadersParams{Headers:network.Headers{"sec-ch-ua":result.Solution.SecChUA}})
if err!=nil { return err }
err=chromedp.Do(browser,
chromedp.Navigate(target.String()),chromedp.WaitReady(chromedp.CSS(`[name="g-recaptcha-response"]`)),
chromedp.Evaluate[chromedp.Void](script),chromedp.Click(chromedp.CSS(`button[type="submit"]`)),
chromedp.WaitVisible(chromedp.ID("success")))
if err!=nil { return err }
// #success is this owned demo form's outcome. Adapt its selectors, token
// parameter and success check to your application, including CSRF/session fields.
return nil
}يستخدم هذا المثال وكيلًا واحدًا عمدًا، لذا لا حاجة إلى تحديد الوكيل المختار من بين المرشحين. إذا استخدمت ProxyCandidates لاحقًا، فاحصل على الوكيل الناجح باستخدام SuccessfulProxy(originalTask, readyResult) واستخدمه مع Chrome.
استبدال افتراضات النموذج التجريبي
تستخدم عملية إدراج الرمز json.Marshal قبل بناء تعبير JavaScript. احتفظ بخطوة الإفلات هذه: فهي تمرّر الرمز كقيمة نصية في JavaScript بدلًا من إدراج نص غير مُفلَت في شيفرة قابلة للتنفيذ.
- استبدل
[name="g-recaptcha-response"]بالحقل الذي يرسله تطبيقك فعليًا. يضبط المثال قيمته ويطلق حدث إدخال؛ عدّل ذلك إذا كان تطبيقك يحتاج إلى مسار إرسال مختلف. - استبدل
button[type="submit"]بعنصر الإرسال المقصود. أدرج أي قيم نموذج وحقول CSRF وحالة جلسة مطلوبة قبل النقر. - استبدل
#successبنتيجة تدل فعلًا على القبول في تطبيقك. اكتمال النقر أو امتلاء حقل الرمز لا يمثل تلك النتيجة.
لا ترسل حزمة SDK الرمز إلى الموقع المستهدف. إذا رفض الموقع الطلب، فافحص النموذج الصادر أولًا: تأكد من أنه يحتوي على result.Solution.Token، لا معرّف المهمة أو قيمة أقدم للحقل، وتحقق من استمرار تطابق الوكيل وهوية المتصفح.
التعامل مع المهل الزمنية دون إنشاء عمليات حل مكررة
لعملية الحل مهلة سياق قدرها 180 ثانية. ويحصل Chrome على مهلة منفصلة قدرها 60 ثانية بعد الحل. تُرجع الدالة run الأخطاء كي يُنفَّذ إلغاء السياق المؤجل وتنظيف موارد المتصفح قبل أن تسجّل main الخطأ.
إلغاء سياق الحل يوقف الانتظار، لا العمل البعيد. تنشئ حزمة SDK المهمة مرة واحدة، وتعيد المحاولة فقط عند حدوث إخفاقات مؤقتة في الاستطلاع؛ ولا تعيد أبدًا محاولة طلب POST الخاص بالإنشاء. لذا فإن انتهاء المهلة ليس سببًا لإرسال مهمة جديدة فورًا.
- عند الإلغاء أو انتهاء المهلة، استخدم
errors.Isلتحديد خطأ السياق. استخرج*solvethree.Errorباستخدامerrors.Asواحتفظ بقيمتيTaskIDوRequestIDفيه. - إذا كان لديك معرّف مهمة، فاسترجعها باستخدام
GetTask. وإلا، فاستعدها بإعادة إرسال مدخلات المهمة الأصلية نفسها تمامًا باستخدام معرّف الطلب نفسه. الاستدعاء مجددًا دون ذلك المعرّف ينشئ طلبًا منطقيًا جديدًا؛ أما تغيير المدخلات مع إعادة استخدامه فيؤدي إلى تعارض. - بالنسبة إلى
*TaskFailedError، افحصErrorCodeواسترجع المهمة الفاشلة للاطلاع على نص الخطأ فيها. هذه المهمة في حالة نهائية: أوقف استطلاعها وأصلح السبب بدلًا من إعادة المحاولة بمدخلات لم تتغير. - عند حدوث خطأ HTTP في API، استخرج
*APIErrorالمتداخل لفحصStatusCodeوRetryAfter. لا تخلط بين فشل HTTP ومهمة فاشلة في حالة نهائية.
المصادر ومرجع API
شغّل مهمتك الأولى.
ابدأ برصيد قدره $5 في مساحة العمل.