diff --git a/Cargo.lock b/Cargo.lock
index 027bbf4..283e65b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -462,6 +462,12 @@ dependencies = [
"dtoa",
]
+[[package]]
+name = "ego-tree"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8"
+
[[package]]
name = "either"
version = "1.15.0"
@@ -671,6 +677,15 @@ dependencies = [
"version_check",
]
+[[package]]
+name = "getopts"
+version = "0.2.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
+dependencies = [
+ "unicode-width",
+]
+
[[package]]
name = "getrandom"
version = "0.2.16"
@@ -1983,6 +1998,21 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+[[package]]
+name = "scraper"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5f3a24d916e78954af99281a455168d4a9515d65eca99a18da1b813689c4ad9"
+dependencies = [
+ "cssparser",
+ "ego-tree",
+ "getopts",
+ "html5ever",
+ "precomputed-hash",
+ "selectors",
+ "tendril",
+]
+
[[package]]
name = "security-framework"
version = "2.11.1"
@@ -2277,6 +2307,7 @@ dependencies = [
"mwbot",
"rand 0.9.2",
"reqwest",
+ "scraper",
"serde",
"thiserror 2.0.12",
"tokio",
@@ -2643,6 +2674,12 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+[[package]]
+name = "unicode-width"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
+
[[package]]
name = "untrusted"
version = "0.9.0"
diff --git a/Cargo.toml b/Cargo.toml
index 903f788..2009d5a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,6 +17,7 @@ futures = "0.3.31"
mwbot = { version = "0.7.0", default-features = false, features = ["generators", "mwbot_derive"] }
rand = "0.9.2"
reqwest = "0.12.22"
+scraper = "0.24.0"
serde = { version = "1.0.219", features = ["derive"] }
thiserror = "2.0.12"
tokio = { version = "1.46.1", features = ["rt"] }
diff --git a/polina.html b/polina.html
new file mode 100644
index 0000000..e0d5ab4
--- /dev/null
+++ b/polina.html
@@ -0,0 +1,586 @@
+
+
+
+
+
+
+
+
+
+ Polina Gorushkina [20000] - WSDC Registry - World Swing Dance Council Points Registry
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Polina Gorushkina [20000] - WSDC Registry - World Swing Dance Council Points Registry
+
+
+
+
+
+ Polina Gorushkina [20000]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | First name: |
+ Polina |
+
+
+ | Last name: |
+ Gorushkina |
+
+
+ | Birth name: |
+ Gorushkina |
+
+
+ | Nickname: |
+ |
+
+
+ | Previous Names: |
+ Pro |
+
+
+ | Transliteral: |
+
+  Polina Gorushkina
+ |
+
+
+ | WSDC-ID: |
+ 20000 |
+
+
+ | Allowed Divisions: |
+ NOV,INT |
+
+
+ | Date of birth: |
+ Pro |
+
+
+ | Age: |
+ Pro |
+
+
+ | Country: |
+ Pro |
+
+
+ | City: |
+ Pro |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ All Time |
+
+
+
+
+
+ | Primary Role |
+ |
+ Follower |
+
+ | Points |
+ |
+ 36 |
+
+ | Points Follower |
+ 100.00% |
+ 36 |
+
+ | Points Last 3 years |
+ |
+ 21 |
+
+ | Timeframe |
+ 2years |
+ December 2020 - December 2022 |
+
+ | Wins |
+ 14.29% |
+ 1 |
+
+ | Placements |
+ 57.14% |
+ 4 |
+
+ | Finals |
+ 1.00x |
+ 7 |
+
+ | Events |
+ 1.75x |
+ 7 |
+
+ | Unique Events |
+ |
+ 4 |
+
+Intermediate |
+ | Points |
+ 20.00% |
+ 6 |
+
+ | Points Follower |
+ 100.00% |
+ 6 |
+
+ | Points Last 3 years |
+ |
+ 6 |
+
+ | Timeframe |
+ |
+ December 2022 - December 2022 |
+
+ | Wins |
+ 0.00% |
+ 0 |
+
+ | Placements |
+ 100.00% |
+ 1 |
+
+ | Finals |
+ 1.00x |
+ 1 |
+
+ | Events |
+ 1.00x |
+ 1 |
+
+ | Unique Events |
+ |
+ 1 |
+
Novice |
+ | Points |
+ 187.50% |
+ 30 |
+
+ | Points Follower |
+ 100.00% |
+ 30 |
+
+ | Points Last 3 years |
+ |
+ 15 |
+
+ | Timeframe |
+ 1year 11months |
+ December 2020 - November 2022 |
+
+ | Wins |
+ 16.67% |
+ 1 |
+
+ | Placements |
+ 50.00% |
+ 3 |
+
+ | Finals |
+ 1.00x |
+ 6 |
+
+ | Events |
+ 1.50x |
+ 6 |
+
+ | Unique Events |
+ |
+ 4 |
+
+
+
+
+
+
+
+
+
+
+
+
Polina Gorushkina is allowed to dance as a leader in the following divisions:
Novice
+
+
+
Polina Gorushkina is allowed to dance as a follower in the following divisions:
Intermediate
Intermediate: 6 of 30 total points
| F | Moscow, Russia - December 2022 | 3rd | 6 |
| TOTAL: | 6 |
Novice: 30 of 16 total points
| F | Moscow, Russia - November 2022 | 1st | 15 |
| F | St.Petersburg, Russia - July 2022 | 5th | 6 |
| F | St. Petersburg, Russia - February 2022 | 5th | 6 |
| F | Moscow, Russia - December 2021 | Final | 1 |
| F | Moscow, Russia - October 2021 | Final | 1 |
| F | Moscow, Russia - December 2020 | Final | 1 |
| TOTAL: | 30 |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/worldsdc/mod.rs b/src/worldsdc/mod.rs
index 80fe793..6455435 100644
--- a/src/worldsdc/mod.rs
+++ b/src/worldsdc/mod.rs
@@ -7,7 +7,6 @@ use crate::{
dance_info::{CompState, DanceInfo, DanceRank, DanceRole},
};
-// mod caching;
pub async fn fetch_wsdc_info(id: u32) -> Result {
let client = ClientBuilder::new()
.user_agent(app_signature())
@@ -37,6 +36,75 @@ pub async fn fetch_wsdc_info(id: u32) -> Result {
Ok(x.into())
}
+use scraper::{Html, Selector};
+
+fn extract_tables(html: &str) -> Vec<(String, Vec<(String, String)>)> {
+ let document = Html::parse_document(html);
+ let card_selector = Selector::parse("div:has( > div.card-header)").unwrap();
+ let title_selector = Selector::parse("div.card-header").unwrap();
+ let table_selector = Selector::parse("div.card-body > table").unwrap();
+ let row_selector = Selector::parse("tr").unwrap();
+ let header_selector = Selector::parse("th").unwrap();
+ let cell_selector = Selector::parse("td").unwrap();
+
+ let mut pairs = Vec::new();
+
+ for card in document.select(&card_selector) {
+ let table = card.select(&table_selector).next().unwrap();
+ let title = card
+ .select(&title_selector)
+ .next()
+ .unwrap()
+ .text()
+ .collect::>()
+ .join("sep")
+ .trim()
+ .to_owned();
+
+ for row in table.select(&row_selector) {
+ let header = row.select(&header_selector).next();
+ let cell = row.select(&cell_selector).next();
+
+ if let (Some(h), Some(c)) = (header, cell) {
+ let key = h.text().collect::().trim().to_string();
+ let value = c.text().collect::().trim().to_string();
+ pairs.push((key, value));
+ }
+ }
+ }
+
+ todo!()
+}
+
+fn parse_table(html: &str) {
+ let tables = extract_tables(html);
+}
+
+#[test]
+fn test_parse_table() {
+ parse_table(include_str!("../../polina.html"));
+}
+
+pub async fn fetch_wsdc_info_scoring_dance(id: u32) -> Result {
+ let client = ClientBuilder::new()
+ .user_agent(app_signature())
+ .build()
+ .map_err(DanceInfoError::ClientBuild)?;
+
+ let url = format!("https://scoring.dance/enUS/wsdc/registry/{id}.html");
+ let request = client
+ .request(reqwest::Method::GET, url)
+ .build()
+ .map_err(DanceInfoError::RequestBuild)?;
+ let response = client
+ .execute(request)
+ .await
+ .map_err(DanceInfoError::Request)?;
+
+ let x: DanceInfoParser = response.json().await.map_err(DanceInfoError::JsonParse)?;
+ Ok(x.into())
+}
+
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, reason = "Allow unwrap in tests")]