From ef402bb5c3f953300eaf559bf0e4f54b2628f68f Mon Sep 17 00:00:00 2001 From: sysadminstory Date: Wed, 14 Feb 2018 12:03:44 +0100 Subject: [PATCH] [DealabsBride] Fix for the new site (#595) * [DealabsBride] Fix for the new site --- bridges/DealabsBridge.php | 372 +++++++++++++++++++++++++++----------- 1 file changed, 263 insertions(+), 109 deletions(-) diff --git a/bridges/DealabsBridge.php b/bridges/DealabsBridge.php index d6b1e66..cd02017 100644 --- a/bridges/DealabsBridge.php +++ b/bridges/DealabsBridge.php @@ -2,8 +2,7 @@ class DealabsBridge extends BridgeAbstract { const NAME = 'Dealabs search bridge'; const URI = 'https://www.dealabs.com/'; - const DESCRIPTION = 'Return the Dealabs search result using keywords, - with/without expired deals, with/without shop deals and by category'; + const DESCRIPTION = 'Return the Dealabs search result using keywords'; const MAINTAINER = 'sysadminstory'; const PARAMETERS = array( array ( 'q' => array( @@ -11,97 +10,56 @@ class DealabsBridge extends BridgeAbstract { 'type' => 'text', 'required' => true ), - 'expired_choice' => array( - 'name' => 'Afficher deals expirés', - 'type' => 'checkbox' + 'hide_expired' => array( + 'name' => 'Masquer les éléments expirés', + 'type' => 'checkbox', + 'required' => 'true' ), - 'instore_choice' => array( - 'name' => 'Afficher deals en magasin', - 'type' => 'checkbox' + 'hide_local' => array( + 'name' => 'Masquer les deals locaux', + 'type' => 'checkbox', + 'title' => 'Masquer les deals en magasins physiques', + 'required' => 'true' + ), + 'priceFrom' => array( + 'name' => 'Prix minimum', + 'type' => 'text', + 'title' => 'Prix mnimum en euros', + 'required' => 'false', + 'defaultValue' => '' + ), + 'priceTo' => array( + 'name' => 'Prix maximum', + 'type' => 'text', + 'title' => 'Prix maximum en euros', + 'required' => 'false', + 'defaultValue' => '' ), - 'cat' => array( - 'name' => 'Catégorie', - 'type' => 'list', - 'values' => array( - 'Toutes les catégories' => '', - 'High-tech' => array( - 'Tous' => 'c2', - 'Informatique' => 's3', - 'Téléphonie' => 's4', - 'Accessoires, consommables' => 's6', - 'Gadgets' => 's8', - 'Applications, logiciels' => 's46' - ), - 'Audiovisuel' => array( - 'Tous' => 'c5', - 'Image et son' => 's9', - 'Photo, caméscopes' => 's10', - 'CD, DVD, Blu-ray' => 's11', - 'Jeux vidéo, consoles' => 's12' - ), - 'Loisirs' => array( - 'Tous' => 'c7', - 'Jeux, jouets' => 's13', - 'Livres, papeterie' => 's14', - 'Plein air' => 's15', - 'Sport' => 's35', - 'Auto/Moto, accessoires' => 's37', - 'Animaux, accessoires' => 's47', - 'Instruments de musique' => 's48' - ), - 'Mode' => array( - 'Tous' => 'c16', - 'Homme' => 's17', - 'Femme' => 's18', - 'Mixte' => 's50', - 'Enfants' => 's19', - 'Puériculture' => 's36', - 'Beauté, santé' => 's21', - 'Bijoux, accessoires' => 's20', - 'Bagagerie' => 's38' - ), - 'Maison' => array( - 'Tous' => 'c23', - 'Meuble, literie, déco' => 's24', - 'Cuisine, art de la table' => 's25', - 'Électroménager' => 's26', - 'Bricolage' => 's27', - 'Jardin' => 's28' - ), - 'Services' => array( - 'Tous' => 'c51', - 'Voyages' => 's57', - 'Hébergement, restauration' => 's52', - 'Sorties' => 's53', - 'Presse' => 's24', - 'Bien-être' => 's55', - 'Transport, expédition' => 's56', - 'Autres' => 's58' - ), - 'Épicerie' => 'c31' - - ) - ) - - )); const CACHE_TIMEOUT = 3600; public function collectData(){ $q = $this->getInput('q'); + $hide_expired = $this->getInput('hide_expired'); + $hide_local = $this->getInput('hide_local'); + $priceFrom = $this->getInput('priceFrom'); + $priceTo = $this->getInput('priceFrom'); - $expired_choice = $this->getInput('expired_choice'); - $instore_choice = $this->getInput('instore_choice'); - $cat_subcat = $this->getInput('cat'); + /* Event if the original website uses POST with the search page, GET works too */ $html = getSimpleHTMLDOM(self::URI - . '/search/?q=' + . '/search/advanced?q=' . urlencode($q) - . '&hide_expired=' - . $expired_choice - . '&hide_instore=' - . $instore_choice - . '&' . $this->getCatSubcatParam($cat_subcat)) + . '&hide_expired='. $hide_expired + . '&hide_local='. $hide_local + . '&priceFrom='. $priceFrom + . '&priceTo='. $priceTo + /* Some default parameters + * search_fields : Search in Titres & Descriptions & Codes + * sort_by : Sort the search by new deals + * time_frame : Search will not be on a limited timeframe + */ + . '&search_fields[]=1&search_fields[]=2&search_fields[]=3&sort_by=new&time_frame=0') or returnServerError('Could not request Dealabs.'); $list = $html->find('article'); if($list === null) { @@ -110,24 +68,232 @@ class DealabsBridge extends BridgeAbstract { foreach($list as $deal) { $item = array(); - $item['uri'] = $deal->find('a.title', 0)->href; - $item['title'] = $deal->find('a.title', 0)->plaintext; - $item['author'] = $deal->find('a.poster_link', 0)->plaintext; - $item['content'] = '
' - . $deal->find('div.image_part', 0)->outertext + $item['uri'] = $deal->find('div[class=threadGrid-title]', 0)->find('a', 0)->href; + $item['title'] = $deal->find( + 'a[class=cept-tt thread-link linkPlain space--r-1 size--all-s size--fromW3-m]', 0 + )->plaintext; + $item['author'] = $deal->find('span.thread-username', 0)->plaintext; + $item['content'] = '

' + . $deal->find('a[class=cept-tt thread-link linkPlain space--r-1 size--all-s size--fromW3-m]', 0)->innertext + . '

' + . $this->getPrix($deal) + . $this->getReduction($deal) + . $this->getExpedition($deal) + . $this->getLivraison($deal) + . $this->getOrigine($deal) + . $deal->find( + 'div[class=cept-description-container overflow--wrap-break size--all-s size--fromW3-m]', 0 + )->innertext . '
' - . $deal->find('a.title', 0)->outertext - . $deal->find('p.description', 0)->outertext - . '' - . $deal->find('div.vote_part', 0)->outertext + . $deal->find('div[class=flex flex--align-c flex--justify-space-between space--b-2]', 0)->children(0)->outertext . '
'; - $item['timestamp'] = $this->relativeDateToTimestamp( - $deal->find('p.date_deal', 0)->plaintext); + $dealDateDiv = $deal->find('div[class=size--all-s flex flex--wrap flex--justify-e flex--grow-1]', 0) + ->find('span[class=hide--toW3]'); + $itemDate = end($dealDateDiv)->plaintext; + if(substr( $itemDate, 0, 6 ) === 'il y a') { + $item['timestamp'] = $this->relativeDateToTimestamp($itemDate); + } else { + $item['timestamp'] = $this->parseDate($itemDate); + } $this->items[] = $item; } } + /** + * Get the Price from a Deal if it exists + * @return string String of the deal price + */ + private function getPrix($deal) + { + if($deal->find( + 'span[class*=thread-price]', 0) != null) { + return '
Prix : ' + . $deal->find( + 'span[class*=thread-price]', 0 + )->plaintext + . '
'; + } else { + return ''; + } + } + + + /** + * Get the Shipping costs from a Deal if it exists + * @return string String of the deal shipping Cost + */ + private function getLivraison($deal) + { + if($deal->find('span[class*=cept-shipping-price]', 0) != null) { + if($deal->find('span[class*=cept-shipping-price]', 0)->children(0) != null) { + return '
Livraison : ' + . $deal->find('span[class*=cept-shipping-price]', 0)->children(0)->innertext + . '
'; + } else { + return '
Livraison : ' + . $deal->find('span[class*=cept-shipping-price]', 0)->innertext + . '
'; + } + } else { + return ''; + } + } + + /** + * Get the source of a Deal if it exists + * @return string String of the deal source + */ + private function getOrigine($deal) + { + if($deal->find('a[class=text--color-greyShade]', 0) != null) { + return '
Origine : ' + . $deal->find('a[class=text--color-greyShade]', 0)->outertext + . '
'; + } else { + return ''; + } + } + + /** + * Get the original Price and discout from a Deal if it exists + * @return string String of the deal original price and discount + */ + private function getReduction($deal) + { + if($deal->find('span[class*=mute--text text--lineThrough]', 0) != null) { + return '
Réduction : ' + . $deal->find( + 'span[class*=mute--text text--lineThrough]', 0 + )->plaintext + . ' ' + . $deal->find('span[class=space--ml-1 size--all-l size--fromW3-xl]', 0)->plaintext + . '
'; + } else { + return ''; + } + } + + /** + * Get the Picture URL from a Deal if it exists + * @return string String of the deal Picture URL + */ + private function getImage($deal) + { + + $selectorLazy = implode( + ' ', /* Notice this is a space! */ + array( + 'thread-image', + 'width--all-auto', + 'height--all-auto', + 'imgFrame-img', + 'cept-thread-img', + 'img--dummy', + 'js-lazy-img' + ) + ); + + $selectorPlain = implode( + ' ', /* Notice this is a space! */ + array( + 'thread-image', + 'width--all-auto', + 'height--all-auto', + 'imgFrame-img', + 'cept-thread-img' + ) + ); + if($deal->find('img[class='. $selectorLazy .']', 0) != null) { + return json_decode( + html_entity_decode( + $deal->find('img[class='. $selectorLazy .']', 0) + ->getAttribute('data-lazy-img')))->{'src'}; + } else { + return $deal->find('img[class='. $selectorPlain .']', 0 )->src; + } + } + + /** + * Get the originating country from a Deal if it existsa + * @return string String of the deal originating country + */ + private function getExpedition($deal) + { + $selector = implode( + ' ', /* Notice this is a space! */ + array( + 'meta-ribbon', + 'overflow--wrap-off', + 'space--l-3', + 'text--color-greyShade' + ) + ); + if($deal->find('span[class='. $selector .']', 0) != null) { + return '
' + . $deal->find('span[class='. $selector .']', 0)->children(2)->plaintext + . '
'; + } else { + return ''; + } + } + + /** + * Transforms a French date into a timestam + * @return int timestamp of the input date + */ + private function parseDate($string) + { + $month_fr = array( + 'janvier', + 'février', + 'mars', + 'avril', + 'mai', + 'juin', + 'juillet', + 'août', + 'septembre', + 'octobre', + 'novembre', + 'décembre' + ); + $month_en = array( + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' + ); + $date_str = trim(str_replace($month_fr, $month_en, $string)); + + if(!preg_match('/[0-9]{4}/', $string)) { + $date_str .= ' ' . date('Y'); + } + $date_str .= ' 00:00'; + + $date = DateTime::createFromFormat('j F Y H:i', $date_str); + return $date->getTimestamp(); + } + + /** + * Transforms a relate French date into a timestam + * @return int timestamp of the input date + */ private function relativeDateToTimestamp($str) { $date = new DateTime(); $search = array( @@ -137,7 +303,8 @@ class DealabsBridge extends BridgeAbstract { 'jour', 'jours', 'mois', - 'ans' + 'ans', + 'et ' ); $replace = array( '-', @@ -145,25 +312,12 @@ class DealabsBridge extends BridgeAbstract { 'hour', 'day', 'month', - 'year' + 'year', + '' ); $date->modify(str_replace($search, $replace, $str)); return $date->getTimestamp(); } - private function getCatSubcatParam($str) { - if(strlen($str) >= 2) { - if(substr($str, 0, 1) == 'c') { - $var_name = 'cat[]'; - } else if(substr($str, 0, 1) == 's') { - $var_name = 'sub_cat[]'; - } - $value = substr($str, 1); - return $var_name .'='. $value; - } else { - return ''; - } - } - }