add transactions

This commit is contained in:
Robin Appelman 2023-11-19 15:04:09 +01:00
commit bd2cd8afe6
9 changed files with 2907 additions and 32 deletions

View file

@ -12,6 +12,7 @@ mod team;
mod team_lookup;
mod team_matches;
mod team_roster_history;
mod transactions;
pub use match_page::*;
pub use player::*;
@ -21,6 +22,7 @@ pub use team::*;
pub use team_lookup::*;
pub use team_matches::*;
pub use team_roster_history::*;
pub use transactions::*;
pub trait Parser {
type Output;
@ -28,8 +30,9 @@ pub trait Parser {
}
trait ElementExt<'a> {
fn first_text(&'a self) -> Option<&'a str>;
fn nth_text(&'a self, n: usize) -> Option<&'a str>;
fn first_text(&self) -> Option<&'a str>;
fn nth_text(&self, n: usize) -> Option<&'a str>;
fn last_text(&self) -> Option<&'a str>;
}
impl<'a> ElementExt<'a> for ElementRef<'a> {
@ -42,6 +45,9 @@ impl<'a> ElementExt<'a> for ElementRef<'a> {
.nth(n - 1)
.map(str::trim)
}
fn last_text(&self) -> Option<&'a str> {
self.text().map(str::trim).filter(|s| !s.is_empty()).last()
}
}
fn select_text<'a>(el: ElementRef<'a>, selector: &Selector) -> Option<&'a str> {

View file

@ -0,0 +1,96 @@
use super::Parser;
use crate::data::{TeamRef, Transaction};
use crate::parser::{
select_last_text, select_text, steam_id_from_link, team_id_from_link, ElementExt,
};
use crate::{ParseError, Result};
use scraper::{Html, Selector};
const SELECTOR_TRANSACTION_ROW: &str = "table.table.table-condensed.table-striped tr";
const SELECTOR_TRANSACTION_PLAYER_LINK: &str = "a[href^=\"players_page\"][title^=\"Roster\"]";
const SELECTOR_TRANSACTION_ACTION: &str = "td:nth-child(4) span b";
const SELECTOR_TRANSACTION_TEAM_LINK: &str = "a[href^=\"team_page\"]";
const SELECTOR_TRANSACTION_TEAM_NAME: &str = "td:nth-child(5)";
pub struct TransactionParser {
selector_row: Selector,
selector_player: Selector,
selector_action: Selector,
selector_team_link: Selector,
selector_team_name: Selector,
}
impl Default for TransactionParser {
fn default() -> Self {
Self::new()
}
}
impl TransactionParser {
pub fn new() -> Self {
TransactionParser {
selector_row: Selector::parse(SELECTOR_TRANSACTION_ROW).unwrap(),
selector_player: Selector::parse(SELECTOR_TRANSACTION_PLAYER_LINK).unwrap(),
selector_action: Selector::parse(SELECTOR_TRANSACTION_ACTION).unwrap(),
selector_team_link: Selector::parse(SELECTOR_TRANSACTION_TEAM_LINK).unwrap(),
selector_team_name: Selector::parse(SELECTOR_TRANSACTION_TEAM_NAME).unwrap(),
}
}
}
impl Parser for TransactionParser {
type Output = Vec<Transaction>;
fn parse(&self, document: &str) -> Result<Self::Output> {
let document = Html::parse_document(document);
document
.select(&self.selector_row)
.filter(|row| row.select(&self.selector_player).next().is_some())
.map(|row| {
let player_link = row.select(&self.selector_player).next().ok_or(
ParseError::ElementNotFound {
selector: SELECTOR_TRANSACTION_PLAYER_LINK,
role: "player link",
},
)?;
let name = player_link.first_text().ok_or(ParseError::EmptyText {
selector: SELECTOR_TRANSACTION_PLAYER_LINK,
role: "player name",
})?;
let steam_id = steam_id_from_link(player_link.attr("href").unwrap_or_default())?;
let action = select_text(row, &self.selector_action)
.ok_or(ParseError::ElementNotFound {
selector: SELECTOR_TRANSACTION_ACTION,
role: "transaction action",
})?
.parse()?;
let team_link = row.select(&self.selector_team_link).next().ok_or(
ParseError::ElementNotFound {
selector: SELECTOR_TRANSACTION_TEAM_LINK,
role: "team link",
},
)?;
let team_id = team_id_from_link(team_link.attr("href").unwrap_or_default())?;
let team_name = select_last_text(row, &self.selector_team_name).ok_or(
ParseError::EmptyText {
selector: SELECTOR_TRANSACTION_TEAM_LINK,
role: "team link",
},
)?;
Ok(Transaction {
name: name.to_string(),
steam_id,
action,
team: TeamRef {
id: team_id,
name: team_name.to_string(),
},
})
})
.collect()
}
}