diff --git a/src/parser.rs b/src/parser.rs index 14e9106..660975b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,7 @@ pub mod darty; pub mod fnac; +pub mod du_bruit_dans_la_cuisine; +pub mod ldlc; extern crate arraygen; extern crate url; @@ -28,6 +30,10 @@ pub struct List { darty: darty::Darty, #[in_array(get_price)] fnac: fnac::Fnac, + #[in_array(get_price)] + du_bruit_dans_la_cuisine: du_bruit_dans_la_cuisine::DuBruitDansLaCuisine, + #[in_array(get_price)] + ldlc: ldlc::LDLC, } impl List { @@ -35,7 +41,9 @@ impl List { pub fn new() -> Result { Ok(List { darty: darty::Darty::new()?, - fnac: fnac::Fnac::new()? + fnac: fnac::Fnac::new()?, + du_bruit_dans_la_cuisine: du_bruit_dans_la_cuisine::DuBruitDansLaCuisine::new()?, + ldlc: ldlc::LDLC::new()? }) } } @@ -43,5 +51,5 @@ impl List { #[test] fn test_parser_list() { let parser_list = List::new().unwrap(); - assert_eq!(parser_list.get_price().len(), 2); + assert_eq!(parser_list.get_price().len(), 4); } \ No newline at end of file diff --git a/src/parser/du_bruit_dans_la_cuisine.rs b/src/parser/du_bruit_dans_la_cuisine.rs new file mode 100644 index 0000000..ef0bfbf --- /dev/null +++ b/src/parser/du_bruit_dans_la_cuisine.rs @@ -0,0 +1,50 @@ +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 DuBruitDansLaCuisine { + price_selector: Selector, + name_selector: Selector, +} + +impl PriceParser for DuBruitDansLaCuisine { + fn new() -> Result { + Ok(DuBruitDansLaCuisine { + price_selector: Selector::parse(r#".price"#).unwrap(), + name_selector: Selector::parse(r#".product.item"#).unwrap(), + }) + } + + fn can_parse(&self, url : &Url) -> bool { + url.host_str().unwrap_or("") == "www.dubruitdanslacuisine.fr" + } + + 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 : f64 = price_text_it.next().unwrap_or("0.").trim_end_matches("€").trim().replace(',', ".").parse()?; + + // Get name + let name_element = html.select(&self.name_selector).next().ok_or(anyhow!("No name element"))?; + let name = name_element.text().nth(1).unwrap_or("").trim(); + + Ok(PriceResult { + name: name.to_owned(), + product: "Cuisine".to_owned(), + price + }) + } +} + +#[test] +fn test_parser_du_bruit_dans_la_cuisine() { + let parser = DuBruitDansLaCuisine::new().unwrap(); + assert!(parser.can_parse(&Url::parse("https://www.dubruitdanslacuisine.fr/tapis-a-patisserie-40-62-14377-p").unwrap())); + assert!(parser.can_parse(&Url::parse("https://www.dubruitdanslacuisine.fr/tapis-a-patisserie-40-62-14377-p").unwrap())); + assert!(parser.can_parse(&Url::parse("https://www.dubrutdanslacuisine.fr/").unwrap()) == false); +} \ No newline at end of file diff --git a/src/parser/ldlc.rs b/src/parser/ldlc.rs new file mode 100644 index 0000000..e8f212b --- /dev/null +++ b/src/parser/ldlc.rs @@ -0,0 +1,52 @@ +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 LDLC { + price_selector: Selector, + name_selector: Selector, +} + +impl PriceParser for LDLC { + fn new() -> Result { + Ok(LDLC { + price_selector: Selector::parse(r#".price"#).unwrap(), + name_selector: Selector::parse(r#".title-1"#).unwrap(), + }) + } + + fn can_parse(&self, url : &Url) -> bool { + url.host_str().unwrap_or("") == "www.ldlc.com" + } + + fn parse(&self, html : &Html) -> Result { + // Get price + let price_element = html.select(&self.price_selector).nth(4).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").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(); + + Ok(PriceResult { + name: name.to_owned(), + product: "High-tech".to_owned(), + price + }) + } +} + +#[test] +fn test_parser_du_bruit_dans_la_cuisine() { + let parser = LDLC::new().unwrap(); + assert!(parser.can_parse(&Url::parse("https://www.ldlc.com/fiche/PB00335410.html").unwrap())); + assert!(parser.can_parse(&Url::parse("http://www.ldlc.com/fiche/PB00335410.html").unwrap())); + assert!(parser.can_parse(&Url::parse("https://www.ldlv.com").unwrap()) == false); +} \ No newline at end of file diff --git a/src/price_checker.rs b/src/price_checker.rs index 26f21ed..fd831a6 100644 --- a/src/price_checker.rs +++ b/src/price_checker.rs @@ -47,8 +47,18 @@ fn test_price_checker() { 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(); + let price_result = price_checker.get_price(Url::parse("https://www.fnac.com/a12584732/Kaamelott-Les-Six-Livres-L-integrale-de-la-serie-Coffret-Blu-ray-Alexandre-Astier-Blu-ray").unwrap()).unwrap(); assert!(price_result.name != ""); assert!(price_result.price != 0.); assert!(price_result.product != ""); + + // Test du bruis dans la cuisine + let price_result = price_checker.get_price(Url::parse("https://www.dubruitdanslacuisine.fr/tapis-a-patisserie-40-62-14377-p").unwrap()).unwrap(); + assert!(price_result.name != ""); + assert!(price_result.price != 0.); + + // LDLC + let price_result = price_checker.get_price(Url::parse("https://www.ldlc.com/fiche/PB00335410.html").unwrap()).unwrap(); + assert!(price_result.name != ""); + assert!(price_result.price != 0.); } \ No newline at end of file