Cleanups for scrapers

This commit is contained in:
2026-04-10 10:04:20 -04:00
parent 0d5cc08bc0
commit 052a762182
15 changed files with 1411 additions and 567 deletions
+57 -10
View File
@@ -14,6 +14,50 @@ from src.browser import get_browser
logger = logging.getLogger(__name__)
def _find_image_in_json(data, depth=0) -> Optional[str]:
"""Recursively search a JSON dict for a Target image URL"""
if depth > 6:
return None
if isinstance(data, str):
if 'scene7.com' in data and not data.endswith('/'):
return data
return None
if isinstance(data, dict):
# Check known Target image keys first
for key in ('primary_image_url', 'base_url', 'url', 'src'):
val = data.get(key)
if isinstance(val, str) and 'scene7.com' in val:
return val
# Recurse, prioritizing enrichment/images paths
for key in ('enrichment', 'images', 'image'):
if key in data:
result = _find_image_in_json(data[key], depth + 1)
if result:
return result
for val in data.values():
result = _find_image_in_json(val, depth + 1)
if result:
return result
if isinstance(data, list) and data:
return _find_image_in_json(data[0], depth + 1)
return None
def _extract_img_url(img_tag) -> Optional[str]:
"""Extract real image URL from an img tag, skipping lazy-load placeholders"""
if not img_tag:
return None
for attr in ("src", "data-src", "data-lazy-src", "data-srcset", "srcset"):
val = img_tag.get(attr, "")
if not val:
continue
# srcset may contain multiple URLs - take the first
url = val.split()[0].rstrip(",")
if url and not url.startswith("data:") and len(url) > 20:
return url
return None
class TargetScraper(BaseScraper):
"""Scraper for Target.com"""
@@ -178,9 +222,8 @@ class TargetScraper(BaseScraper):
if fulfillment:
in_stock = fulfillment.get("is_out_of_stock_in_all_store_locations", True) is False
# Get image
images = data.get("images", [])
image_url = images[0].get("base_url") if images else None
# Get image - search all known Target JSON paths
image_url = _find_image_in_json(data)
return Product(
name=name,
@@ -247,11 +290,16 @@ class TargetScraper(BaseScraper):
break
parent = parent.find_parent()
# Try to find image
image_url = None
img = link.select_one("img")
if img:
image_url = img.get("src") or img.get("data-src")
# Try to find image - check inside link first, then walk up to parents
image_url = _extract_img_url(link.select_one("img"))
if not image_url:
parent = link.find_parent()
for _ in range(4):
if parent:
image_url = _extract_img_url(parent.select_one("img"))
if image_url:
break
parent = parent.find_parent()
# Check stock (assume in stock unless we see otherwise)
in_stock = True
@@ -307,8 +355,7 @@ class TargetScraper(BaseScraper):
in_stock = not out_of_stock
# Get image
img = card.select_one("img")
image_url = img.get("src") if img else None
image_url = _extract_img_url(card.select_one("img"))
# Extract product ID from URL
product_id = ""