From b5eac962b06aa16774ede47a543e0262dae130df Mon Sep 17 00:00:00 2001 From: Floke Date: Fri, 1 Aug 2025 11:11:37 +0000 Subject: [PATCH] erweiterung normalize URL --- helpers.py | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/helpers.py b/helpers.py index c700337b..84bd4a61 100644 --- a/helpers.py +++ b/helpers.py @@ -207,13 +207,23 @@ def create_log_filename(mode): # ============================================================================== def simple_normalize_url(url): - """Normalisiert URL zu domain.tld oder k.A. (ohne www, ohne Pfad).""" + """ + Bereinigt und normalisiert eine URL auf die reine Domain (z.B. 'example.com'). + Entfernt 'www.', Protokolle, Pfade und Query-Parameter. + NEU v2.1: Behandelt unsichtbare Zeichen und internationale Domains (Umlaute) korrekt. + """ logger = logging.getLogger(__name__) - if not url or not isinstance(url, str): return "k.A." - url = url.strip() - if not url or url.lower() == 'k.a.': return "k.A." + if not url or not isinstance(url, str): + return "k.A." - if not url.lower().startswith(("http://", "https://")): + # 1. Bereinige unsichtbare Zeichen, die oft Probleme machen + # \u200b = zero-width space, \xad = soft hyphen + url = url.replace('\u200b', '').replace('\xad', '').strip() + if not url or url.lower() == 'k.a.': + return "k.A." + + # 2. Füge ein Protokoll hinzu, falls es fehlt, damit urlparse funktioniert + if not re.match(r'^(http|https)://', url): url = "https://" + url try: @@ -223,34 +233,43 @@ def simple_normalize_url(url): logger.debug(f"URL '{url[:100]}...' konnte nicht sinnvoll geparst werden (leerer netloc).") return "k.A." + # Entferne Port-Informationen domain_part = domain_part.split(":", 1)[0] + # Entferne User-Info (user@domain.com) if '@' in domain_part: domain_part = domain_part.split('@', 1)[1] - + + # 3. KORRIGIERTE LOGIK: Zuerst in IDNA encodieren, dann als ASCII decodieren try: - domain_part = domain_part.encode('ascii').decode('idna') - except UnicodeDecodeError: - pass + # Das ist der entscheidende Schritt für Umlaute etc. + # 'lübeck.de' -> b'xn--lbeck-5wa.de' (bytes) + domain_part_encoded = domain_part.encode('idna') + # b'xn--lbeck-5wa.de' -> 'xn--lbeck-5wa.de' (string) + domain_part = domain_part_encoded.decode('ascii') + except UnicodeError as e: + logger.warning(f"Konnte Domain '{domain_part[:100]}' nicht nach IDNA konvertieren: {e}") + return "k.A. (Unicode-Fehler)" + # 4. Standard-Normalisierung domain_part = domain_part.lower() - if domain_part.startswith("www."): domain_part = domain_part[4:] + # 5. Finale Validierung if domain_part and '.' in domain_part: parts = domain_part.split('.') if len(parts) > 1 and parts[-1].isalpha() and len(parts[-1]) >= 2: return domain_part else: - logger.debug(f"URL '{url[:100]}...' normalisiert zu '{domain_part}', aber TLD-Pruefung schlug fehl.") + logger.debug(f"URL '{url[:100]}...' normalisiert zu '{domain_part}', aber TLD-Prüfung schlug fehl.") return "k.A." else: - logger.debug(f"URL '{url[:100]}...' normalisiert zu '{domain_part}', enthaelt keinen Punkt oder ist leer.") + logger.debug(f"URL '{url[:100]}...' normalisiert zu '{domain_part}', enthält keinen Punkt oder ist leer.") return "k.A." except Exception as e: - logger.error(f"Fehler bei URL-Normalisierung fuer '{url[:100]}...': {e}") - return "k.A. (Fehler Normalisierung)" + logger.error(f"Unerwarteter Fehler bei URL-Normalisierung für '{url[:100]}...': {e}") + return "k.A. (Fehler bei Normalisierung)" def normalize_string(s):