This commit is contained in:
Robin Appelman 2023-11-15 21:05:11 +01:00
commit 0c58410f6a
11 changed files with 1902 additions and 0 deletions

4
src/data.rs Normal file
View file

@ -0,0 +1,4 @@
#[derive(Debug)]
pub struct Player {
pub name: String,
}

20
src/error.rs Normal file
View file

@ -0,0 +1,20 @@
use thiserror::Error;
use miette::Diagnostic;
#[derive(Debug, Error, Diagnostic)]
pub enum ScrapeError {
#[error("Failed to request data: {0:#}")]
Request(#[from] reqwest::Error),
#[error(transparent)]
#[diagnostic(transparent)]
Parse(#[from] ParseError)
}
#[derive(Debug, Error, Diagnostic)]
pub enum ParseError {
#[error("Couldn't find expected element '{selector}' for {role}")]
ElementNotFound {
selector: &'static str,
role: &'static str
}
}

18
src/main.rs Normal file
View file

@ -0,0 +1,18 @@
mod error;
mod parser;
pub mod data;
use main_error::MainResult;
use reqwest::get;
pub use error::*;
use crate::parser::{PlayerParser, Parser};
pub type Result<T, E = ScrapeError> = std::result::Result<T, E>;
#[tokio::main]
async fn main() -> MainResult {
let body = get("https://www.ugcleague.com/players_page.cfm?player_id=76561198024494988").await?.text().await?;
let parser = PlayerParser::new();
dbg!(parser.parse(&body)?);
Ok(())
}

10
src/parser/mod.rs Normal file
View file

@ -0,0 +1,10 @@
use crate::Result;
mod player;
pub use player::*;
pub trait Parser {
type Output;
fn parse(&self, document: &str) -> Result<Self::Output>;
}

35
src/parser/player.rs Normal file
View file

@ -0,0 +1,35 @@
use scraper::{Html, Selector};
use super::Parser;
use crate::{ParseError, Result};
use crate::data::Player;
const SELECTOR_PLAYER_NAME: &str = ".col-md-4 > h3 > b";
pub struct PlayerParser {
selector_name: Selector,
}
impl PlayerParser {
pub fn new() -> Self {
PlayerParser {
selector_name: Selector::parse(SELECTOR_PLAYER_NAME).unwrap(),
}
}
}
impl Parser for PlayerParser {
type Output = Player;
fn parse(&self, document: &str) -> Result<Self::Output> {
let document = Html::parse_document(&document);
let name = document.select(&self.selector_name).next().ok_or(ParseError::ElementNotFound {
selector: SELECTOR_PLAYER_NAME,
role: "player name",
})?.text().next().unwrap_or_default().to_string();
Ok(Player {
name
})
}
}