diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..4da8f7c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. + // Pointez pour afficher la description des attributs existants. + // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Lancer", + "type": "cppdbg", + "request": "launch", + "program": "target/debug/deps/price_checker-9ac713c382a0d250", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Activer l'impression en mode Pretty pour gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/src/parser.rs b/src/parser.rs index 2620400..14e9106 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,5 @@ pub mod darty; +pub mod fnac; extern crate arraygen; extern crate url; @@ -24,14 +25,17 @@ pub trait PriceParser{ /// Represent the list of all the parser pub struct List { #[in_array(get_price)] - darty: darty::Darty + darty: darty::Darty, + #[in_array(get_price)] + fnac: fnac::Fnac, } impl List { /// Create the list pub fn new() -> Result { Ok(List { - darty: darty::Darty::new()? + darty: darty::Darty::new()?, + fnac: fnac::Fnac::new()? }) } } @@ -39,5 +43,5 @@ impl List { #[test] fn test_parser_list() { let parser_list = List::new().unwrap(); - assert_eq!(parser_list.get_price().len(), 1); + assert_eq!(parser_list.get_price().len(), 2); } \ No newline at end of file diff --git a/src/parser/fnac.rs b/src/parser/fnac.rs new file mode 100644 index 0000000..ac0d654 --- /dev/null +++ b/src/parser/fnac.rs @@ -0,0 +1,58 @@ +use super::PriceParser; +use crate::PriceResult; +use scraper::{Selector, Html}; +use url::Url; +use anyhow::{Result, anyhow}; + +#[derive(Debug)] +/// Parser for the darty website +pub struct Fnac { + price_selector: Selector, + name_selector: Selector, + product_selector: Selector +} + +impl PriceParser for Fnac { + fn new() -> Result { + Ok(Fnac { + price_selector: Selector::parse(r#".f-priceBox-price.checked"#).unwrap(), + name_selector: Selector::parse(r#".f-productHeader-Title"#).unwrap(), + product_selector: Selector::parse(r#".f-productHeader-subTitleLink"#).unwrap() + }) + } + + fn can_parse(&self, url : &Url) -> bool { + url.host_str().unwrap_or("") == "www.fnac.com" + } + + fn parse(&self, html : &Html) -> Result { + // Get price + let price_element = html.select(&self.price_selector).next().ok_or(anyhow!("No price element"))?; + let mut price_text_it = price_element.text(); + let price_ent : u32 = price_text_it.next().unwrap_or("0").trim_end_matches(',').parse()?; + let price_dec : u32 = price_text_it.next().unwrap_or("0").trim_start_matches('€').parse()?; + let price = price_ent as f64 + (price_dec as f64) / 100.; + + // Get name + let name_element = html.select(&self.name_selector).next().ok_or(anyhow!("No name element"))?; + let name = name_element.text().next().unwrap_or("").trim().replace('\n', "-"); + + // Get product + let family_element = html.select(&self.product_selector).next().ok_or(anyhow!("No product element"))?; + let family = family_element.text().next().unwrap_or("").trim().replace('\n', "-"); + + Ok(PriceResult { + name: name.to_owned(), + product: family.to_owned(), + price + }) + } +} + +#[test] +fn test_parser_fnac() { + let fnac_parser = Fnac::new().unwrap(); + assert!(fnac_parser.can_parse(&Url::parse("https://www.fnac.com/Apple-iPhone-XS-64-Go-5-8-Argent/a12849718/w-4?CtoPid=488371").unwrap())); + assert!(fnac_parser.can_parse(&Url::parse("http://www.fnac.com/Apple-iPhone-XS-64-Go-5-8-Argent/a12849718/w-4?CtoPid=488371").unwrap())); + assert!(fnac_parser.can_parse(&Url::parse("https://www.fnace.com").unwrap()) == false); +} \ No newline at end of file diff --git a/src/price_checker.rs b/src/price_checker.rs index 6b1eb99..d746a3c 100644 --- a/src/price_checker.rs +++ b/src/price_checker.rs @@ -45,4 +45,10 @@ fn test_price_checker() { assert!(price_result.name != ""); assert!(price_result.price != 0.); assert!(price_result.product != ""); + + // Test fnac + let price_result = price_checker.get_price(Url::parse("https://www.fnac.com/PC-Gaming-Milenium-MM1-Ekko-R207-A536X-W-S-R48-B-D1-AMD-Ryzen-5-32-Go-RAM-500-Go-SSD-1-To-SATA-Noir/a14620943/w-4").unwrap()).unwrap(); + assert!(price_result.name != ""); + assert!(price_result.price != 0.); + assert!(price_result.product != ""); } \ No newline at end of file