准备工作
安装Rust和相关库
首先,你需要安装Rust。如果你还没有安装,可以访问Rust官网进行安装。
接下来,我们需要安装Selenium的Rust客户端库fantoccini和OpenCV的Rust绑定库opencv.
在终端中运行以下命令安装依赖:
sh
cargo new yidun_crack
cd yidun_crack
cargo add fantoccini
cargo add opencv
验证码页面
验证码页面地址:https://dun.163.com/trial/jigsaw
代码实现
1. 初始化Selenium
我们首先启动Selenium WebDriver并导航到验证码页面。
rust
use fantoccini::{Client, Locator};
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = Client::new("http://localhost:4444").await?;
// 打开目标网页
client.goto("https://dun.163.com/trial/jigsaw").await?;
// 延迟加载以确保页面加载完全
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
// 后续的验证码处理代码将放在这里
client.close().await?;
Ok(())
}
2. 获取验证码图片
获取验证码图片并保存到本地,以便使用OpenCV进行图像处理。
rust
use fantoccini::Client;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use reqwest;
async fn get_image(client: &Client, selector: &str, file_path: &str) -> Result<(), Box<dyn Error>> {
let elem = client.find(Locator::Css(selector)).await?;
let img_url = elem.attr("src").await?.ok_or("No src attribute")?;
let response = reqwest::get(&img_url).await?;
let bytes = response.bytes().await?;
let mut file = File::create(file_path)?;
file.write_all(&bytes)?;
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = Client::new("http://localhost:4444").await?;
client.goto("https://dun.163.com/trial/jigsaw").await?;
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
get_image(&client, ".yidun_bg-img", "bg.png").await?;
get_image(&client, ".yidun_jigsaw", "puzzle.png").await?;
// 后续的验证码处理代码将放在这里
client.close().await?;
Ok(())
}
3. 使用OpenCV匹配图像
使用OpenCV找到拼图缺口的位置。
rust
use opencv::core::{Point, Rect, Scalar, Size, CV_8UC1};
use opencv::imgcodecs::{imread, imwrite, IMREAD_COLOR, IMREAD_GRAYSCALE};
use opencv::imgproc::{cvt_color, match_template, tm_sqdiff_normed};
use opencv::prelude::*;
fn get_slide_distance(bg_path: &str, puzzle_path: &str) -> Result<f64, Box<dyn Error>> {
let bg_img = imread(bg_path, IMREAD_COLOR)?;
let puzzle_img = imread(puzzle_path, IMREAD_COLOR)?;
let mut result = Mat::default()?;
let result_cols = bg_img.cols() - puzzle_img.cols() + 1;
let result_rows = bg_img.rows() - puzzle_img.rows() + 1;
let size = Size::new(result_cols, result_rows);
result.create(size, CV_8UC1)?;
match_template(&bg_img, &puzzle_img, &mut result, tm_sqdiff_normed, &Mat::default())?;
let min_max_loc = opencv::core::min_max_loc(&result, None, None, None, None)?;
Ok(min_max_loc.min_loc.x as f64)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = Client::new("http://localhost:4444").await?;
client.goto("https://dun.163.com/trial/jigsaw").await?;
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
get_image(&client, ".yidun_bg-img", "bg.png").await?;
get_image(&client, ".yidun_jigsaw", "puzzle.png").await?;
let distance = get_slide_distance("bg.png", "puzzle.png")?;
println!("Slide distance: {}", distance);
// 后续的验证码处理代码将放在这里
client.close().await?;
Ok(())
}
4. 模拟滑动行为
模拟人类滑动行为,以避免被检测为机器人。
rust
use rand::Rng;
use std::time::Duration;
async fn slide_puzzle(client: &Client, distance: f64) -> Result<(), Box<dyn Error>> {
let slider = client.find(Locator::Css(".yidun_slider")).await?;
let rect = slider.rect().await?;
let start_x = rect.x + rect.width / 2;
let start_y = rect.y + rect.height / 2;
client.mouse_move_to_location(Some((start_x as f64, start_y as f64))).await?;
client.mouse_down().await?;
let steps = 30;
let move_x = distance / steps as f64;
let mut rng = rand::thread_rng();
for i in 0..steps {
let current_x = start_x as f64 + move_x * i as f64;
client.mouse_move_to_location(Some((current_x, start_y as f64))).await?;
tokio::time::sleep(Duration::from_millis(100 + rng.gen_range(0..50))).await;
}
client.mouse_up().await?;
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {更多内容联系1436423940
let client = Client::new("http://localhost:4444").await?;
client.goto("https://dun.163.com/trial/jigsaw").await?;
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
get_image(&client, ".yidun_bg-img", "bg.png").await?;
get_image(&client, ".yidun_jigsaw", "puzzle.png").await?;
let distance = get_slide_distance("bg.png", "puzzle.png")?;
println!("Slide distance: {}", distance);
slide_puzzle(&client, distance).await?;
tokio::time::sleep(Duration::from_secs(5)).await;
client.close().await?;
Ok(())
}