#!/usr/bin/env python3
"""Fetch Amazon board game deals and compare with brettspielpreise.de price histories.
Final version with validated matches."""
import re, json, time, urllib.request, urllib.parse, ssl
# ---- Step 1: Parse HTML ----
html_path = "/home/hermes/workspace/amazon_deals_2026-06-05.html"
with open(html_path, "r", encoding="utf-8") as f:
html = f.read()
deal_blocks = re.findall(
r'
'
r'(.*?)
',
html, re.DOTALL
)
print(f"Found {len(deal_blocks)} deal blocks")
deals = []
for block in deal_blocks:
name_match = re.search(r'(.*?)', block)
name = name_match.group(1).strip() if name_match else "Unknown"
price_match = re.search(r'font-weight:bold;">(\d+[.,]\d+) €', block)
price = float(price_match.group(1).replace(",", ".")) if price_match else None
uvp_match = re.search(r'UVP (\d+[.,]\d+) €', block)
uvp = float(uvp_match.group(1).replace(",", ".")) if uvp_match else None
asin_match = re.search(r'/dp/([A-Z0-9]+)', block)
asin = asin_match.group(1) if asin_match else None
url_match = re.search(r'href="(https://www\.amazon\.de/dp/[^"]+)"', block)
url = url_match.group(1) if url_match else f"https://www.amazon.de/dp/{asin}?tag=60pro05-21"
deals.append({"name": name, "amazon_price": price, "uvp": uvp, "asin": asin, "url": url})
# ---- Step 2: Filter ----
FILTER_KEYWORDS = [
"schwarzer peter", "skat", "rommé", "romme", "bridge canasta",
"top trumps", "wetfussballstars",
"uno ", "uno flip", "uno show", "uno teams", "phase 10",
]
filtered = []
for d in deals:
name_lower = d["name"].lower()
if not any(kw in name_lower for kw in FILTER_KEYWORDS):
filtered.append(d)
else:
kw = next(kw for kw in FILTER_KEYWORDS if kw in name_lower)
print(f" SKIP: {d['name'][:70]}... [{kw}]")
print(f"After filtering: {len(filtered)} deals")
# ---- Step 3: HTTP helpers ----
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
def http_get(url):
req = urllib.request.Request(url, headers={
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
})
try:
with urllib.request.urlopen(req, timeout=15, context=ctx) as resp:
return resp.read().decode("utf-8", errors="replace")
except Exception:
return None
# ---- Search terms with specific overrides ----
SEARCH_CONFIG = [
# (amazon_name_keyword, search_term)
("Maus reiß aus", "Maus reiß aus"),
("Die Verräter", "Die Verräter Brettspiel"),
("Jumanji", "Jumanji Familienspiel"),
("Monsterjäger", "Monsterjäger Schmidt"),
("Sweet Takes", "Sweet Takes"),
("My City", "My City Kosmos"),
("Evacuation", "Evacuation"),
("STILLE POST EXTREM", "Stille Post Extrem"),
("Dog", "Dog Royal"),
("THE MIND", "The Mind"),
("Catan", "Catan"),
("Leben in Reterra", "Leben in Reterra"),
("Sagaland", "Sagaland"),
("Hitster", "Hitster"),
("Outsmarted", "Outsmarted"),
("Monopoly Harry Potter", "Monopoly Harry Potter"),
("Die Magischen Schlüssel", "Die Magischen Schlüssel"),
("Scrabble Zwei in Eins", "Scrabble"),
("Das verrückte Labyrinth", "Das verrückte Labyrinth"),
("Funkelschatz", "Funkelschatz"),
("Leiterspiel", "Leiterspiel Schmidt"),
("Ligretto", "Ligretto"),
]
FALLBACK_SEARCH = {
"Die Verräter": ["the traitors die verrater"],
"Dog": ["Dog Den letzten beissen die Hunde"],
"Sweet Takes": ["Sweet Takes Hasbro"],
"Die Magischen Schlüssel": ["Magischen Schlüssel Game Factory"],
}
def get_search_terms(name):
terms = []
for key, val in SEARCH_CONFIG:
if key.lower() in name.lower():
terms.append(val)
break
if not terms:
words = name.replace("-", " ").replace("–", " ").replace(",", " ").split()
stop = {"das", "die", "der", "den", "für", "und", "mit", "von", "ein", "eine", "einen", "ab", "des", "dem"}
meaningful = [w for w in words if w.lower() not in stop and len(w) > 1 and not w.isdigit()]
terms.append(" ".join(meaningful[:3]))
for key, fbs in FALLBACK_SEARCH.items():
if key.lower() in name.lower():
for fb in fbs:
if fb not in terms:
terms.append(fb)
return terms
def search_brettspielpreise(search_term):
url = f"https://brettspielpreise.de/item/search?search={urllib.parse.quote(search_term)}"
body = http_get(url)
if not body:
return []
show_links = re.findall(r'/item/show/(\d+)/([^"]+)', body)
items, seen = [], set()
for item_id, slug in show_links:
if item_id not in seen:
seen.add(item_id)
history_url = f"https://brettspielpreise.de/item/history/{item_id}/{slug}"
items.append((item_id, urllib.parse.unquote(slug), history_url))
return items[:5]
def get_price_history(history_url):
body = http_get(history_url)
if not body:
return None
idx = body.find('datasets')
if idx == -1:
return None
s = body.rfind('