From 01d04c1b8f4b28313a3384edb0ea3ebff04ab494 Mon Sep 17 00:00:00 2001 From: Floke Date: Sun, 20 Jul 2025 06:39:29 +0000 Subject: [PATCH] Robuste, lineare Wikipedia-Suche MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - REFACTOR: Die komplexe, rekursive `search_company_article`-Funktion in `wikipedia_scraper.py` wurde durch eine einfache, lineare Implementierung ersetzt. - FIX: Der hartnäckige `TypeError` bei der Parameter-Übergabe wurde durch die neue, übersichtlichere Struktur endgültig behoben. - FEATURE: Die Suche prüft nun intelligent eine Liste von Suchbegriffen und validiert jeden potenziellen Treffer, was die Zuverlässigkeit erhöht. --- wikipedia_scraper.py | 109 +++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 65 deletions(-) diff --git a/wikipedia_scraper.py b/wikipedia_scraper.py index 256796c4..0102bd2a 100644 --- a/wikipedia_scraper.py +++ b/wikipedia_scraper.py @@ -212,78 +212,57 @@ class WikipediaScraper: def search_company_article(self, company_name, website=None, parent_name=None, max_recursion_depth=1): """ - Sucht einen passenden Wikipedia-Artikel. Finale Version mit korrekter - Parameter-Weitergabe an die innere rekursive Funktion. + Sucht einen passenden Wikipedia-Artikel für ein Unternehmen durch eine lineare + Überprüfung generierter Suchbegriffe. Diese Methode ist einfacher und robuster + als die alte, rekursive Implementierung. """ - if not company_name or str(company_name).strip() == "": - self.logger.warning("Wikipedia search skipped: No company name provided.") + if not company_name: + self.logger.warning("Wikipedia-Suche übersprungen: Kein Firmenname angegeben.") return None search_terms = self._generate_search_terms(company_name, website) - if not search_terms: - self.logger.warning(f"Keine Suchbegriffe fuer '{company_name[:100]}...' generiert.") - return None + self.logger.info(f"Starte Wikipedia-Suche für '{company_name[:50]}...' mit Begriffen: {search_terms}") - self.logger.info(f"Starte Wikipedia-Suche fuer '{company_name[:100]}...' mit Begriffen: {search_terms}") - - processed_titles = set() - original_search_name_norm = normalize_company_name(company_name) - - # Die innere Funktion erbt `parent_name` aus dem Scope der äußeren Funktion. - def check_page_recursive(title_to_check, current_depth): - effective_max_depth = max_recursion_depth if max_recursion_depth is not None else 2 - if title_to_check in processed_titles or current_depth > effective_max_depth: - return None - - processed_titles.add(title_to_check) - self.logger.debug(f" -> Pruefe potenziellen Artikel: '{title_to_check[:100]}...' (Tiefe: {current_depth})") - - normalized_option_title_local = normalize_company_name(title_to_check) - title_similarity_to_original = fuzzy_similarity(normalized_option_title_local, original_search_name_norm) - - if current_depth > 0 and title_similarity_to_original < 0.3: - self.logger.debug(f" -> Option '{title_to_check[:100]}' hat zu geringe Ähnlichkeit ({title_similarity_to_original:.2f}). Übersprungen.") - return None - - page = None - try: - page = wikipedia.page(title_to_check, auto_suggest=False, preload=False, redirect=True) - # KORRIGIERTER AUFRUF: Übergibt jetzt 5 Argumente, wie von _validate_article erwartet. - if self._validate_article(page, company_name, website, parent_name): - self.logger.info(f" -> Titel '{page.title[:100]}...' erfolgreich validiert!") - return page - else: - return None - except wikipedia.exceptions.PageError: - self.logger.debug(f" -> Artikel '{title_to_check[:100]}' nicht gefunden (PageError).") - return None - except wikipedia.exceptions.DisambiguationError as e_disamb: - self.logger.info(f" -> Begriffsklaerung '{e_disamb.title}' gefunden (Tiefe {current_depth}). Pruefe Optionen...") - if current_depth >= effective_max_depth: return None - - relevant_options = [] - for option in e_disamb.options: - option_lower = option.lower() - if not any(ex in option_lower for ex in ["(person)", "(familienname)"]) and len(option) < 80: - if fuzzy_similarity(normalize_company_name(option), original_search_name_norm) > 0.3: - relevant_options.append(option) - - for option_to_check in relevant_options[:3]: - # Der rekursive Aufruf ist korrekt und einfach. - validated_page = check_page_recursive(option_to_check, current_depth + 1) - if validated_page: return validated_page - return None - except Exception as e_page: - title_for_log = page.title[:100] if page and hasattr(page, 'title') and page.title else title_to_check[:100] - self.logger.error(f" -> Unerwarteter Fehler bei Verarbeitung von Seite '{title_for_log}': {e_page}") - return None - - # Hauptlogik der Suche for term in search_terms: - page_found = check_page_recursive(term, 0) - if page_found: return page_found + self.logger.debug(f" -> Prüfe Suchbegriff: '{term}'") + try: + # Nutze die Suchfunktion von Wikipedia, die besser mit uneindeutigen Begriffen umgeht + # und oft direkt die richtige Seite vorschlägt. + suggested_titles = wikipedia.search(term, results=3) + if not suggested_titles: + continue - self.logger.warning(f"Kein passender & validierter Wikipedia-Artikel fuer '{company_name[:100]}...' gefunden.") + for title in suggested_titles: + self.logger.debug(f" -> Potenzieller Artikel gefunden: '{title}'") + try: + page = wikipedia.page(title, auto_suggest=False, redirect=True) + # Validiere den gefundenen Artikel mit dem vollen Kontext + if self._validate_article(page, company_name, website, parent_name): + self.logger.info(f" -> ERFOLG: Artikel '{page.title}' wurde für '{company_name}' validiert.") + return page + else: + # Artikel ist nicht relevant, fahre mit dem nächsten Vorschlag fort + continue + except wikipedia.exceptions.DisambiguationError as e: + self.logger.debug(f" -> Begriffsklärungsseite '{title}' gefunden. Prüfe Optionen...") + # Prüfe die ersten 3 Optionen der Begriffsklärungsseite + for option in e.options[:3]: + try: + page = wikipedia.page(option, auto_suggest=False, redirect=True) + if self._validate_article(page, company_name, website, parent_name): + self.logger.info(f" -> ERFOLG: Artikel '{page.title}' aus Begriffsklärung validiert.") + return page + except Exception: + continue # Ignoriere Fehler bei einzelnen Optionen + except Exception: + # Ignoriere Fehler beim Laden einer einzelnen Seite und mache weiter + continue + + except Exception as e_search: + self.logger.error(f" -> Unerwarteter Fehler bei der Suche mit Begriff '{term}': {e}") + continue # Mache mit dem nächsten Suchbegriff weiter + + self.logger.warning(f"Kein passender & validierter Wikipedia-Artikel für '{company_name[:50]}...' gefunden.") return None def _extract_first_paragraph_from_soup(self, soup):