Rust ile reCAPTCHA Enterprise çözün
Rust'tan solvethree REST API'sini kullanın: bir görev oluşturun, hazır olana kadar sorgulayın, ardından döndürülen tarayıcı kimliği ve aynı proxy ile solution.token değerini hedefe gönderin. Aşağıdaki örnek resmi bir Rust SDK'sı değil; doğrudan reqwest, Tokio ve serde_json kullanır.
Bu sayfada
Siteyi ve isteği yapılandırın
Önce çalışma alanınızın konsolunda hedef ana makine adı için etkin bir profil oluşturun. Ana makine adı ve eylem göndermek profil oluşturmaz. Hedef henüz yapılandırılmadıysa site profili kurulumuna bakın.
Rust istemcisinin çalışacağı sunucuda şu ortam değişkenlerini ayarlayın:
SOLVETHREE_API_KEY: çalışma alanınızın API anahtarı. Sunucu tarafında tutun.SOLVETHREE_PROXY: çözüm işlemi ve ardından yapılacak hedef isteği için proxy URL'si.REQUEST_ID: bu mantıksal görev için isteğe bağlı, sabit bir kimlik. Bağlantı kesintisinden sonra kurtarma yapabilmek için isteği göndermeden önce kaydedin.
| Alan | Gönderilecek değer |
|---|---|
site | Hedef ana makine adı. Örnekteki accounts.example.com değerini değiştirin. |
action | Hedefin beklediği eylem. Gerekirse login değerini değiştirin. |
proxy | SOLVETHREE_PROXY değişkeninden okunan tek proxy URL'si. |
requestId | 1–64 ASCII harfi, rakam, alt çizgi veya kısa çizgi içeren bir idempotans anahtarı. |
recaptchaType | Varsayılan değeri enterprise-v3 olduğu için burada belirtilmemiştir. |
Bu reCAPTCHA isteğine type veya url alanları eklemeyin. proxy veya proxyCandidates alanlarından tam olarak biri gereklidir; örnek, hedefe aktarımda aynı bağlantının kullanılabilmesi için proxy kullanır.
Rust istemcisini oluşturun
Bir Cargo ikili uygulama projesinde bağımlılık dosyasını Cargo.toml, istemciyi ise src/main.rs içine yerleştirin. Ortam değişkenlerini ayarlayıp hedef ana makine adını ve eylemi değiştirdikten sonra projeyi Cargo ile çalıştırın. Bağımlılıklar reqwest'i 0.13.5 sürümüne sabitler.
[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())
}
}
}İstemci, Bearer token ile kimlik doğrulayarak POST /v1/tasks adresine tek bir oluşturma isteği yapar. Döndürülen görev kimliğini saklar ve sonraki durum istekleri için GET /v1/tasks/:id kullanır.
İki sınır, istemcinin süresiz beklemesini önler: reqwest'in zaman aşımı her HTTP isteğini 30 saniyeyle sınırlar, Tokio'nun zaman aşımı ise oluşturma ve sorgulamayı birlikte 180 saniyeyle sınırlar. Bunlar istemci tarafındaki tercihlerdir, hizmetin tamamlanma garantileri değildir. Yönlendirmeler reqwest'in ClientBuilder'ı üzerinden devre dışı bırakılır.
Yalnızca pending ve solving durumları sorgulama döngüsünü sürdürür. ready sonucu döndürür, failed bir hatayla durur; beklenmeyen bir durum da sonsuza dek sorgulamak yerine işlemi durdurur. Başarılı akış token'ı değil, görev kimliğini yazdırır.
Yeni bir çözüm başlatmadan kesintiye uğrayan isteği kurtarın
Örnek, requestId değerini ve döndürülen görev kimliğini bellekte tutar; HTTP, aktarım, ayrıştırma veya süre aşımı hatası oluştuğunda bunları yazdırır. Süreç sonlandığında bunları kalıcı olarak saklamaz. Yeniden başlatma sonrası kurtarma için oluşturmadan önce istek kimliğini ve özgün görev girdilerini, ardından görev kimliğini gelir gelmez kaydedin.
- 1.
Görev kimliğiniz varsa o görevi alın
Başka bir görev oluşturmak yerine GET /v1/tasks/:id ile devam edin. Örneğin normal giriş noktası her zaman görev oluşturur; yeniden başlatma akışı kayıtlı kimliği kullanmalıdır.
- 2.
Yalnızca istek kimliğiniz varsa oluşturma işlemini kurtarın
Aynı görev isteğini aynı requestId ile gönderin. Bu, mevcut görevi döndürür. Kimliği yeniden kullanırken girdileri değiştirmek çakışmaya neden olur.
- 3.
Kurtarılan görevin durumunu işleyin
pending veya solving durumundaki görevleri sorgulamaya devam edin. ready durumundaki çözümü kullanın veya failed durumunda durup errorCode ve error alanlarını inceleyin. Yerel bir zaman aşımı tek başına uzaktaki görevin başarısız olduğunu göstermez.
HTTP hataları ve görev hataları farklı şekilde işlenmelidir. İstemci, başarılı sonuç verisini ayrıştırmadan önce başarısız HTTP yanıtlarını kontrol eder. Nihai görev hatası ise failed görev durumu olarak gelir; başarısız çözümlerin ücreti iade edilir. Örneğin hata mesajı yalnızca errorCode içerir; bu nedenle sorunun nedenini araştırırken görev yanıtındaki error alanını da inceleyin. Değiştirilmemiş girdilerle yeniden denemeden önce API hata işlemeye bakın.
Token'ı tarayıcı kimliğiyle gönderin
Örnek, görev hazır olduğunda durur; uygulama isteğini hedefe göndermez. Bu istek için görev kimliği değil, solution.token gerekir. Döndürülen userAgent ve secChUa kimliğini özgün proxy üzerinden kullanın ve başka bir tarayıcı oturumundan değerleri karıştırmak yerine amaçlanan hedefe gönderin.
Hazır bir görev, bir çözüm üretildiği anlamına gelir; hedefin uygulama isteğinizi kabul ettiği anlamına gelmez. Hedefe özgü gönderimi, başarılı akışta işaretlenmiş yorumun bulunduğu yere ekleyin; token aktarımıyla ilgili bilgi için reCAPTCHA Enterprise entegrasyon kılavuzuna bakın.
Kaynaklar ve API referansı
İlk görevinizi çalıştırın.
$5 çalışma alanı kredisiyle başlayın.