Rust से reCAPTCHA Enterprise हल करें
Rust से solvethree के REST API का उपयोग करें: टास्क बनाएँ, तैयार होने तक पोल करें, फिर लौटाई गई ब्राउज़र पहचान और उसी प्रॉक्सी का उपयोग करके लक्ष्य को solution.token सबमिट करें। नीचे दिया उदाहरण सीधे reqwest, Tokio और serde_json का उपयोग करता है—किसी आधिकारिक Rust SDK का नहीं।
इस पेज पर
साइट और अनुरोध कॉन्फ़िगर करें
पहले अपने वर्कस्पेस के कंसोल में लक्ष्य होस्टनाम के लिए सक्रिय प्रोफ़ाइल बनाएँ। होस्टनाम और ऐक्शन भेजने से प्रोफ़ाइल नहीं बनती। लक्ष्य अभी कॉन्फ़िगर नहीं है तो साइट प्रोफ़ाइल सेटअप देखें।
जिस सर्वर पर Rust क्लाइंट चलेगा, वहाँ ये एनवायरनमेंट वेरिएबल सेट करें:
SOLVETHREE_API_KEY: आपके वर्कस्पेस की API कुंजी। इसे सर्वर पर ही रखें।SOLVETHREE_PROXY: समाधान और उसके बाद लक्ष्य अनुरोध के लिए प्रॉक्सी URL।REQUEST_ID: इस तार्किक टास्क के लिए वैकल्पिक, स्थिर ID। अनुरोध भेजने से पहले इसे सहेजें, ताकि कनेक्शन बाधित होने के बाद आप रिकवरी कर सकें।
| फ़ील्ड | क्या भेजें |
|---|---|
site | लक्ष्य होस्टनाम। उदाहरण में accounts.example.com को बदलें। |
action | लक्ष्य द्वारा अपेक्षित ऐक्शन। आवश्यकता हो तो login बदलें। |
proxy | SOLVETHREE_PROXY से पढ़ा गया एकल प्रॉक्सी URL। |
requestId | 1–64 ASCII अक्षर, अंक, अंडरस्कोर या हाइफ़न वाली आइडेम्पोटेंसी कुंजी। |
recaptchaType | यहाँ छोड़ा गया है क्योंकि इसका डिफ़ॉल्ट enterprise-v3 है। |
इस reCAPTCHA अनुरोध में type या url फ़ील्ड न जोड़ें। proxy या proxyCandidates में से ठीक एक आवश्यक है; उदाहरण proxy का उपयोग करता है ताकि लक्ष्य को भेजते समय उसी कनेक्शन का उपयोग किया जा सके।
Rust क्लाइंट बनाएँ
Cargo बाइनरी प्रोजेक्ट में डिपेंडेंसी फ़ाइल Cargo.toml में और क्लाइंट src/main.rs में रखें। एनवायरनमेंट वेरिएबल सेट करने और लक्ष्य होस्टनाम व ऐक्शन बदलने के बाद प्रोजेक्ट को Cargo से चलाएँ। डिपेंडेंसी reqwest को संस्करण 0.13.5 पर पिन करती हैं।
[package]
name = "solvethree-example"
version = "0.1.0"
edition = "2021"
[dependencies]
reqwest = { version = "=0.13.5", features = ["json"] }
serde_json = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }use std::{env, error::Error, time::{Duration, SystemTime, UNIX_EPOCH}};
use reqwest::{Client, redirect::Policy};
use serde_json::{json, Value};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let api = "https://api.solvethree.com/v1";
let key = env::var("SOLVETHREE_API_KEY")?;
let request_id = env::var("REQUEST_ID").unwrap_or_else(|_| format!("rust-{}", SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_nanos()));
let input = json!({"site":"accounts.example.com", "action":"login", "proxy":env::var("SOLVETHREE_PROXY")?, "requestId":request_id});
let client = Client::builder().redirect(Policy::none()).timeout(Duration::from_secs(30)).build()?;
let mut task_id: Option<String> = None;
let outcome = tokio::time::timeout(Duration::from_secs(180), async {
let response = client.post(format!("{api}/tasks?waitMs=0")).bearer_auth(&key).json(&input).send().await?;
if !response.status().is_success() { return Err(format!("API HTTP {}", response.status()).into()); }
let mut result: Value = response.json().await?;
let id = result["id"].as_str().ok_or("Missing task ID")?.to_owned();
if !id.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_' || b == b'-') { return Err("Invalid task ID".into()); }
task_id = Some(id.clone());
loop {
match result["status"].as_str() {
Some("ready") => return Ok::<Value, Box<dyn Error>>(result),
Some("failed") => return Err(format!("Task failed: {}", result["errorCode"]).into()),
Some("pending") | Some("solving") => {},
_ => return Err("Unexpected task status".into()),
}
tokio::time::sleep(Duration::from_secs(1)).await;
let response = client.get(format!("{api}/tasks/{id}?waitMs=15000")).bearer_auth(&key).send().await?;
if !response.status().is_success() { return Err(format!("API HTTP {}", response.status()).into()); }
result = response.json().await?;
}
}).await;
match outcome {
Ok(Ok(result)) => {
println!("Ready task: {}", result["id"].as_str().unwrap_or("unknown"));
// Submit result["solution"]["token"] with returned browser headers
// through the original proxy; do not log the solution.
Ok(())
},
Ok(Err(error)) => {
eprintln!("Recovery requestId={request_id} taskId={task_id:?}");
Err(error)
},
Err(_) => {
eprintln!("Recovery requestId={request_id} taskId={task_id:?}");
Err("Local deadline reached; recover the existing task".into())
}
}
}क्लाइंट Bearer टोकन से प्रमाणीकरण करते हुए POST /v1/tasks पर निर्माण का एक अनुरोध भेजता है। यह लौटाई गई टास्क ID सुरक्षित रखता है और आगे के स्टेटस अनुरोधों के लिए GET /v1/tasks/:id का उपयोग करता है।
दो सीमाएँ क्लाइंट को अनिश्चित समय तक प्रतीक्षा करने से रोकती हैं: reqwest का टाइमआउट हर HTTP अनुरोध को 30 सेकंड तक सीमित करता है, जबकि Tokio का टाइमआउट निर्माण और पोलिंग को मिलाकर 180 सेकंड तक सीमित करता है। ये क्लाइंट-साइड विकल्प हैं, सेवा पूरी होने की गारंटी नहीं। रीडायरेक्ट reqwest के ClientBuilder के ज़रिए बंद किए गए हैं।
केवल pending और solving पर पोलिंग लूप जारी रहता है। ready परिणाम लौटाता है, failed त्रुटि के साथ रुकता है और अप्रत्याशित स्टेटस पर भी अनंत पोलिंग करने के बजाय प्रक्रिया रुक जाती है। सफलता का पथ टास्क ID प्रिंट करता है, टोकन नहीं।
दोबारा समाधान शुरू किए बिना बाधित अनुरोध की रिकवरी करें
उदाहरण requestId और लौटाई गई टास्क ID को मेमोरी में रखता है और HTTP, ट्रांसपोर्ट, पार्सिंग या समय-सीमा की त्रुटि होने पर उन्हें प्रिंट करता है। प्रोसेस समाप्त होने के बाद ये स्थायी रूप से सुरक्षित नहीं रहते। रीस्टार्ट के बाद रिकवरी के लिए, निर्माण से पहले अनुरोध ID और मूल टास्क इनपुट स्टोर करें, फिर टास्क ID मिलते ही उसे स्टोर करें।
- 1.
यदि आपके पास टास्क ID है, तो वह टास्क प्राप्त करें
दूसरा टास्क बनाने के बजाय GET /v1/tasks/:id से फिर शुरू करें। नमूने का सामान्य एंट्री पॉइंट हमेशा टास्क बनाता है; रीस्टार्ट पथ को सहेजी गई ID का उपयोग करना चाहिए।
- 2.
केवल अनुरोध ID हो तो निर्माण की रिकवरी करें
उसी requestId के साथ वही टास्क अनुरोध सबमिट करें। इससे मौजूदा टास्क लौटता है। ID का दोबारा उपयोग करते हुए इनपुट बदलने पर टकराव होता है।
- 3.
रिकवरी के बाद मिले स्टेटस को सँभालें
pending या solving टास्क को पोल करते रहें। ready समाधान का उपयोग करें, या failed पर रुककर errorCode और error की जाँच करें। केवल स्थानीय टाइमआउट से यह सिद्ध नहीं होता कि रिमोट टास्क विफल हुआ।
HTTP विफलताओं और टास्क विफलताओं को अलग-अलग सँभालना ज़रूरी है। क्लाइंट सफलता पेलोड पार्स करने से पहले असफल HTTP प्रतिक्रियाओं की जाँच करता है। इसके विपरीत, टास्क की अंतिम विफलता टास्क स्टेटस failed के रूप में आती है; विफल समाधानों का शुल्क वापस किया जाता है। नमूने के विफलता संदेश में केवल errorCode शामिल है, इसलिए निदान करते समय टास्क प्रतिक्रिया में error भी जाँचें। उन्हीं इनपुट के साथ दोबारा प्रयास करने से पहले API त्रुटि हैंडलिंग देखें।
टोकन को उसकी ब्राउज़र पहचान के साथ सबमिट करें
उदाहरण टास्क तैयार होने पर रुक जाता है; यह लक्ष्य को एप्लिकेशन अनुरोध नहीं भेजता। उस अनुरोध को solution.token चाहिए, टास्क ID नहीं। मूल प्रॉक्सी के ज़रिए लौटाई गई userAgent और secChUa पहचान का उपयोग करें और किसी दूसरे ब्राउज़र सेशन के मान मिलाने के बजाय निर्धारित लक्ष्य को सबमिट करें।
तैयार टास्क का मतलब है कि समाधान बन गया है, यह नहीं कि लक्ष्य ने आपका एप्लिकेशन अनुरोध स्वीकार कर लिया है। सफलता-पथ की चिह्नित टिप्पणी पर लक्ष्य-विशिष्ट सबमिशन जोड़ें; टोकन हैंडऑफ़ के मार्गदर्शन के लिए reCAPTCHA Enterprise एकीकरण गाइड देखें।
स्रोत और API संदर्भ
अपना पहला टास्क चलाएँ।
$5 वर्कस्पेस क्रेडिट के साथ शुरुआत करें।