From 43ea314e4122459a651bc6230656c98c396c83c9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Nov 2025 16:25:30 +0000 Subject: [PATCH] fix: Improve Fnac image extraction and add Shopify fallbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes two issues: **1. Fnac - No Images Displayed** Problem: FnacParser only searched for images in parent container, missing images nested directly in the link element. Solution: Two-priority search - PRIORITY 1: Search in link element first (picture, img) - PRIORITY 2: Search in parent container - Added warning log when no image found - Ensures parent is always defined before use **2. L'Incroyable - 0 Products (Shopify sites)** Problem: GenericParser fallbacks didn't include Shopify patterns. L'Incroyable uses Shopify structure with /products/ URLs. Solution: Added Shopify-specific fallbacks - a[href*='/products/'] (Shopify product URLs) - a.product-card__link (Shopify class) - a[href*='/collections/'] (Shopify collections) - li[class*='product'] a (list-based layouts) **Fallback Order (now 17 selectors):** 1. Product URL patterns (Shopify, generic) 2. Semantic classes (article, .product-card) 3. Shopify-specific selectors 4. Generic structure patterns 5. Last resort wildcards **Expected Impact:** - ✅ Fnac images should now display - ✅ L'Incroyable should find products (Shopify) - ✅ Better coverage of Shopify-based stores --- app/services/parsers/fnac_parser.py | 31 +++++++++++++++++++++----- app/services/parsers/generic_parser.py | 5 +++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/app/services/parsers/fnac_parser.py b/app/services/parsers/fnac_parser.py index faa42a1..ef2ae87 100644 --- a/app/services/parsers/fnac_parser.py +++ b/app/services/parsers/fnac_parser.py @@ -80,11 +80,30 @@ class FnacParser(BaseParser): if not self.filter_by_query(title, query): continue - # Extract image + # Extract image - try in link first, then parent image_url = None parent = link.find_parent(["article", "li", "div"]) - if parent: - # Try picture > source first + + # PRIORITY 1: Try in the link itself + picture = link.find("picture") + if picture: + source = picture.find("source") + if source and source.get("srcset"): + image_url = source.get("srcset").split(",")[0].split()[0] + if not image_url: + img = picture.find("img") + if img: + image_url = self._get_image_src(img) + + # Try img directly in link + if not image_url: + img = link.find("img") + if img: + image_url = self._get_image_src(img) + + # PRIORITY 2: Try in parent container + if not image_url and parent: + # Try picture > source picture = parent.find("picture") if picture: source = picture.find("source") @@ -101,8 +120,10 @@ class FnacParser(BaseParser): if img: image_url = self._get_image_src(img) - if image_url: - image_url = self.make_absolute_url(image_url) + if image_url: + image_url = self.make_absolute_url(image_url) + else: + self.logger.warning(f"No image found for Fnac product: {title[:40]}...") # Extract price price = None diff --git a/app/services/parsers/generic_parser.py b/app/services/parsers/generic_parser.py index ca093d3..d000ef3 100644 --- a/app/services/parsers/generic_parser.py +++ b/app/services/parsers/generic_parser.py @@ -73,6 +73,7 @@ class GenericParser(BaseParser): fallback_selectors = [ # Product-specific URLs "a[href*='/produit']", + "a[href*='/products/']", # Shopify "a[href*='/product']", "a[href*='/p/']", "a[href*='/item']", @@ -82,9 +83,13 @@ class GenericParser(BaseParser): ".product-card a[href]", ".product-item a[href]", "[class*='product'] a[href]", + # Shopify specific + "a.product-card__link", + "a[href*='/collections/']", # Generic structure "article[class*='product'] a", "div[class*='product'] a", + "li[class*='product'] a", # Very generic (last resort) "a[class*='product']", ]