team list

This commit is contained in:
Robin Appelman 2023-11-18 21:53:17 +01:00
commit 202917c318
12 changed files with 128772 additions and 5 deletions

View file

@ -3,10 +3,10 @@ mod error;
#[doc(hidden)] #[doc(hidden)]
pub mod parser; pub mod parser;
use crate::data::{MembershipHistory, Player, RosterHistory, Seasons, Team, TeamSeason}; use crate::data::{MembershipHistory, Player, RosterHistory, Seasons, Team, TeamRef, TeamSeason};
use crate::parser::{ use crate::parser::{
Parser, PlayerDetailsParser, PlayerParser, SeasonsParser, TeamMatchesParser, TeamParser, Parser, PlayerDetailsParser, PlayerParser, SeasonsParser, TeamLookupParser, TeamMatchesParser,
TeamRosterHistoryParser, TeamParser, TeamRosterHistoryParser,
}; };
pub use error::*; pub use error::*;
use reqwest::redirect::Policy; use reqwest::redirect::Policy;
@ -24,6 +24,7 @@ pub struct UgcClient {
team_roster_history_parser: TeamRosterHistoryParser, team_roster_history_parser: TeamRosterHistoryParser,
team_matches_parser: TeamMatchesParser, team_matches_parser: TeamMatchesParser,
seasons_parser: SeasonsParser, seasons_parser: SeasonsParser,
team_lookup_parser: TeamLookupParser,
} }
/// "API client" for ugc by scraping the website /// "API client" for ugc by scraping the website
@ -37,6 +38,7 @@ impl UgcClient {
team_roster_history_parser: TeamRosterHistoryParser::new(), team_roster_history_parser: TeamRosterHistoryParser::new(),
team_matches_parser: TeamMatchesParser::new(), team_matches_parser: TeamMatchesParser::new(),
seasons_parser: SeasonsParser::new(), seasons_parser: SeasonsParser::new(),
team_lookup_parser: TeamLookupParser::new(),
} }
} }
@ -130,4 +132,33 @@ impl UgcClient {
.await?; .await?;
self.seasons_parser.parse(&body) self.seasons_parser.parse(&body)
} }
async fn teams(&self, link: &str) -> Result<Vec<TeamRef>> {
let body = self.client.get(link).send().await?.text().await?;
self.team_lookup_parser.parse(&body)
}
/// Get a list of all 9v9 teams
pub async fn teams_9v9(&self) -> Result<Vec<TeamRef>> {
self.teams("https://www.ugcleague.com/team_lookup_tf2h.cfm")
.await
}
/// Get a list of all 6v6 teams
pub async fn teams_6v6(&self) -> Result<Vec<TeamRef>> {
self.teams("https://www.ugcleague.com/team_lookup_tf26.cfm")
.await
}
/// Get a list of all 4v4 teams
pub async fn teams_4v4(&self) -> Result<Vec<TeamRef>> {
self.teams("https://www.ugcleague.com/team_lookup_tf24.cfm")
.await
}
/// Get a list of all 2v2 teams
pub async fn teams_2v2(&self) -> Result<Vec<TeamRef>> {
self.teams("https://www.ugcleague.com/team_lookup_tf22.cfm")
.await
}
} }

View file

@ -8,6 +8,7 @@ mod player;
mod player_details; mod player_details;
mod seasons; mod seasons;
mod team; mod team;
mod team_lookup;
mod team_matches; mod team_matches;
mod team_roster_history; mod team_roster_history;
@ -15,6 +16,7 @@ pub use player::*;
pub use player_details::*; pub use player_details::*;
pub use seasons::*; pub use seasons::*;
pub use team::*; pub use team::*;
pub use team_lookup::*;
pub use team_matches::*; pub use team_matches::*;
pub use team_roster_history::*; pub use team_roster_history::*;

65
src/parser/team_lookup.rs Normal file
View file

@ -0,0 +1,65 @@
use super::Parser;
use crate::data::TeamRef;
use crate::parser::{team_id_from_link, ElementExt};
use crate::{ParseError, Result};
use scraper::{Html, Selector};
const SELECTOR_SELECT: &str = "select[name=\"clan_select\"]";
const SELECTOR_OPTION: &str = "option[value^=\"team_page\"]";
pub struct TeamLookupParser {
selector_select: Selector,
selector_option: Selector,
}
impl Default for TeamLookupParser {
fn default() -> Self {
Self::new()
}
}
impl TeamLookupParser {
pub fn new() -> Self {
TeamLookupParser {
selector_select: Selector::parse(SELECTOR_SELECT).unwrap(),
selector_option: Selector::parse(SELECTOR_OPTION).unwrap(),
}
}
}
impl Parser for TeamLookupParser {
type Output = Vec<TeamRef>;
fn parse(&self, document: &str) -> Result<Self::Output> {
let document = Html::parse_document(document);
let select =
document
.select(&self.selector_select)
.next()
.ok_or(ParseError::ElementNotFound {
selector: SELECTOR_SELECT,
role: "team list",
})?;
select
.select(&self.selector_option)
.map(|option| {
let link = option.attr("value").ok_or(ParseError::EmptyText {
role: "team link",
selector: SELECTOR_OPTION,
})?;
let text = option.first_text().ok_or(ParseError::EmptyText {
role: "team name",
selector: SELECTOR_OPTION,
})?;
let (_, name) = text.split_once("-").unwrap_or_default();
let id = team_id_from_link(link)?;
Ok(TeamRef {
id,
name: name.trim().to_string(),
})
})
.collect()
}
}

2983
tests/data/lookup_2v2.html Normal file

File diff suppressed because it is too large Load diff

7157
tests/data/lookup_4v4.html Normal file

File diff suppressed because it is too large Load diff

11476
tests/data/lookup_6v6.html Normal file

File diff suppressed because it is too large Load diff

11729
tests/data/lookup_9v9.html Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
use insta::assert_json_snapshot; use insta::assert_json_snapshot;
use std::fs::read_to_string; use std::fs::read_to_string;
use ugc_scraper::parser::{ use ugc_scraper::parser::{
Parser, PlayerDetailsParser, PlayerParser, SeasonsParser, TeamMatchesParser, TeamParser, Parser, PlayerDetailsParser, PlayerParser, SeasonsParser, TeamLookupParser, TeamMatchesParser,
TeamRosterHistoryParser, TeamParser, TeamRosterHistoryParser,
}; };
#[test] #[test]
@ -60,3 +60,35 @@ fn test_parse_seasons_html() {
let parsed = parser.parse(&body).unwrap(); let parsed = parser.parse(&body).unwrap();
assert_json_snapshot!(parsed); assert_json_snapshot!(parsed);
} }
#[test]
fn test_parse_seasons_9_html() {
let body = read_to_string("tests/data/lookup_9v9.html").unwrap();
let parser = TeamLookupParser::new();
let parsed = parser.parse(&body).unwrap();
assert_json_snapshot!(parsed);
}
#[test]
fn test_parse_seasons_6_html() {
let body = read_to_string("tests/data/lookup_6v6.html").unwrap();
let parser = TeamLookupParser::new();
let parsed = parser.parse(&body).unwrap();
assert_json_snapshot!(parsed);
}
#[test]
fn test_parse_seasons_4_html() {
let body = read_to_string("tests/data/lookup_4v4.html").unwrap();
let parser = TeamLookupParser::new();
let parsed = parser.parse(&body).unwrap();
assert_json_snapshot!(parsed);
}
#[test]
fn test_parse_seasons_2_html() {
let body = read_to_string("tests/data/lookup_2v2.html").unwrap();
let parser = TeamLookupParser::new();
let parsed = parser.parse(&body).unwrap();
assert_json_snapshot!(parsed);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff