#!/usr/bin/env python3 """Spiele-Offensive Top-30 mit korrekten Bildern aus den Listing-Seiten.""" import re, sys, urllib.request from datetime import datetime from html import unescape UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36" NOW = datetime.now().strftime("%d.%m.%Y %H:%M") PID = "505" OUT = "/home/hermes/workspace/spiele_offensive_top30.html" def fetch(url, timeout=15): req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=timeout) as r: raw = r.read() try: return raw.decode("utf-8") except: return raw.decode("iso-8859-1", errors="replace") def fix(s): for a,b in [("ü","ü"),("ö","ö"),("ä","ä"),("ß","ß"),("Ü","Ü"),("Ä","Ä"),("Ö","Ö"),("é","é")]: s = s.replace(a,b) return unescape(s.replace("&","&").replace(""",'"')).strip() # ── Build aid→image_filename map from Sonderangebote listing pages ── # The HTML pattern:
print("Scraping Sonderangebote...", file=sys.stderr) aid_img = {} for page in range(10): try: h = fetch(f"https://www.spiele-offensive.de/Kat/Sonderangebote.html?sse={page}", 15) except Exception as e: print(f" p{page}: {e}", file=sys.stderr); continue # Clean regex: capture aid from onclick + filename from img src for m in re.finditer( r'registerItemSelection\(dataLayer,\s*(\d+)\s*,.*?' r']*src='[^']*/([^/\"'\s?]+)'", h) if m: return m.group(1).strip() # Alternative: any width=450 image m = re.search(r"width=450/([^\"'\s?]+)", h) if m: return m.group(1).strip() # Last resort: first mediaservice image that's not 100x100 for m in re.finditer(r'src="https://mediaservice[^"]*/([^/"\s?]+)"', h): fn = m.group(1) if 'size=100x100' not in fn and len(fn) > 3: return fn.strip() except: pass return None # ── Extract deals from existing deals HTML ── print("Reading existing deals...", file=sys.stderr) with open("/home/hermes/workspace/spiele_offensive_deals.html") as f: html = f.read() deals = [] for m in re.finditer( r'
([^<]+)
.*?' r'
]*>([^<]+)
.*?' r'([^<]*).*?' r'([^<]+).*?' r'UVP {old} €' bc = "#b12704" if rabatt >= 80 else ("#e63946" if rabatt >= 60 else "#cc0c39") if aid in aid_img: isrc = img_url(aid, aid_img[aid]) igh = f'' else: igh = '
?
' cards += f"""
{igh}
{name} {new} €{old_h} -{rabatt}% {saved_s} Zu Spiele-Offensive →
""" out_html = f""" Top 30 Brettspiel-Angebote — Spiele-Offensive.de

Top 30 Brettspiel-Angebote auf Spiele-Offensive.de

Stand: {NOW} · Sortiert nach Rabatt · Preise inkl. MwSt. · Affiliate-Links (PID {PID}) · Bilder: HappyShops CDN

{cards}
""" with open(OUT, "w") as f: f.write(out_html) import subprocess c = subprocess.run(["grep", "-c", "mediaservice", OUT], capture_output=True, text=True) imgs = c.stdout.strip() print(f"Done: {len(top30)} deals, {imgs} with images, {len(out_html)} bytes", file=sys.stderr) print(f"FILE:{OUT}")