""" Scrape brand logos from the web. Tries Clearbit Logo API first, falls back to scraping the homepage. Outputs brand_logos.json for Go to read. """ import json import os import sys import urllib.request import urllib.error import ssl import re # ── Brand → domain mapping ────────────────────────────────── BRANDS = { "Armstrong": "armstrongflooring.com", "Bruce": "bruce.com", "COREtec": "coretecfloors.com", "Daltile": "daltile.com", "Karndean": "karndean.com", "LifeProof": "lifeproof.com", "Mohawk Flooring": "mohawkflooring.com", "MSI Surfaces": "msisurfaces.com", "Pergo": "pergo.com", "Shaw Floors": "shawfloors.com", } OUTPUT_DIR = "static/brand_logos" OUTPUT_JSON = "brand_logos.json" ssl_ctx = ssl.create_default_context() ssl_ctx.check_hostname = False ssl_ctx.verify_mode = ssl.CERT_NONE def fetch_url(url, timeout=10): """Fetch URL and return response data.""" try: req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}) resp = urllib.request.urlopen(req, timeout=timeout, context=ssl_ctx) return resp.read(), resp.getcode() except Exception as e: print(f" [!] Failed: {e}") return None, 0 def try_clearbit(domain): """Try Clearbit Logo API: https://logo.clearbit.com/{domain}""" url = f"https://logo.clearbit.com/{domain}" print(f" Trying Clearbit: {url}") data, code = fetch_url(url) if data and code == 200: return data, "png" return None, None def try_homepage_favicon(domain): """Try to find logo from homepage HTML (og:image or favicon).""" url = f"https://{domain}" print(f" Fetching homepage: {url}") html_bytes, code = fetch_url(url) if not html_bytes: return None, None html = html_bytes.decode("utf-8", errors="ignore") # Try og:image first m = re.search(r']+property=["\']og:image["\'][^>]+content=["\']([^"\']+)', html) if m: img_url = m.group(1) if img_url.startswith("//"): img_url = "https:" + img_url elif img_url.startswith("/"): img_url = url + img_url print(f" Found og:image: {img_url}") data, _ = fetch_url(img_url) if data: ext = img_url.split(".")[-1].split("?")[0] or "png" return data, ext # Try favicon m = re.search(r']+rel=["\'](?:icon|shortcut icon)["\'][^>]+href=["\']([^"\']+)', html) if m: favicon_url = m.group(1) if favicon_url.startswith("//"): favicon_url = "https:" + favicon_url elif favicon_url.startswith("/"): favicon_url = url + favicon_url print(f" Found favicon: {favicon_url}") data, _ = fetch_url(favicon_url) if data: return data, "ico" # Try /favicon.ico favicon_url = f"https://{domain}/favicon.ico" print(f" Trying: {favicon_url}") data, _ = fetch_url(favicon_url) if data: return data, "ico" return None, None def try_wikipedia(name): """Try to get logo from Wikipedia.""" search_name = name.replace(" ", "_") # Try the Wikipedia REST API api_url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{search_name}" print(f" Trying Wikipedia: {api_url}") data, code = fetch_url(api_url) if data and code == 200: try: info = json.loads(data) thumb = info.get("thumbnail", {}).get("source") if thumb: print(f" Found Wikipedia thumbnail: {thumb}") img_data, _ = fetch_url(thumb) if img_data: return img_data, "png" except Exception: pass # Try infobox image via action=query query_url = f"https://en.wikipedia.org/w/api.php?action=query&titles={search_name}&prop=pageimages&format=json&pithumbsize=200" print(f" Trying Wikipedia query: {query_url}") data, code = fetch_url(query_url) if data and code == 200: try: result = json.loads(data) pages = result.get("query", {}).get("pages", {}) for page in pages.values(): thumb = page.get("thumbnail", {}).get("source") if thumb: print(f" Found: {thumb}") img_data, _ = fetch_url(thumb) if img_data: return img_data, "png" except Exception: pass return None, None def main(): os.makedirs(OUTPUT_DIR, exist_ok=True) results = {} for brand, domain in BRANDS.items(): print(f"\n{'='*60}") print(f"Brand: {brand} ({domain})") img_data = None ext = "png" # Strategy 1: Clearbit img_data, ext = try_clearbit(domain) # Strategy 2: Homepage og:image / favicon if not img_data: img_data, ext = try_homepage_favicon(domain) # Strategy 3: Wikipedia if not img_data: img_data, ext = try_wikipedia(brand) if img_data and len(img_data) > 100: filename = f"{brand.lower().replace(' ', '_').replace('.', '')}.{ext}" filepath = os.path.join(OUTPUT_DIR, filename) with open(filepath, "wb") as f: f.write(img_data) local_url = f"/static/brand_logos/{filename}" print(f" [OK] Saved: {filepath} ({len(img_data)} bytes)") results[brand] = local_url else: print(f" [FAIL] No logo found for {brand}") results[brand] = "" # Write JSON mapping json_path = os.path.join(os.path.dirname(__file__) or ".", "..", "..", OUTPUT_JSON) # Go binary runs from project root, output to root root_json_path = OUTPUT_JSON with open(root_json_path, "w", encoding="utf-8") as f: json.dump(results, f, indent=2, ensure_ascii=False) print(f"\n{'='*60}") print(f"Logo mapping saved to {root_json_path}") print(f"Logos saved to {OUTPUT_DIR}/") print(json.dumps(results, indent=2, ensure_ascii=False)) if __name__ == "__main__": main()