"""Adapter für https://www.spielbox.de/neuheiten-neue-spiele (Joomla-Blog). Seitenstruktur (Stand Analyse August 2026): - Pro Beitrag ein `div.item` mit Titel-Link in `div.page-header h2 a`, Beitragsdatum (TT.MM.JJJJ) im ersten Absatz (`p > strong`). - Pagination über `.pagination`-Links der Form `?start=N` (6 Beiträge je Seite) — alle Seiten werden durchlaufen, bis keine neue Seite mehr gefunden wird. - Verlag: Heuristik — Präfix des Titels vor dem Doppelpunkt (z. B. „Pegasus Spiele: Next Station Berlin“); fehlt er, bleibt der Verlag leer. Ein Autor wird auf dieser Liste nicht strukturiert mitgeliefert. """ from __future__ import annotations import re from bs4 import BeautifulSoup from .basis import QuellenAdapter, QuellenTreffer, bild_aus_element DATUM_MUSTER = re.compile(r"(\d{2}\.\d{2}\.\d{4})") class SpielboxQuelle(QuellenAdapter): name = "spielbox" anzeigename = "spielbox.de Neuheiten" start_urls = ("https://www.spielbox.de/neuheiten-neue-spiele",) def seite_verarbeiten(self, inhalt: bytes, url: str): suppe = BeautifulSoup(inhalt, "html.parser") treffer: list[QuellenTreffer] = [] for element in suppe.select("div.item"): kopf_link = element.select_one("div.page-header h2 a") or element.find("h2") if kopf_link is None: continue # Strukturänderung: Beitrag überspringen, Lauf hält an titel = kopf_link.get_text(" ", strip=True) if not titel: continue href = kopf_link.get("href") if hasattr(kopf_link, "get") else None quellen_url = _absolute_url(href, url) or url datum = None for absatz in element.find_all("p"): strong = absatz.find("strong") if strong is not None: fund = DATUM_MUSTER.search(strong.get_text(strip=True)) if fund: datum = fund.group(1) break verlag = _verlag_aus_titel(titel) treffer.append( QuellenTreffer( titel=titel, verlag=verlag, autor=None, erscheinungsdatum_oder_quartal=datum, quellen_url=quellen_url, bild_url=bild_aus_element(element, url), ) ) folge_links: list[str] = [] for link in suppe.select(".pagination a[href]"): ziel = _absolute_url(link["href"], url) # Nur echte Paginierung dieser Liste folgen (?start=N), # nicht den Druck-/Sprung-Links. if ziel and "start=" in ziel: folge_links.append(ziel) return treffer, folge_links def _verlag_aus_titel(titel: str) -> str | None: """„Verlag: Spielname“ → Verlag als Präfix vor dem Doppelpunkt.""" if ":" not in titel: return None praefix = titel.split(":", 1)[0].strip() if 0 < len(praefix) <= 60: return praefix return None def _absolute_url(href: str | None, basis_url: str) -> str | None: if not href: return None from urllib.parse import urljoin return urljoin(basis_url, href)