"""Adapter für cliquenabend.de Messe-Eventseiten (z. B. SPIEL 2025 Essen). Seite: …/events/130000-SPIEL-2025-Essen.html (große Einzelseite, ~4 MB). Struktur (Stand Analyse August 2026): Eine einzige Tabelle mit der Kopfzeile Update | Verlag | Stand | Spiel | Autor; eine Zeile pro Spiel. Titel steht in `a[href^="/spiele/"] > b`, Verlage in fett formatierten `div`-Blöcken der Verlagsspalte, das Update-Datum in der Form TT.MM.JJ. Die Seite ist nicht paginiert. """ 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{2})\b") BASIS_URL = "https://www.cliquenabend.de" class CliquenabendQuelle(QuellenAdapter): name = "cliquenabend" anzeigename = "Cliquenabend Messe-Übersicht" start_urls = ("https://www.cliquenabend.de/events/130000-SPIEL-2025-Essen.html",) def seite_verarbeiten(self, inhalt: bytes, url: str): suppe = BeautifulSoup(inhalt, "html.parser") treffer: list[QuellenTreffer] = [] tabelle = suppe.find("table") if tabelle is None: return [], [] # Strukturänderung: nichts tun, kein Crash for zeile in tabelle.find_all("tr"): zellen = zeile.find_all("td") if len(zellen) < 5: continue if zellen[0].get_text(strip=True).lower() == "update": continue # Kopfzeile treffer.append(self._zeile(zellen, url)) return [t for t in treffer if t is not None], [] def _zeile(self, zellen, url: str) -> QuellenTreffer | None: spiel_zelle = zellen[3] titel_link = spiel_zelle.find("a", href=re.compile(r"^/spiele/")) titel = None quellen_url = url if titel_link is not None: fett = titel_link.find("b") titel = (fett or titel_link).get_text(" ", strip=True) href = titel_link.get("href") if href: from urllib.parse import urljoin quellen_url = urljoin(BASIS_URL, href) if not titel: return None verlag = _verlage(zellen[1]) autor = zellen[4].get_text(" ", strip=True) or None datum = None jahr_text = zellen[0].get_text(strip=True) fund = DATUM_MUSTER.search(jahr_text) if fund: # Datum so übernehmen, wie es in der Quelle steht (z. B. „15.10.25“). datum = fund.group(0) return QuellenTreffer( titel=titel, verlag=verlag, autor=autor, erscheinungsdatum_oder_quartal=datum, quellen_url=quellen_url, bild_url=bild_aus_element(spiel_zelle, quellen_url), ) def _verlage(zelle) -> str | None: """Verlagsspalte: fett formatierte `div`-Blöcke enthalten die Namen.""" namen = [ div.get_text(" ", strip=True) for div in zelle.find_all("div") if div.get_text(" ", strip=True) ] if not namen: roh = zelle.get_text(" ", strip=True) namen = [teil for teil in (roh.split(",") if roh else []) if teil.strip() and teil.strip().lower() != "profil"] bereinigt = [] for name in namen: name = name.strip().rstrip(",").strip() # „Piatnik Profil ,“ → Profil-Link-Text hängt am Namen; abschneiden. if name.lower().endswith(" profil"): name = name[: -len(" Profil")].strip() if name and name.lower() != "profil": bereinigt.append(name) return ", ".join(bereinigt) if bereinigt else None