diff --git a/brancheneinstufung.py b/brancheneinstufung.py index b785a2c8..16093159 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -3673,81 +3673,87 @@ class WikipediaScraper: ) processed_titles = set() original_search_name_norm = normalize_company_name(company_name) # Einmal normalisieren + processed_titles = set() - def check_page_recursive(title_to_check, current_depth): - page_object_to_return = None # Explizit initialisieren - if title_to_check in processed_titles: - self.logger.debug(f" -> Titel '{title_to_check[:100]}...' bereits verarbeitet. Übersprungen.") + + + def check_page_recursive(title_to_check, original_search_name_for_validation, current_depth_val): + # Beachten Sie die Parameternamen hier. + # original_search_name_for_validation wird für die Ähnlichkeitsprüfung mit Optionen verwendet. + # company_name (aus der äußeren Funktion) wird für self._validate_article verwendet. + + if title_to_check in processed_titles: + self.logger.debug(f" -> Titel '{title_to_check[:100]}...' bereits verarbeitet. Übersprungen.") + return None + if current_depth_val > max_recursion_depth: + self.logger.debug(f" -> Maximale Rekursionstiefe ({max_recursion_depth}) für '{title_to_check[:100]}...' erreicht. Stoppe.") + return None + + processed_titles.add(title_to_check) + self.logger.debug(f" -> Pruefe potenziellen Artikel: '{title_to_check[:100]}...' (Tiefe: {current_depth_val})") + + normalized_option_title_local = normalize_company_name(title_to_check) # Lokale Variable + title_similarity_to_original_local = fuzzy_similarity(normalized_option_title_local, original_search_name_for_validation) + + if current_depth_val > 0 and title_similarity_to_original_local < 0.3: + self.logger.debug(f" -> Option '{title_to_check[:100]}' hat zu geringe Ähnlichkeit ({title_similarity_to_original_local:.2f}) zum Original-Suchbegriff '{original_search_name_for_validation}'. Übersprungen.") + return None + + page = None + try: + page = wikipedia.page(title_to_check, auto_suggest=False, preload=False, redirect=True) + if self._validate_article(page, company_name, website): # Hier wird der company_name der äußeren Funktion verwendet + self.logger.info(f" -> Titel '{page.title[:100]}...' erfolgreich validiert!") + return page # Gibt das Page-Objekt zurück + else: + self.logger.debug(f" -> Titel '{page.title[:100]}...' nicht validiert.") + return None # Nicht validiert + + except wikipedia.exceptions.DisambiguationError as e_disamb: + self.logger.info( + f" -> Begriffsklaerung '{e_disamb.title}' gefunden für '{title_to_check[:100]}...' (Tiefe {current_depth_val}). " + f"Pruefe Optionen (max 3 nach Filter): {str(e_disamb.options[:10])[:200]}..." + ) + if current_depth_val >= max_recursion_depth: + self.logger.warning(f" -> Max Rekursionstiefe für Begriffsklärung '{e_disamb.title}' erreicht.") return None - if current_depth > max_recursion_depth: - self.logger.debug(f" -> Maximale Rekursionstiefe ({max_recursion_depth}) für '{title_to_check[:100]}...' erreicht. Stoppe.") - return None - - processed_titles.add(title_to_check) - self.logger.debug(f" -> Pruefe potenziellen Artikel: '{title_to_check[:100]}...' (Tiefe: {current_depth})") - try: - # preload=False, um nicht sofort alles zu laden - page = wikipedia.page(title_to_check, auto_suggest=False, preload=False, redirect=True) - - # Validierung durchführen - if self._validate_article(page, company_name, website): # company_name ist der ursprüngliche Suchname - self.logger.info(f" -> Titel '{page.title[:100]}...' erfolgreich validiert!") - page_object_to_return = page # Potenziell guter Artikel - else: - self.logger.debug(f" -> Titel '{page.title[:100]}...' nicht validiert.") - page_object_to_return = None # Nicht validiert + relevant_options = [] + # ... (Filterlogik für Optionen) + for option_title_iter in e_disamb.options: # Iterationsvariable umbenannt + # ... (Ihre Filterlogik hier, die relevant_options füllt) + option_lower_iter = option_title_iter.lower() # Lokale Variable + if not any(ex in option_lower_iter for ex in [ + "(person)", "(familienname)", # etc. + ]) and len(option_title_iter) < 80: + normalized_option_iter = normalize_company_name(option_title_iter) + if fuzzy_similarity(normalized_option_iter, original_search_name_for_validation) > 0.3: + relevant_options.append(option_title_iter) - except wikipedia.exceptions.DisambiguationError as e_disamb: - self.logger.info( - f" -> Begriffsklaerung '{e_disamb.title}' gefunden für '{title_to_check[:100]}...' (Tiefe {current_depth}). " - f"Pruefe Optionen (max 3 nach Filter): {str(e_disamb.options[:10])[:200]}..." # Zeige nur die ersten paar Optionen - ) - if current_depth >= max_recursion_depth: - self.logger.warning(f" -> Max Rekursionstiefe für Begriffsklärung '{e_disamb.title}' erreicht. Stoppe weitere Auflösung.") - return None # Wichtig: None zurückgeben + for option_to_check_further_iter in relevant_options[:3]: + # Wichtig: original_search_name_for_validation weitergeben + validated_page_from_option_iter = check_page_recursive(option_to_check_further_iter, original_search_name_for_validation, current_depth_val + 1) + if validated_page_from_option_iter: + return validated_page_from_option_iter + return None + # ... (andere except-Blöcke) ... + except Exception as e_page: # Allgemeinerer Fehler + if page and hasattr(page, 'title') and page.title: # Sicherstellen, dass page.title existiert + title_for_log = page.title[:100] + else: + title_for_log = title_to_check[:100] - relevant_options = [] - for option_title in e_disamb.options: - option_lower = option_title.lower() - # Verbesserte Filterung - if not any(ex in option_lower for ex in [ - "(person)", "(familienname)", "(vorname)", "(künstlername)", "liste von", - "(ort)", "(geographie)", "(stadt)", "(gemeinde)", "(landkreis)", "river", "bayou", - "liste ", "liste)", "(album)", "(film)", "(lied)", "(manga)", " (Begriffsklärung)", - "(einheit)", "(maßeinheit)", " (Begriffsklärung)", " (Begriffsklärungshinweis)", "begriffsklärung", - " (surname)", " (given name)", " (band)", " (musician)", " (album)", " (song)", - " (film)", " (tv series)", " (character)", " (comics)", " (disambiguation)" # Englische Varianten - ]) and len(option_title) < 80: # Kürzere Titel bevorzugen - # Zusätzlicher Check: Ähnlichkeit der Option zum *Original* Suchbegriff - normalized_option = normalize_company_name(option_title) - if fuzzy_similarity(normalized_option, original_search_name_norm) > 0.3: # Mindestähnlichkeit - relevant_options.append(option_title) - - self.logger.debug(f" -> {len(relevant_options)} potenziell relevante Optionen für '{e_disamb.title}' nach Filterung: {str(relevant_options[:5])[:200]}...") - - # Nur die Top N relevantesten Optionen prüfen (z.B. die ersten 3) - for i, option_to_check_further in enumerate(relevant_options[:3]): # << HIER LIMITIEREN - validated_page_from_option = check_page_recursive(option_to_check_further, current_depth + 1) - if validated_page_from_option: - self.logger.info(f" -> Option '{option_to_check_further[:100]}...' aus Begriffsklaerung erfolgreich validiert!") - return validated_page_from_option # Gib die erste valide Seite zurück - - self.logger.debug(f" -> Keine passende/validierte Unternehmens-Option in Begriffsklaerung '{e_disamb.title}' gefunden.") - return None # Keine valide Option gefunden - - except wikipedia.exceptions.PageError: - self.logger.debug(f" -> Seite '{title_to_check[:100]}...' nicht gefunden (PageError).") - return None - except (requests.exceptions.RequestException, wikipedia.exceptions.WikipediaException) as e_req: - self.logger.warning(f" -> Netzwerk/API-Fehler bei Verarbeitung von '{title_to_check[:100]}...': {e_req}") - return None - except Exception as e_page: - # Aggressiveres Abfangen von Fehlern beim Zugriff auf page-Objekt - self.logger.error(f" -> Unerwarteter Fehler bei Verarbeitung von Seite '{title_to_check[:100]}...': {type(e_page).__name__} - {e_page}") - self.logger.debug(traceback.format_exc()) + if "extlinks" in str(e_page).lower(): + self.logger.warning(f" -> KeyError ('extlinks') beim Verarbeiten von Titel '{title_for_log}...'. Übersprungen.") return None + self.logger.error( + f" -> Unerwarteter Fehler bei Verarbeitung von Seite '{title_for_log}...': " + f"{type(e_page).__name__} - {e_page}" + ) + self.logger.debug(traceback.format_exc()) + return None + return None # Fallback, falls kein Pfad ein Ergebnis liefert return page_object_to_return # Gibt validierte Seite oder None zurück