stealthscraper_rs/
solver.rs1#![cfg(feature = "browser")]
2use crate::Error;
6use crate::scraper::CloudScraper;
7use headless_chrome::Tab;
8use std::sync::Arc;
9use std::time::Duration;
10
11pub struct GenericSolver;
16
17impl GenericSolver {
18 pub fn solve_cloudflare_turnstile(tab: &Arc<Tab>) -> Result<(), Error> {
21 let challenge_selectors = vec![
24 ".cf-turnstile",
25 "#challenge-stage",
26 "input[type='checkbox']",
27 ];
28
29 for selector in challenge_selectors {
30 if let Ok(element) = tab.wait_for_element(selector) {
31 let box_model = element
33 .get_box_model()
34 .map_err(|e| Error::BrowserError(format!("Box model failed: {}", e)))?;
35 let center_x = box_model.content.most_left();
36 let center_y = box_model.content.most_top();
37
38 CloudScraper::human_move_mouse(tab, center_x, center_y)?;
40
41 std::thread::sleep(Duration::from_millis(150));
43
44 tab.click_point(headless_chrome::browser::tab::point::Point {
46 x: center_x,
47 y: center_y,
48 })
49 .map_err(|e| Error::InteractionError(format!("Click failed: {}", e)))?;
50
51 std::thread::sleep(Duration::from_secs(3));
53 return Ok(());
54 }
55 }
56
57 Err(Error::InteractionError(
58 "Could not find a challenge element to solve".to_string(),
59 ))
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use headless_chrome::Browser;
67
68 #[cfg(feature = "browser")]
69 #[test]
70 fn test_solve_cloudflare_turnstile_not_found() {
71 let browser = Browser::default().expect("Expected to get a browser");
73 let tab = browser.new_tab().expect("Expected to get a tab");
74
75 let result = GenericSolver::solve_cloudflare_turnstile(&tab);
76 assert!(result.is_err());
77 }
78
79 #[cfg(feature = "browser")]
80 #[test]
81 fn test_solve_cloudflare_turnstile_success() {
82 let browser = Browser::default().expect("Failed to launch");
83 let tab = browser.new_tab().expect("Failed to create tab");
84
85 let html_content = "<html><body><div class='cf-turnstile' style='width: 300px; height: 65px;'></div></body></html>";
87 let file_path = std::env::temp_dir().join("test_solver.html");
88 std::fs::write(&file_path, html_content).expect("Failed to write mock HTML");
89 let file_url = format!("file://{}", file_path.display());
90
91 tab.navigate_to(&file_url).expect("Failed to navigate");
92 tab.wait_until_navigated().expect("Failed to wait");
93
94 let result = GenericSolver::solve_cloudflare_turnstile(&tab);
95 assert!(result.is_ok());
96 }
97}