1#[derive(Debug, Clone)]
2pub struct CaptchaInfo {
3 pub captcha_type: String,
4 pub sitekey: String,
5}
6
7pub async fn detect_captcha_on_page(page: &crate::eoka::Page) -> Option<CaptchaInfo> {
8 let hcaptcha_script = r#"
9 (() => document.querySelector('[data-sitekey]')?.getAttribute('data-sitekey') || null)()
10 "#;
11 if let Ok(result) = page.evaluate::<serde_json::Value>(hcaptcha_script).await {
12 if let Some(sitekey) = result.as_str().filter(|key| !key.is_empty()) {
13 return Some(CaptchaInfo {
14 captcha_type: "hcaptcha".into(),
15 sitekey: sitekey.into(),
16 });
17 }
18 }
19
20 let recaptcha_script = r#"
21 (() => {
22 if (![...document.scripts].some(s => s.src.includes('recaptcha'))) return null;
23 return document.documentElement.innerHTML.match(/"sitekey"\s*:\s*"([^"]+)"/)?.[1] || null;
24 })()
25 "#;
26 if let Ok(result) = page.evaluate::<serde_json::Value>(recaptcha_script).await {
27 if let Some(sitekey) = result.as_str().filter(|key| !key.is_empty()) {
28 return Some(CaptchaInfo {
29 captcha_type: "recaptcha".into(),
30 sitekey: sitekey.into(),
31 });
32 }
33 }
34 None
35}