This commit is contained in:
2025-05-30 19:16:07 +00:00
parent 8aaa601891
commit fadc31b41c

View File

@@ -3638,107 +3638,139 @@ class WikipediaScraper:
return result
@retry_on_failure
def search_company_article(self, company_name, website=None):
def search_company_article(self, company_name, website=None, max_recursion_depth=2): # 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
Artikel gefunden wird. Behandelt explizit Begriffsklaerungsseiten.
"""
if not company_name or str(company_name).strip() == "":
self.logger.warning("Wikipedia search skipped: No company name provided.") # <<< GEÄNDERT
self.logger.warning("Wikipedia search skipped: No company name provided.")
raise ValueError("Kein Firmenname fuer Wikipedia Suche angegeben.")
search_terms = self._generate_search_terms(company_name, website)
if not search_terms:
self.logger.warning(f"Keine Suchbegriffe fuer '{company_name[:100]}...' generiert.") # <<< GEÄNDERT
self.logger.warning(f"Keine Suchbegriffe fuer '{company_name[:100]}...' generiert.")
return None
self.logger.info( # <<< GEÄNDERT
self.logger.info(
f"Starte Wikipedia-Suche fuer '{company_name[:100]}...' "
f"(Website: {website[:100]}...) mit Begriffen: {search_terms}"
)
processed_titles = set()
processed_titles = set() # Verhindert Endlosschleifen bei zirkulären Redirects/Disambiguations
def check_page(title_to_check):
if title_to_check in processed_titles:
# 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.")
return None
processed_titles.add(title_to_check)
self.logger.debug(f" -> Pruefe potenziellen Artikel: '{title_to_check[:100]}...'") # <<< GEÄNDERT
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)
if self._validate_article(page, company_name, website):
self.logger.info(f" -> Titel '{page.title[:100]}...' erfolgreich validiert!") # <<< GEÄNDERT
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
else:
self.logger.debug(f" -> Titel '{title_to_check[:100]}...' nicht validiert.") # <<< GEÄNDERT
self.logger.debug(f" -> Titel '{title_to_check[:100]}...' nicht validiert.")
return None
except wikipedia.exceptions.PageError:
self.logger.debug(f" -> Seite '{title_to_check[:100]}...' nicht gefunden (PageError).") # <<< GEÄNDERT
self.logger.debug(f" -> Seite '{title_to_check[:100]}...' nicht gefunden (PageError).")
return None
except wikipedia.exceptions.DisambiguationError as e_inner:
self.logger.info( # <<< GEÄNDERT
f" -> Begriffsklaerung '{title_to_check[:100]}...' gefunden. "
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()
if any(
# Erweiterte Negativ-Filterung
if not any(
ex in option_lower
for ex in ["(person)", "(ort)", "(geographie)", "liste ", "liste)"]
):
continue
validated_option_page = check_page(option)
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( # <<< GEÄNDERT
self.logger.info(
f" -> Option '{option[:100]}...' aus Begriffsklaerung erfolgreich validiert!"
)
return validated_option_page
self.logger.debug( # <<< GEÄNDERT
self.logger.debug(
f" -> Keine passende/validierte Unternehmens-Option in Begriffsklaerung '{title_to_check[:100]}...' gefunden."
)
return None
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( # <<< GEÄNDERT
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."
)
return None
except Exception as e_page:
self.logger.error( # <<< GEÄNDERT
self.logger.error(
f" -> Unerwarteter Fehler bei Verarbeitung von Titel '{title_to_check[:100]}...': "
f"{type(e_page).__name__} - {e_page}"
)
self.logger.debug(traceback.format_exc()) # <<< GEÄNDERT
self.logger.debug(traceback.format_exc())
return None
self.logger.debug(f" -> Versuche direkten Match fuer '{company_name[:100]}...'...") # <<< GEÄNDERT
validated_page = check_page(company_name)
# Direkter Match mit dem ursprünglichen Firmennamen
self.logger.debug(f" -> Versuche direkten Match fuer '{company_name[:100]}...'...")
validated_page = check_page_recursive(company_name, current_depth=0) # Starte mit Tiefe 0
if validated_page:
return validated_page
self.logger.debug( # <<< GEÄNDERT
# Suche mit generierten Begriffen
self.logger.debug(
f" -> Kein direkter Treffer/validiert. Starte Suche mit generierten Begriffen: {search_terms}"
)
for term in search_terms:
if term == company_name: continue # Bereits oben geprüft
try:
self.logger.debug(f" -> Suche mit Begriff: '{term[:100]}...'...") # <<< GEÄNDERT
search_results = wikipedia.search(term, results=getattr(Config, 'WIKIPEDIA_SEARCH_RESULTS', 5))
self.logger.debug(f" -> Suchergebnisse fuer '{term[:100]}...': {search_results}") # <<< GEÄNDERT
self.logger.debug(f" -> Suche mit Begriff: '{term[:100]}...'...")
search_results = wikipedia.search(term, results=getattr(Config, 'WIKIPEDIA_SEARCH_RESULTS', 3)) # Weniger Ergebnisse pro Term
self.logger.debug(f" -> Suchergebnisse fuer '{term[:100]}...': {search_results}")
if not search_results:
self.logger.debug(f" -> Keine Suchergebnisse fuer '{term[:100]}...'.") # <<< GEÄNDERT
self.logger.debug(f" -> Keine Suchergebnisse fuer '{term[:100]}...'.")
continue
for title in search_results:
validated_page = check_page(title)
validated_page = check_page_recursive(title, current_depth=0) # Starte mit Tiefe 0 für jeden neuen Suchtreffer
if validated_page:
return validated_page
except Exception as e_search:
self.logger.error( # <<< GEÄNDERT
f"Fehler waehrend Wikipedia-Suche fuer '{term[:100]}...': "
# Fehler von wikipedia.search() selbst, nicht von check_page_recursive
self.logger.error(
f"Fehler waehrend Wikipedia-Suche (wikipedia.search) fuer '{term[:100]}...': "
f"{type(e_search).__name__} - {e_search}"
)
raise e_search
# Hier nicht direkt 'raise e_search', da der Retry-Decorator auf search_company_article liegt.
# Wenn dies ein wiederholbarer Fehler der wikipedia-Bibliothek ist, sollte der Decorator greifen.
# Für den Moment loggen wir und machen mit dem nächsten Suchbegriff weiter.
# Bei einem persistenten API-Problem wird der äußere Decorator nach mehreren Versuchen abbrechen.
self.logger.warning( # <<< GEÄNDERT
self.logger.warning(
f"Kein passender & validierter Wikipedia-Artikel fuer '{company_name[:100]}...' gefunden nach Pruefung aller Begriffe und Optionen."
)
return None