From 6a299e92c9ab40906abfe030c70cf47cae73a08a Mon Sep 17 00:00:00 2001 From: Floke Date: Sun, 1 Jun 2025 14:44:48 +0000 Subject: [PATCH] bugfix --- brancheneinstufung.py | 159 ++++++++++++++++++++++++++---------------- 1 file changed, 99 insertions(+), 60 deletions(-) diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 4e0e8414..4cf03835 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -3652,7 +3652,7 @@ class WikipediaScraper: return result @retry_on_failure - def search_company_article(self, company_name, website=None, max_recursion_depth=2): # max_recursion_depth hinzugefügt + def search_company_article(self, company_name, website=None, max_recursion_depth=1): # max_recursion_depth hinzugefügt """ Sucht einen passenden Wikipedia-Artikel fuer das Unternehmen und gibt das wikipedia.WikipediaPage Objekt zurueck, wenn ein relevanter und validierter @@ -3671,82 +3671,121 @@ class WikipediaScraper: f"Starte Wikipedia-Suche fuer '{company_name[:100]}...' " f"(Website: {website[:100]}...) mit Begriffen: {search_terms}" ) - processed_titles = set() # Verhindert Endlosschleifen bei zirkulären Redirects/Disambiguations + processed_titles = set() + original_search_name_norm = normalize_company_name(company_name) # Einmal normalisieren - # Innere Hilfsfunktion mit Rekursionstiefe def check_page_recursive(title_to_check, current_depth): - if title_to_check in processed_titles or current_depth > max_recursion_depth: - if title_to_check in processed_titles: - self.logger.debug(f" -> Titel '{title_to_check[:100]}...' bereits verarbeitet oder Rekursionstiefe überschritten.") + 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.") 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: - page = wikipedia.page(title_to_check, auto_suggest=False, preload=True) + # 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!") - return page + page_object_to_return = page # Potenziell guter Artikel else: - self.logger.debug(f" -> Titel '{title_to_check[:100]}...' nicht validiert.") - return None + self.logger.debug(f" -> Titel '{page.title[:100]}...' nicht validiert.") + page_object_to_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}). " + 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 + + 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 wikipedia.exceptions.DisambiguationError as e_inner: - self.logger.info( - f" -> Begriffsklaerung '{title_to_check[:100]}...' gefunden (Tiefe {current_depth}). " - f"Pruefe Optionen: {str(e_inner.options)[:100]}..." - ) - if current_depth >= max_recursion_depth: - self.logger.warning(f" -> Maximale Rekursionstiefe ({max_recursion_depth}) für Begriffsklärung '{title_to_check[:100]}...' erreicht. Stoppe weitere Auflösung.") - return None - - # Filtere und priorisiere Optionen - # Man könnte hier noch intelligenter filtern, z.B. Optionen bevorzugen, die "(Unternehmen)" enthalten - valid_options = [] - for option in e_inner.options: - option_lower = option.lower() - # Erweiterte Negativ-Filterung - if not any( - ex in option_lower - for ex in [ - "(person)", "(familienname)", "(vorname)", "(künstlername)", - "(ort)", "(geographie)", "(stadt)", "(gemeinde)", "(landkreis)", - "liste ", "liste)", "(album)", "(film)", "(lied)", "(manga)", - "(einheit)", "(maßeinheit)", "(begriffsklärung)", "Begriffsklärung)" # Begriffsklärungen explizit ausschließen für direkte Rekursion - ] - ) and len(option) < 100 : # Vermeide extrem lange Options-Strings - valid_options.append(option) - - self.logger.debug(f" -> {len(valid_options)} potenziell relevante Optionen für '{title_to_check[:100]}...' nach Filterung: {str(valid_options)[:200]}...") - - for option in valid_options: - # Rekursiver Aufruf mit erhöhter Tiefe - validated_option_page = check_page_recursive(option, current_depth + 1) - if validated_option_page: - self.logger.info( - f" -> Option '{option[:100]}...' aus Begriffsklaerung erfolgreich validiert!" - ) - return validated_option_page - - self.logger.debug( - f" -> Keine passende/validierte Unternehmens-Option in Begriffsklaerung '{title_to_check[:100]}...' gefunden." - ) - return None # Wichtig: Gibt None zurück, wenn keine der Optionen erfolgreich war except (requests.exceptions.RequestException, wikipedia.exceptions.WikipediaException) as e_req: - self.logger.warning( - f" -> Netzwerk/API-Fehler beim Laden/Validieren von '{title_to_check[:100]}...': " - f"{type(e_req).__name__} - {e_req}. Ueberspringe diesen Titel." - ) + self.logger.warning(f" -> Netzwerk/API-Fehler bei Verarbeitung von '{title_to_check[:100]}...': {e_req}") return None except Exception as e_page: - self.logger.error( - f" -> Unerwarteter Fehler bei Verarbeitung von Titel '{title_to_check[:100]}...': " - f"{type(e_page).__name__} - {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()) return None + + return page_object_to_return # Gibt validierte Seite oder None zurück + + # --- Hauptlogik von search_company_article --- + # Direkter Match mit dem ursprünglichen Firmennamen + self.logger.debug(f" -> Versuche direkten Match fuer '{company_name[:100]}...' mit check_page_recursive...") + page_found = check_page_recursive(company_name, original_search_name_norm, current_depth=0) + if page_found: + return page_found + + # Suche mit generierten Begriffen + self.logger.debug(f" -> Kein direkter Treffer/validiert. Starte Suche mit generierten Begriffen via check_page_recursive: {search_terms}") + for term in search_terms: + if term == company_name: continue # Bereits oben geprüft + self.logger.debug(f" -> Versuche Suchbegriff: '{term[:100]}...' mit check_page_recursive...") + page_found = check_page_recursive(term, original_search_name_norm, current_depth=0) # Starte Rekursion für den Term + if page_found: + return page_found + + # Die wikipedia.search() wird hier nicht mehr primär genutzt, + # da check_page_recursive schon die wikipedia.page()-Suche macht. + # Falls check_page_recursive(term) nichts findet, könnten wir hier optional + # noch wikipedia.search() als Fallback nutzen, aber mit Vorsicht. + # Fürs Erste lassen wir es weg, um die API-Calls zu reduzieren. + # + # try: + # search_results = wikipedia.search(term, results=getattr(Config, 'WIKIPEDIA_SEARCH_RESULTS', 2)) # Weniger Ergebnisse + # if search_results: + # self.logger.debug(f" -> Fallback wikipedia.search für '{term[:100]}...' ergab: {search_results}") + # for title in search_results: + # page_found = check_page_recursive(title, original_search_name_norm, current_depth=0) + # if page_found: + # return page_found + # except Exception as e_search: + # self.logger.error(f"Fehler waehrend Fallback wikipedia.search() fuer '{term[:100]}...': {e_search}") + + self.logger.warning(f"Kein passender & validierter Wikipedia-Artikel fuer '{company_name[:100]}...' gefunden nach allen Versuchen.") + return None # Direkter Match mit dem ursprünglichen Firmennamen self.logger.debug(f" -> Versuche direkten Match fuer '{company_name[:100]}...'...")