From 3a826e3903bfea120b1b177e7746c0fd4b866605 Mon Sep 17 00:00:00 2001 From: Jan-Peter von Hunnius Date: Wed, 16 Oct 2024 11:24:12 +0200 Subject: [PATCH] Copied initial source --- Cargo.toml | 13 ++++ src/main.rs | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d2d73d2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "top_drives_db" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +scraper = "0.20.0" +reqwest = "0.12.7" +#ureq = { version = "2.6"} +#native-tls = { version = "0.2.12", features = [] } +#html_parser = "0.7.0" +tokio = { version = "1.40.0", features = ["full"] } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..6ba8f5f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,190 @@ +use scraper::{Html, Selector}; +use std::collections::HashSet; +use std::env; +use std::str::FromStr; +use tokio; + +struct Car { + class: String, + rq: u8, + manufacturer: String, + model: String, + year: u16, +// upgrade: String, +} +async fn get_page(url: &str) -> String { + match reqwest::Client::builder() + .danger_accept_invalid_certs(true) + .build() + .unwrap() + .get(url) + .send() + .await + { + Ok(response) => match response.text().await { + Ok(text) => text, + Err(error) => { + println!("Error getting content! Error: {}", error); + String::from("") + } + }, + Err(error) => { + println!("Error getting content! Error: {}", error); + String::from("") + } + } +} + +fn parse_best_car(text: String) -> Car { + let mut car = Car { + class: String::from("Z"), + rq: 0, + manufacturer: String::from(""), + model: String::from(""), + year: 1900, +// upgrade: String::from("000"), + }; + + let document = Html::parse_document(&text); + + let manufacturer_selector = Selector::parse(".carList__item-manufacturer").unwrap(); + car.manufacturer = String::from(match document.select(&manufacturer_selector).next() { + None => "", + Some(manufacturer) => manufacturer.text().collect::>()[0], + }); + + let model_selector = Selector::parse(".carList__item-model").unwrap(); + car.model = String::from(match document.select(&model_selector).next() { + None => "", + Some(model) => model.text().collect::>()[0], + }); + + let year_selector = Selector::parse(".carList__item-year").unwrap(); + car.year = u16::from_str(match document.select(&year_selector).next() { + None => "1900", + Some(year) => year.text().collect::>()[0], + }) + .unwrap(); + + let level_selector = Selector::parse(".carList__item-level").unwrap(); + let rq_raw = document + .select(&level_selector) + .next() + .unwrap() + .inner_html(); + let rq_fragment = Html::parse_document(rq_raw.trim()); + + let span_selector = Selector::parse("span").unwrap(); + let mut element_iterator = rq_fragment.select(&span_selector); + let class = String::from(match element_iterator.next() { + None => "Z", + Some(class) => class.text().collect::>()[0], + }); + car.class = class.to_uppercase(); + let rq = match element_iterator.next() { + None => "1900", + Some(rq) => rq.text().collect::>()[0], + }; + car.rq = u8::from_str(rq).unwrap(); +/* + let upgrade_selector = Selector::parse(".carList__item-upgrade ").unwrap(); + let upgrade_raw = match document.select(&upgrade_selector).next() { + None => "", + Some(model) => model.text().collect::>()[0], + }; + car.upgrade = String::from(upgrade_raw).trim().parse().unwrap(); +*/ + car +} + +#[tokio::main] +async fn main() { + let args: Vec<_> = env::args().collect(); + + let mut min_track = 4; + let mut max_track = 278; + + let min_rq = 10; + let mut max_rq = 113; + + match args.len() { + 1 => {} + 2 => max_rq = parse_argument(&args, 1, 10, 113), + 3 => { + max_rq = parse_argument(&args, 1, 10, 113); + min_track = parse_argument(&args, 2, 4, 278); + max_track = min_track; + } + 4 => { + max_rq = parse_argument(&args, 1, 10, 113); + min_track = parse_argument(&args, 2, 4, 278); + max_track = parse_argument(&args, 3, 4, 278); + if max_track < min_track { + let temp = min_track; + min_track = max_track; + max_track = temp + } + } + _ => panic!("Too many arguemnts."), + } + + let mut keepers: HashSet = HashSet::new(); + + for track in min_track..max_track + 1 { + let best_car = get_best_car(track, 10).await; + if best_car.len() > 10 { + for level in min_rq..max_rq + 1 { + let best_car = get_best_car(track, level).await; + if best_car.len() > 10 { +// println!("Best Car under RQ {} for track {}: {}", level, track, best_car); + keepers.insert(best_car); + } + } + } + } + + println!("Keepers:"); + for car in keepers { + println!("{}", car); + } +} + +fn parse_argument(args: &Vec, index: usize, min: u16, max: u16) -> u16 { + match args[index].parse::() { + Ok(parsed_value) => { + if parsed_value >= min && parsed_value <= max { + parsed_value + } else { + panic!( + "Argument {} is out of range. Please provide a value between {} and {}.", + index, min, max + ); + } + } + Err(_) => { + panic!("Argument {} could not be parsed. Please provide a positive integer value between {} and {}.", index, min, max) + } + } +} + +async fn get_best_car(track: u16, max_level: u16) -> String { + let url = format!("https://topdrives.club/ajax/load-best-vehicles?sort_by=level&sortorder=desc&prize=all&level=10%3B{}&acceleration=1%3B50&grip=40%3B110&year=1900%3B2030&seats_count=1%3B9&track={}&page=0", + max_level, track); + // println!("Getting {}", url); + let text = get_page(&url).await; + if text.len() > 10 { + let best_car = parse_best_car(text); + format!( +// "{}{} {} {} {} {}", + "{}{} {} {} {}", + best_car.class, + best_car.rq, + best_car.manufacturer, + best_car.model, + best_car.year, +// best_car.upgrade, + ) + } else { + String::from("") + } +}