mirror of
https://codeberg.org/icewind/ugc-scaper.git
synced 2026-06-03 18:24:10 +02:00
historical seasons
This commit is contained in:
parent
43bfba6307
commit
e20a9cdae9
8 changed files with 3064 additions and 3 deletions
14
src/data.rs
14
src/data.rs
|
|
@ -173,3 +173,17 @@ pub enum MatchResult {
|
|||
},
|
||||
ByeWeek,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
pub struct Seasons {
|
||||
pub mode: String,
|
||||
pub seasons: Vec<Season>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
pub struct Season {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
|
|
|||
18
src/lib.rs
18
src/lib.rs
|
|
@ -3,9 +3,9 @@ mod error;
|
|||
#[doc(hidden)]
|
||||
pub mod parser;
|
||||
|
||||
use crate::data::{MembershipHistory, Player, RosterHistory, Team, TeamSeason};
|
||||
use crate::data::{MembershipHistory, Player, RosterHistory, Seasons, Team, TeamSeason};
|
||||
use crate::parser::{
|
||||
Parser, PlayerDetailsParser, PlayerParser, TeamMatchesParser, TeamParser,
|
||||
Parser, PlayerDetailsParser, PlayerParser, SeasonsParser, TeamMatchesParser, TeamParser,
|
||||
TeamRosterHistoryParser,
|
||||
};
|
||||
pub use error::*;
|
||||
|
|
@ -23,6 +23,7 @@ pub struct UgcClient {
|
|||
team_parser: TeamParser,
|
||||
team_roster_history_parser: TeamRosterHistoryParser,
|
||||
team_matches_parser: TeamMatchesParser,
|
||||
seasons_parser: SeasonsParser,
|
||||
}
|
||||
|
||||
/// "API client" for ugc by scraping the website
|
||||
|
|
@ -35,6 +36,7 @@ impl UgcClient {
|
|||
team_parser: TeamParser::new(),
|
||||
team_roster_history_parser: TeamRosterHistoryParser::new(),
|
||||
team_matches_parser: TeamMatchesParser::new(),
|
||||
seasons_parser: SeasonsParser::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,4 +118,16 @@ impl UgcClient {
|
|||
.await?;
|
||||
self.team_matches_parser.parse(&body)
|
||||
}
|
||||
|
||||
/// Get all historical seasons by game mode
|
||||
pub async fn previous_seasons(&self) -> Result<Vec<Seasons>> {
|
||||
let body = self
|
||||
.client
|
||||
.get("https://www.ugcleague.com")
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
self.seasons_parser.parse(&body)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ use time::macros::format_description;
|
|||
|
||||
mod player;
|
||||
mod player_details;
|
||||
mod seasons;
|
||||
mod team;
|
||||
mod team_matches;
|
||||
mod team_roster_history;
|
||||
|
||||
pub use player::*;
|
||||
pub use player_details::*;
|
||||
pub use seasons::*;
|
||||
pub use team::*;
|
||||
pub use team_matches::*;
|
||||
pub use team_roster_history::*;
|
||||
|
|
|
|||
84
src/parser/seasons.rs
Normal file
84
src/parser/seasons.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
use super::Parser;
|
||||
use crate::data::{Season, Seasons};
|
||||
use crate::parser::{select_text, ElementExt};
|
||||
use crate::{ParseError, Result};
|
||||
use scraper::{Html, Selector};
|
||||
|
||||
const SELECTOR_MENU: &str = ".sub-menu";
|
||||
const SELECTOR_NAME: &str = ".mega-menu-sub-title";
|
||||
const SELECTOR_SEASON_LINK: &str = "ul[id$=\"seasons\"] a[href^=\"rankings_\"]";
|
||||
|
||||
pub struct SeasonsParser {
|
||||
selector_menu: Selector,
|
||||
selector_name: Selector,
|
||||
selector_link: Selector,
|
||||
}
|
||||
|
||||
impl Default for SeasonsParser {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl SeasonsParser {
|
||||
pub fn new() -> Self {
|
||||
SeasonsParser {
|
||||
selector_menu: Selector::parse(SELECTOR_MENU).unwrap(),
|
||||
selector_name: Selector::parse(SELECTOR_NAME).unwrap(),
|
||||
selector_link: Selector::parse(SELECTOR_SEASON_LINK).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parser for SeasonsParser {
|
||||
type Output = Vec<Seasons>;
|
||||
|
||||
fn parse(&self, document: &str) -> Result<Self::Output> {
|
||||
let document = Html::parse_document(document);
|
||||
|
||||
document
|
||||
.select(&self.selector_menu)
|
||||
.filter(|item| item.select(&self.selector_link).next().is_some())
|
||||
.filter(|item| item.select(&self.selector_name).next().is_some())
|
||||
.map(|item| {
|
||||
let name = select_text(item, &self.selector_name)
|
||||
.ok_or(ParseError::EmptyText {
|
||||
role: "game mode name",
|
||||
selector: SELECTOR_NAME,
|
||||
})?
|
||||
.trim_end_matches(" Menu");
|
||||
|
||||
let seasons = item
|
||||
.select(&self.selector_link)
|
||||
.map(|link| {
|
||||
let text = link
|
||||
.first_text()
|
||||
.ok_or(ParseError::EmptyText {
|
||||
role: "season name",
|
||||
selector: SELECTOR_SEASON_LINK,
|
||||
})?
|
||||
.trim_end_matches(" Final Standings")
|
||||
.trim_end_matches(" Final Rank")
|
||||
.trim_end_matches(" Final Ranks");
|
||||
let link = link.attr("href").ok_or(ParseError::EmptyText {
|
||||
role: "season link",
|
||||
selector: SELECTOR_SEASON_LINK,
|
||||
})?;
|
||||
let id = link
|
||||
.trim_start_matches("rankings_")
|
||||
.trim_end_matches(".cfm");
|
||||
Ok(Season {
|
||||
name: text.to_string(),
|
||||
id: id.to_string(),
|
||||
})
|
||||
})
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
Ok(Seasons {
|
||||
mode: name.to_string(),
|
||||
seasons,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue