bugfix
This commit is contained in:
@@ -4068,240 +4068,162 @@ class DataProcessor:
|
|||||||
# --- Der Code fuer den naechsten Verarbeitungsschritt (Wikipedia) folgt im naechsten Block ---
|
# --- Der Code fuer den naechsten Verarbeitungsschritt (Wikipedia) folgt im naechsten Block ---
|
||||||
# Definition der Methode _process_single_row wird in der naechsten Nachricht fortgesetzt.
|
# Definition der Methode _process_single_row wird in der naechsten Nachricht fortgesetzt.
|
||||||
|
|
||||||
# --- 2. Wikipedia Handling (Search, Extraction, Status Reset) ---
|
# ======================================================================
|
||||||
|
# === 2. Wikipedia Handling (Search, Extraction, Status Reset) ==========
|
||||||
|
# ======================================================================
|
||||||
# Dieser Schritt wird ausgefuehrt, wenn 'wiki' in steps_to_run enthalten ist UND
|
# Dieser Schritt wird ausgefuehrt, wenn 'wiki' in steps_to_run enthalten ist UND
|
||||||
# (_needs_wiki_processing True ist ODER force_reeval True ist).
|
# (_needs_wiki_processing True ist ODER force_reeval True ist).
|
||||||
# _needs_wiki_processing prueft AN und S='X (URL Copied)'.
|
# _needs_wiki_processing prueft V (alt AN) und Y="X (URL Copied)" (alt S).
|
||||||
# Die Logik fuer S='X (URL Copied)' dient dazu, eine URL, die durch die Wiki-Update
|
|
||||||
# Funktion in M kopiert wurde, sofort neu extrahieren zu lassen.
|
|
||||||
# Nutzt interne Helfer: _get_cell_value_safe, _needs_wiki_processing.
|
|
||||||
# Nutzt globale Helfer: COLUMN_MAP, logger, wikipedia, wikipedia.exceptions,
|
|
||||||
# retry_on_failure, unquote, time, traceback.
|
|
||||||
# Nutzt die uebergebene wiki_scraper Instanz.
|
|
||||||
|
|
||||||
# Pruefen Sie, ob der Wiki-Schritt im aktuellen Lauf angefordert wurde
|
|
||||||
run_wiki_step = 'wiki' in steps_to_run
|
run_wiki_step = 'wiki' in steps_to_run
|
||||||
# Pruefen Sie, ob der Wiki-Schritt laut Status oder Re-Eval noetig ist
|
# _needs_wiki_processing (Block 18) nutzt die NEUEN Spaltennamen für Timestamps/Status
|
||||||
wiki_processing_needed_based_on_status = self._needs_wiki_processing(row_data, force_reeval)
|
wiki_processing_needed_based_on_status = self._needs_wiki_processing(row_data, force_reeval)
|
||||||
|
|
||||||
|
|
||||||
# Wenn der Wiki-Schritt angefordert wurde UND laut Status/Re-Eval noetig ist
|
|
||||||
if run_wiki_step and wiki_processing_needed_based_on_status:
|
if run_wiki_step and wiki_processing_needed_based_on_status:
|
||||||
any_processing_done = True # Markiere, dass in dieser Zeile etwas getan wird
|
any_processing_done = True
|
||||||
|
|
||||||
# Bestimme den Grund fuer die Ausfuehrung dieses Schritts fuer das Logging
|
|
||||||
grund_message_parts = []
|
grund_message_parts = []
|
||||||
if force_reeval: grund_message_parts.append('Re-Eval')
|
if force_reeval: grund_message_parts.append('Re-Eval')
|
||||||
# Pruefe, ob der Timestamp AN leer ist (nutzt interne Helfer)
|
if not self._get_cell_value_safe(row_data, "Wikipedia Timestamp").strip(): grund_message_parts.append('V (Wikipedia Timestamp) leer') # Neuer Schlüssel
|
||||||
if not self._get_cell_value_safe(row_data, "Wikipedia Timestamp").strip(): grund_message_parts.append('AN leer')
|
if self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)": grund_message_parts.append("Y (Chat Wiki Konsistenzpruefung)='X (URL Copied)'") # Neuer Schlüssel
|
||||||
# Pruefe, ob Status S "X (URL Copied)" ist (nutzt interne Helfer)
|
grund_message = ", ".join(filter(None, grund_message_parts)) or "Unbekannter Grund"
|
||||||
if self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)": grund_message_parts.append("S='X (URL Copied)'")
|
|
||||||
grund_message = ", ".join(grund_message_parts)
|
|
||||||
|
|
||||||
self.logger.info(f"Zeile {row_num_in_sheet}: Fuehre WIKI Suche/Extraktion aus (Grund: {grund_message})...") # <<< GEÄNDERT
|
self.logger.info(f"Zeile {row_num_in_sheet}: Fuehre WIKI Suche/Extraktion aus (Grund: {grund_message})...")
|
||||||
|
|
||||||
# Holen Sie die aktuelle Wiki URL aus Spalte M (nutzt interne Helfer)
|
# Aktuelle Wiki URL aus Spalte N (alt M)
|
||||||
url_in_m = self._get_cell_value_safe(row_data, "Wiki URL").strip()
|
url_in_n_sheet = self._get_cell_value_safe(row_data, "Wiki URL").strip() # Neuer Schlüssel "Wiki URL"
|
||||||
url_to_extract = None # Die URL, von der wir am Ende Daten extrahieren werden
|
url_to_extract_from = None
|
||||||
search_was_needed = False # Flag, ob eine neue Suche durchgefuehrt wurde
|
search_was_needed_flag = False
|
||||||
|
|
||||||
|
status_y_indicates_reparse = self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)" # Neuer Schlüssel
|
||||||
|
timestamp_v_is_empty = not self._get_cell_value_safe(row_data, "Wikipedia Timestamp").strip() # Neuer Schlüssel
|
||||||
|
|
||||||
|
n_url_looks_valid_in_sheet = url_in_n_sheet and isinstance(url_in_n_sheet, str) and "wikipedia.org/wiki/" in url_in_n_sheet.lower() and url_in_n_sheet.lower() not in ["k.a.", "kein artikel gefunden", "fehler bei suche", "http:"]
|
||||||
|
|
||||||
# --- Logik zur Bestimmung der URL, die verwendet werden soll ---
|
# --- Logik zur Bestimmung der URL und Priorisierung von SerpAPI ---
|
||||||
# Prioritaet (bei Ausfuehrung des Wiki-Schritts):
|
if status_y_indicates_reparse:
|
||||||
# 1. Wenn Status S == "X (URL Copied)": Ignoriere URL in M, fuehre neue Suche aus.
|
self.logger.info(f" -> Status Y ist 'X (URL Copied)', ignoriere URL '{url_in_n_sheet[:100]}...' in N. Starte neue Suche (primär SerpAPI)...")
|
||||||
# 2. Wenn force_reeval True: Nimm URL in M, WENN gueltig aussehend. Sonst neue Suche.
|
search_was_needed_flag = True
|
||||||
# 3. Wenn AN leer (und kein S="X(URL Copied)", kein Re-Eval): Nimm URL in M, WENN valide. Sonst neue Suche.
|
|
||||||
|
|
||||||
status_s_indicates_reparse = self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)"
|
|
||||||
an_value = self._get_cell_value_safe(row_data, "Wikipedia Timestamp").strip()
|
|
||||||
# Pruefe, ob die URL in M existiert und wie eine Wikipedia-URL aussieht (ignoriert "k.A." und Fehlerwerte)
|
|
||||||
m_url_exists_and_looks_valid = url_in_m and isinstance(url_in_m, str) and "wikipedia.org/wiki/" in url_in_m.lower() and url_in_m.lower() not in ["k.a.", "kein artikel gefunden", "fehler bei suche", "http:"] # Fuege "http:" hinzu
|
|
||||||
|
|
||||||
|
|
||||||
# Bestimmen Sie, ob eine neue Suche notwendig ist
|
|
||||||
if status_s_indicates_reparse:
|
|
||||||
# Wenn Status S signalisiert, dass eine neu kopierte URL extrahiert werden soll, fuehre immer eine Suche aus.
|
|
||||||
self.logger.warning(f" -> Status S ist 'X (URL Copied)', ignoriere URL '{url_in_m[:100]}...' in M und starte neue Suche...") # <<< GEÄNDERT
|
|
||||||
search_was_needed = True # Suche ist noetig
|
|
||||||
|
|
||||||
elif force_reeval:
|
elif force_reeval:
|
||||||
# Wenn Re-Eval erzwungen wird
|
self.logger.debug(" -> Re-Eval Modus aktiv fuer Wiki-Schritt.")
|
||||||
self.logger.debug(" -> Re-Eval Modus aktiv fuer Wiki-Schritt.") # <<< GEÄNDERT
|
if n_url_looks_valid_in_sheet:
|
||||||
# Wenn die URL in M existiert und gueltig aussieht
|
self.logger.info(f" -> Re-Eval: Nutze vorhandene URL aus Spalte N direkt: {url_in_n_sheet[:100]}...")
|
||||||
if m_url_exists_and_looks_valid:
|
url_to_extract_from = url_in_n_sheet
|
||||||
# Im Re-Eval Modus nehmen wir die URL aus M an, OHNE erneute Validierung oder Suche (Vertrauen auf M!).
|
|
||||||
self.logger.info(f" -> Re-Eval: Nutze vorhandene URL aus Spalte M direkt: {url_in_m[:100]}...") # <<< GEÄNDERT
|
|
||||||
url_to_extract = url_in_m # Verwende die URL aus M direkt
|
|
||||||
else:
|
else:
|
||||||
# Wenn M leer/ungueltig ist, auch im Re-Eval Modus neu suchen
|
self.logger.debug(f" -> Re-Eval: Spalte N leer/ungueltig ('{url_in_n_sheet[:100]}...'). Starte neue Suche (primär SerpAPI)...")
|
||||||
self.logger.debug(f" -> Re-Eval: Spalte M ist leer oder ungueltig ('{url_in_m[:100]}...'). Starte neue Suche...") # <<< GEÄNDERT
|
search_was_needed_flag = True
|
||||||
search_was_needed = True # Suche ist noetig
|
elif timestamp_v_is_empty: # Wikipedia Timestamp (V, alt AN) ist leer
|
||||||
|
if n_url_looks_valid_in_sheet:
|
||||||
elif not an_value:
|
self.logger.debug(f" -> Wikipedia Timestamp (V) fehlt, pruefe Validitaet der URL aus N: {url_in_n_sheet[:100]}...")
|
||||||
# Wenn AN leer ist (und kein S="X(Copied)" oder Re-Eval)
|
|
||||||
# Wenn die URL in M existiert und gueltig aussieht
|
|
||||||
if m_url_exists_and_looks_valid:
|
|
||||||
# Wenn AN fehlt und M gefuellt ist, pruefen wir die Validitaet der M-URL ueber die wikipedia Bibliothek.
|
|
||||||
self.logger.debug(f" -> AN fehlt, pruefe Validitaet der URL aus M: {url_in_m[:100]}...") # <<< GEÄNDERT
|
|
||||||
try:
|
try:
|
||||||
# Extrahieren des Titels aus der URL fuer wikipedia.page (nutzt globale Helfer)
|
# Validierung mit der wiki_scraper Instanz
|
||||||
# Dieser Aufruf kann Exceptions werfen (PageError, DisambiguationError).
|
# _validate_article erwartet ein Page-Objekt. Wir müssen es zuerst holen.
|
||||||
title_from_url_part = url_in_m.split('/wiki/', 1)[1].split('#')[0] # Titelteil nach /wiki/, Anker entfernen
|
title_from_url_part = url_in_n_sheet.split('/wiki/', 1)[1].split('#')[0]
|
||||||
title_from_url = unquote(title_from_url_part).replace('_', ' ') # Dekodieren und Unterstriche ersetzen
|
title_from_url = unquote(title_from_url_part).replace('_', ' ')
|
||||||
|
page_object_from_n = wikipedia.page(title_from_url, auto_suggest=False, preload=True) # Kann Exceptions werfen
|
||||||
# Laden des Page Objekts, um es mit _validate_article zu pruefen.
|
|
||||||
# wikipedia.page nutzt intern Requests und API calls, die fehlschlagen koennen.
|
if self.wiki_scraper._validate_article(page_object_from_n, company_name, website_url):
|
||||||
# wikipedia.page selbst kann wikipedia.exceptions werfen.
|
url_to_extract_from = page_object_from_n.url
|
||||||
# Wir fangen diese spezifischen wikipedia.exceptions hier ab, aber andere RequestsExceptions
|
self.logger.info(f" -> Vorhandene URL aus N '{url_to_extract_from[:100]}...' ist valide und wird verwendet.")
|
||||||
# werden vom retry_on_failure auf extract_company_data gefangen (spaeter).
|
|
||||||
page_from_m = wikipedia.page(title_from_url, auto_suggest=False, preload=True)
|
|
||||||
|
|
||||||
# Validierung des Artikels mit der Scraper-Methode (nutzt interne Methode)
|
|
||||||
# _validate_article kann interne Fehler haben (z.B. bei HTML Parsing), aber faengt sie.
|
|
||||||
if self.wiki_scraper._validate_article(page_from_m, company_name, website_url):
|
|
||||||
url_to_extract = page_from_m.url # Die URL ist valide und wird verwendet
|
|
||||||
self.logger.info(f" -> Vorhandene URL aus M '{url_to_extract[:100]}...' ist valide und wird verwendet.") # <<< GEÄNDERT
|
|
||||||
else:
|
else:
|
||||||
# Wenn der Artikel aus M nicht validiert wird
|
self.logger.warning(f" -> Vorhandene URL aus N '{page_object_from_n.title[:100]}...' ist NICHT valide. Starte neue Suche (primär SerpAPI)...")
|
||||||
self.logger.warning(f" -> Vorhandene URL aus M '{page_from_m.title[:100]}...' ist NICHT valide. Starte neue Suche...") # <<< GEÄNDERT
|
search_was_needed_flag = True
|
||||||
search_was_needed = True # Suche ist noetig
|
except (wikipedia.exceptions.PageError, wikipedia.exceptions.DisambiguationError) as e_wiki_val:
|
||||||
|
self.logger.warning(f" -> Vorhandene URL aus N '{url_in_n_sheet[:100]}...' fuehrt zu Fehler ({type(e_wiki_val).__name__}). Starte neue Suche (primär SerpAPI)...")
|
||||||
except (wikipedia.exceptions.PageError, wikipedia.exceptions.DisambiguationError) as e_wiki_m:
|
if isinstance(e_wiki_val, wikipedia.exceptions.DisambiguationError):
|
||||||
# Wenn die URL in M zu einem nicht existierenden Artikel oder einer Begriffsklaerung fuehrt
|
self.logger.debug(f" -> Disambiguation Optionen: {str(e_wiki_val.options)[:100]}...")
|
||||||
self.logger.warning(f" -> Vorhandene URL aus M '{url_in_m[:100]}...' fuehrt zu Fehler ({type(e_wiki_m).__name__}). Starte neue Suche...") # <<< GEÄNDERT
|
search_was_needed_flag = True
|
||||||
# Logge die Disambiguation Optionen auf Debug, falls vorhanden
|
except Exception as e_val_m_general:
|
||||||
if isinstance(e_wiki_m, wikipedia.exceptions.DisambiguationError):
|
self.logger.exception(f" -> Unerwarteter Fehler beim Pruefen/Laden der URL aus N '{url_in_n_sheet[:100]}...': {e_val_m_general}. Starte neue Suche (primär SerpAPI)...")
|
||||||
self.logger.debug(f" -> Disambiguation Optionen: {str(e_wiki_m.options)[:100]}...") # <<< GEÄNDERT
|
search_was_needed_flag = True
|
||||||
search_was_needed = True # Suche ist noetig
|
|
||||||
pass # Faert fort
|
|
||||||
|
|
||||||
except Exception as e_val_m:
|
|
||||||
# Fange andere unerwartete Fehler beim Pruefen der URL aus M ab (z.B. URL-Parsing-Fehler vor wikipedia.page)
|
|
||||||
self.logger.exception(f" -> Unerwarteter Fehler beim Pruefen der URL aus M '{url_in_m[:100]}...': {e_val_m}. Starte neue Suche...") # <<< GEÄNDERT
|
|
||||||
search_was_needed = True # Suche ist noetig
|
|
||||||
pass # Faert fort
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# M ist leer/ungueltig und AN fehlt -> Suche starten
|
self.logger.debug(f" -> Wikipedia Timestamp (V) fehlt und N leer/ungueltig ('{url_in_n_sheet[:100]}...'). Starte Wikipedia-Suche (primär SerpAPI) fuer '{company_name[:50]}...'...")
|
||||||
self.logger.debug(f" -> AN fehlt und M leer/ungueltig ('{url_in_m[:100]}...'). Starte Wikipedia-Suche fuer '{company_name[:100]}...'...") # <<< GEÄNDERT
|
search_was_needed_flag = True
|
||||||
search_was_needed = True # Suche ist noetig
|
|
||||||
|
if search_was_needed_flag:
|
||||||
# --- Führe die Suche aus, wenn search_was_needed True ist ---
|
self.logger.info(f" -> Suche nach Wikipedia-Artikel für '{company_name[:50]}...' via SerpAPI...")
|
||||||
if search_was_needed:
|
search_name_for_serp = crm_kurzform if crm_kurzform and len(crm_kurzform) > 2 else company_name
|
||||||
self.logger.debug(f" -> Fuehre Wikipedia Suche ueber scraper durch...") # <<< GEÄNDERT
|
self.logger.debug(f" Verwende Suchnamen für SerpAPI: '{search_name_for_serp}'")
|
||||||
try:
|
try:
|
||||||
# Rufe die search_company_article Methode des Scrapers auf.
|
# serp_wikipedia_lookup ist global und nutzt retry
|
||||||
# search_company_article ist mit retry_on_failure dekoriert und wirft bei endgueltigem Fehler eine Exception.
|
new_url_from_serp = serp_wikipedia_lookup(search_name_for_serp, website=website_url)
|
||||||
# Nutzt die ggf. neue Website URL fuer Kontext im search_company_article.
|
if new_url_from_serp:
|
||||||
validated_page = self.wiki_scraper.search_company_article(company_name, website_url) # Nutzt die uebergebene scraper Instanz
|
url_to_extract_from = new_url_from_serp
|
||||||
|
self.logger.info(f" -> SerpAPI Suche erfolgreich, gefundene URL: {url_to_extract_from[:100]}...")
|
||||||
if validated_page:
|
|
||||||
# Wenn ein validierter Artikel gefunden wurde, setze die URL, von der extrahiert werden soll.
|
|
||||||
url_to_extract = validated_page.url
|
|
||||||
self.logger.info(f" -> Suche erfolgreich, validierte URL: {url_to_extract[:100]}...") # <<< GEÄNDERT
|
|
||||||
else:
|
|
||||||
# Wenn die Suche keinen validierten Artikel fand
|
|
||||||
self.logger.debug(f" -> Suche fand keinen validierten Artikel fuer '{company_name[:100]}...'.") # <<< GEÄNDERT
|
|
||||||
url_to_extract = 'Kein Artikel gefunden' # Signalisiert kein Artikel gefunden
|
|
||||||
|
|
||||||
except Exception as e_wiki_search:
|
|
||||||
# Wenn search_company_article eine Exception wirft (nach Retries)
|
|
||||||
# Der Fehler wird bereits vom retry_on_failure Decorator geloggt.
|
|
||||||
self.logger.error(f"FEHLER bei Wikipedia Suche fuer '{company_name[:100]}...': {e_wiki_search}") # <<< GEÄNDERT
|
|
||||||
url_to_extract = f"FEHLER bei Suche: {str(e_wiki_search)[:50]}..." # Signalisiert Fehler bei Suche (gekuerzt)
|
|
||||||
# Pass, faert fort, um zumindest den Status zu setzen.
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# --- Datenextraktion, wenn eine URL bestimmt wurde, von der extrahiert werden soll ---
|
|
||||||
# Extrahiere Daten, wenn url_to_extract einen Wert hat, der NICHT "Kein Artikel gefunden" oder ein Fehlerstring ist.
|
|
||||||
if url_to_extract and isinstance(url_to_extract, str) and url_to_extract.lower() not in ['kein artikel gefunden'] and not url_to_extract.startswith("FEHLER"):
|
|
||||||
self.logger.debug(f" -> Extrahiere Daten von URL: {url_to_extract[:100]}...") # <<< GEÄNDERT
|
|
||||||
try:
|
|
||||||
# Rufe die extract_company_data Methode des Scrapers auf.
|
|
||||||
# extract_company_data ist mit retry_on_failure dekoriert und wirft bei endgueltigem Fehler eine Exception.
|
|
||||||
extracted_data = self.wiki_scraper.extract_company_data(url_to_extract) # Nutzt die uebergebene scraper Instanz
|
|
||||||
|
|
||||||
# Pruefen Sie, ob die Extraktion erfolgreich war (nicht None oder mit Fehlerwert)
|
|
||||||
if extracted_data and isinstance(extracted_data, dict) and extracted_data.get('url') != 'k.A.': # Pruefe auf gueltige Extraktion
|
|
||||||
final_wiki_data = extracted_data # Aktualisiere die Arbeitskopie der Wiki-Daten mit den extrahierten Daten.
|
|
||||||
wiki_data_updated_in_this_run = True # Markieren, dass extrahierte Daten da sind (Trigger fuer Chat).
|
|
||||||
self.logger.info(f" -> Datenextraktion von {url_to_extract[:100]}... erfolgreich.") # <<< GEÄNDERT
|
|
||||||
else:
|
else:
|
||||||
# Wenn extrahierte Daten leer oder ungueltig sind (z.B. parse Fehler intern)
|
self.logger.warning(f" -> SerpAPI Suche fand keinen passenden Wikipedia-Artikel für '{search_name_for_serp}'.")
|
||||||
self.logger.error(f" -> Fehler bei Datenextraktion von {url_to_extract[:100]}... oder Extraktion war leer. Setze Daten auf 'k.A.'") # <<< GEÄNDERT
|
url_to_extract_from = 'Kein Artikel gefunden' # Expliziter Wert
|
||||||
# Behalte die URL, aber setze alle anderen Felder auf k.A. oder Fehler.
|
except Exception as e_serp_wiki_search:
|
||||||
final_wiki_data = {'url': url_to_extract, 'first_paragraph': 'k.A. (Extraktion fehlgeschlagen)', 'branche': 'k.A.', 'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.'}
|
self.logger.error(f"FEHLER bei SerpAPI Wikipedia Suche für '{search_name_for_serp}': {e_serp_wiki_search}")
|
||||||
wiki_data_updated_in_this_run = True # Markieren, dass die Daten ueberschrieben werden.
|
url_to_extract_from = f"FEHLER bei Suche (SerpAPI): {str(e_serp_wiki_search)[:50]}..."
|
||||||
|
|
||||||
|
# --- Datenextraktion, wenn eine URL bestimmt wurde ---
|
||||||
|
if url_to_extract_from and isinstance(url_to_extract_from, str) and url_to_extract_from.lower() not in ['kein artikel gefunden'] and not url_to_extract_from.startswith("FEHLER"):
|
||||||
|
self.logger.debug(f" -> Extrahiere Daten von URL: {url_to_extract_from[:100]}...")
|
||||||
|
try:
|
||||||
|
extracted_data = self.wiki_scraper.extract_company_data(url_to_extract_from)
|
||||||
|
if extracted_data and isinstance(extracted_data, dict) and extracted_data.get('url') != 'k.A.':
|
||||||
|
final_wiki_data = extracted_data
|
||||||
|
wiki_data_updated_in_this_run = True
|
||||||
|
self.logger.info(f" -> Datenextraktion von {url_to_extract_from[:100]}... erfolgreich.")
|
||||||
|
else:
|
||||||
|
self.logger.error(f" -> Fehler bei Datenextraktion von {url_to_extract_from[:100]}... oder Extraktion war leer. Setze Daten auf 'k.A.'")
|
||||||
|
final_wiki_data = {'url': url_to_extract_from, 'sitz_stadt': 'k.A.', 'sitz_land': 'k.A.', 'first_paragraph': 'k.A. (Extraktion fehlgeschlagen)', 'branche': 'k.A.', 'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.'}
|
||||||
|
wiki_data_updated_in_this_run = True
|
||||||
except Exception as e_wiki_extract:
|
except Exception as e_wiki_extract:
|
||||||
# Wenn extract_company_data eine Exception wirft (nach Retries)
|
self.logger.error(f"FEHLER bei Wikipedia Datenextraktion von {url_to_extract_from[:100]}...: {e_wiki_extract}")
|
||||||
self.logger.error(f"FEHLER bei Wikipedia Datenextraktion von {url_to_extract[:100]}...: {e_wiki_extract}") # <<< GEÄNDERT
|
final_wiki_data = {'url': url_to_extract_from, 'sitz_stadt': 'k.A.', 'sitz_land': 'k.A.', 'first_paragraph': f'k.A. (FEHLER Extraktion: {str(e_wiki_extract)[:50]}...)', 'branche': 'k.A.', 'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.'}
|
||||||
# Setze Daten auf k.A., behalte aber die URL, von der extrahiert werden sollte
|
wiki_data_updated_in_this_run = True
|
||||||
final_wiki_data = {'url': url_to_extract, 'first_paragraph': f'k.A. (FEHLER Extraktion: {str(e_wiki_extract)[:50]}...)', 'branche': 'k.A.', 'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.'} # Korrektur: e -> e_wiki_extract
|
else: # Wenn keine gueltige URL zum Extrahieren bestimmt wurde
|
||||||
wiki_data_updated_in_this_run = True # Markieren, dass die Daten ueberschrieben werden.
|
self.logger.debug(f" -> Keine gueltige URL zum Extrahieren bestimmt ('{url_to_extract_from}'). Wiki-Daten nicht extrahiert oder bleiben auf Fehlerstatus.")
|
||||||
pass # Faert fort
|
if url_to_extract_from in ['Kein Artikel gefunden'] or (isinstance(url_to_extract_from, str) and url_to_extract_from.startswith("FEHLER")):
|
||||||
|
final_wiki_data['url'] = url_to_extract_from
|
||||||
|
for key_to_clear in ['sitz_stadt', 'sitz_land', 'first_paragraph', 'branche', 'umsatz', 'mitarbeiter', 'categories']:
|
||||||
|
final_wiki_data[key_to_clear] = 'k.A.'
|
||||||
|
wiki_data_updated_in_this_run = True
|
||||||
|
|
||||||
else:
|
# --- Sheet Updates für N-AB (Wiki-Daten) und Timestamps V, W, X ---
|
||||||
# Wenn keine gueltige URL zum Extrahieren bestimmt wurde (z.B. Suche fand nichts oder Fehler bei Suche)
|
# Verwende die NEUEN Spaltenschlüssel aus der aktuellen COLUMN_MAP
|
||||||
self.logger.debug(f" -> Keine gueltige URL zum Extrahieren bestimmt ('{url_to_extract}'). Wiki-Daten nicht extrahiert.") # <<< GEÄNDERT
|
|
||||||
# final_wiki_data behaelt die current_wiki_data Werte (initial geladen) oder wurde oben bei Suche auf "Kein Artikel gefunden"/"FEHLER" gesetzt.
|
|
||||||
# Stelle sicher, dass final_wiki_data die richtige URL enthaelt, auch wenn keine Extraktion stattfand.
|
|
||||||
if url_to_extract in ['Kein Artikel gefunden'] or (isinstance(url_to_extract, str) and url_to_extract.startswith("FEHLER")): # Korrektur Pruefung
|
|
||||||
final_wiki_data['url'] = url_to_extract # Update nur die URL im Ergebnis
|
|
||||||
|
|
||||||
# --- Sheet Updates fuer M-R und AN ---
|
|
||||||
# Diese Updates werden immer hinzugefuegt, WENN der WIKI-Schritt lief (run_wiki_step and wiki_processing_needed_based_on_status war True).
|
|
||||||
# Auch wenn die Suche/Extraktion fehlschlug (dann werden k.A. oder Fehlermeldungen geschrieben).
|
|
||||||
# Aktualisiere die Spalten M-R mit den finalen Daten im final_wiki_data Dictionary.
|
|
||||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki URL"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('url', 'k.A.')]]})
|
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki URL"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('url', 'k.A.')]]})
|
||||||
|
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Sitz Stadt"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('sitz_stadt', 'k.A.')]]})
|
||||||
|
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Sitz Land"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('sitz_land', 'k.A.')]]})
|
||||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Absatz"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('first_paragraph', 'k.A.')]]})
|
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Absatz"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('first_paragraph', 'k.A.')]]})
|
||||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Branche"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('branche', 'k.A.')]]})
|
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Branche"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('branche', 'k.A.')]]})
|
||||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Umsatz"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('umsatz', 'k.A.')]]})
|
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Umsatz"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('umsatz', 'k.A.')]]})
|
||||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Mitarbeiter"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('mitarbeiter', 'k.A.')]]})
|
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Mitarbeiter"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('mitarbeiter', 'k.A.')]]})
|
||||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Kategorien"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('categories', 'k.A.')]]})
|
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Kategorien"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('categories', 'k.A.')]]})
|
||||||
|
|
||||||
|
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wikipedia Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]}) # Spalte V
|
||||||
|
|
||||||
# Setze den Wikipedia Timestamp (AN), da der Wiki-Schritt lief (auch wenn fehlerhaft)
|
# Setze Y (Chat Wiki Konsistenzpruefung) und W (Wiki Verif. Timestamp) zurück, wenn Neubewertung nötig
|
||||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wikipedia Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
status_y_from_sheet = self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() # Neuer Schlüssel Y
|
||||||
|
url_changed_and_is_valid_wiki_link = (url_in_n_sheet != final_wiki_data.get('url')) and \
|
||||||
|
isinstance(final_wiki_data.get('url'), str) and \
|
||||||
|
"wikipedia.org/wiki/" in final_wiki_data.get('url', '').lower() and \
|
||||||
|
final_wiki_data.get('url', '').lower() not in ["k.a.", "kein artikel gefunden"] and \
|
||||||
|
not final_wiki_data.get('url', '').startswith("FEHLER")
|
||||||
|
|
||||||
|
if force_reeval or status_y_from_sheet == "X (URL COPIED)" or url_changed_and_is_valid_wiki_link:
|
||||||
# --- Setze S ('Chat Wiki Konsistenzpruefung') und AX ('Wiki Verif. Timestamp') zurueck, wenn Neubewertung noetig ist ---
|
y_idx = COLUMN_MAP.get("Chat Wiki Konsistenzpruefung")
|
||||||
# Eine Neubewertung (Zuruecksetzen von S und AX) ist noetig, wenn:
|
w_idx = COLUMN_MAP.get("Wiki Verif. Timestamp")
|
||||||
# - force_reeval True ist (immer bei Re-Eval des Wiki-Schritts)
|
if y_idx is not None and w_idx is not None:
|
||||||
# - Status S zuvor "X (URL Copied)" war (der Trigger fuer die Re-Extraktion)
|
y_let = self.sheet_handler._get_col_letter(y_idx + 1)
|
||||||
# - Die neue URL in M (final_wiki_data['url']) anders ist als die urspruengliche URL aus M (url_in_m), UND die neue URL gueltig ist.
|
w_let = self.sheet_handler._get_col_letter(w_idx + 1)
|
||||||
|
updates.append({'range': f'{y_let}{row_num_in_sheet}', 'values': [["?"]]})
|
||||||
status_s_indicates_reparse = self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)"
|
updates.append({'range': f'{w_let}{row_num_in_sheet}', 'values': [[""]]}) # W (alt AX) leeren
|
||||||
# Pruefe, ob die FINAL_wiki_data URL (nach Suche/Extraktion) anders ist als die URSPRUENGLICHE URL in M im Sheet.
|
# Grund für Reset loggen
|
||||||
# UND stelle sicher, dass die neue URL eine gueltige URL ist (nicht "k.A." oder Fehlerstring).
|
reset_reason_parts = []
|
||||||
new_wiki_url = final_wiki_data.get('url')
|
if force_reeval: reset_reason_parts.append('Re-Eval')
|
||||||
url_changed_and_valid = (url_in_m != new_wiki_url) and isinstance(new_wiki_url, str) and new_wiki_url.lower() not in ["k.a.", "kein artikel gefunden"] and not new_wiki_url.startswith("FEHLER") # Korrektur Pruefung
|
if status_y_from_sheet == "X (URL COPIED)": reset_reason_parts.append("Y='X (URL Copied)'")
|
||||||
|
if url_changed_and_is_valid_wiki_link: reset_reason_parts.append('URL geändert und valide')
|
||||||
# Bestimme, ob S und AX zurueckgesetzt werden sollen
|
self.logger.info(f" -> Status Y ('Chat Wiki Konsistenzpruefung') zurueckgesetzt auf '?' und Timestamp W ('Wiki Verif. Timestamp') geleert (Grund: {', '.join(reset_reason_parts) or 'Unbekannt'}).")
|
||||||
if force_reeval or status_s_indicates_reparse or url_changed_and_valid:
|
|
||||||
s_idx = COLUMN_MAP.get("Chat Wiki Konsistenzpruefung")
|
|
||||||
ax_idx = COLUMN_MAP.get("Wiki Verif. Timestamp")
|
|
||||||
if s_idx is not None and ax_idx is not None:
|
|
||||||
s_let = self.sheet_handler._get_col_letter(s_idx + 1)
|
|
||||||
ax_let = self.sheet_handler._get_col_letter(ax_idx + 1)
|
|
||||||
|
|
||||||
# Fuegen Sie die Updates zum Zuruecksetzen von S und AX hinzu
|
|
||||||
# S wird auf '?' gesetzt, um anzuzeigen, dass eine Verifizierung aussteht
|
|
||||||
updates.append({'range': f'{s_let}{row_num_in_sheet}', 'values': [["?"]]})
|
|
||||||
# AX wird geleert, um die Batch-Verifizierung zu triggern
|
|
||||||
updates.append({'range': f'{ax_let}{row_num_in_sheet}', 'values': [[""]]})
|
|
||||||
|
|
||||||
# Bestimme den Grund-String fuer das Logging
|
|
||||||
grund_message_parts = []
|
|
||||||
if force_reeval: grund_message_parts.append('Re-Eval')
|
|
||||||
if status_s_indicates_reparse: grund_message_parts.append("S='X (URL Copied)'")
|
|
||||||
if url_changed_and_valid: grund_message_parts.append('URL geaendert und gueltig')
|
|
||||||
grund_message_s_reset = ", ".join(grund_message_parts)
|
|
||||||
|
|
||||||
self.logger.info(f" -> Status S zurueckgesetzt auf '?' und Timestamp AX geleert fuer erneute Verifikation (Grund: {grund_message_s_reset}).") # <<< GEÄNDERT
|
|
||||||
else:
|
else:
|
||||||
# Logge Fehler, wenn Spaltenindizes fehlen
|
self.logger.error("FEHLER: Konnte Spaltenbuchstaben fuer Y oder W nicht ermitteln. Zuruecksetzen uebersprungen.")
|
||||||
self.logger.error("FEHLER: Konnte Spaltenbuchstaben fuer S oder AX nicht ermitteln. Zuruecksetzen uebersprungen.") # <<< GEÄNDERT
|
|
||||||
|
# else if run_wiki_step (aber nicht processing_needed_based_on_status):
|
||||||
|
# self.logger.debug(f"Zeile {row_num_in_sheet}: Ueberspringe WIKI Suche/Extraktion (Timestamp V vorhanden, Y nicht 'X (URL Copied)' und kein Re-Eval).")
|
||||||
|
|
||||||
|
# --- Ende Wikipedia Handling ---
|
||||||
|
|
||||||
|
|
||||||
# else if run_wiki_step:
|
# else if run_wiki_step:
|
||||||
@@ -4962,47 +4884,33 @@ class DataProcessor:
|
|||||||
|
|
||||||
|
|
||||||
# Verarbeitung der markierten Zeilen
|
# Verarbeitung der markierten Zeilen
|
||||||
processed_count = 0 # Zaehlt Zeilen, fuer die _process_single_row aufgerufen wurde (im Rahmen des Limits).
|
processed_count = 0
|
||||||
# Die Liste updates_clear_flag wird NICHT mehr hier gefuellt, da _process_single_row das Update selbst hinzufuegt (Block 21).
|
|
||||||
# Die Liste rows_actually_processed wird nicht mehr benoetigt.
|
|
||||||
|
|
||||||
# Iteriere ueber die gefundenen markierten Zeilen
|
# Iteriere ueber die gefundenen markierten Zeilen
|
||||||
for task in rows_to_process:
|
for task in rows_to_process:
|
||||||
# Ueberpruefen Sie das Limit fuer die zu verarbeitenden Zeilen VOR der Verarbeitung
|
# === HIER DIE DEBUG-AUSGABE EINFÜGEN ===
|
||||||
|
self.logger.debug(f"Re-Eval Loop Check: processed_count={processed_count}, row_limit={row_limit}")
|
||||||
|
# === ENDE DEBUG-AUSGABE ===
|
||||||
|
|
||||||
if row_limit is not None and isinstance(row_limit, int) and row_limit > 0 and processed_count >= row_limit:
|
if row_limit is not None and isinstance(row_limit, int) and row_limit > 0 and processed_count >= row_limit:
|
||||||
# Wenn das Limit erreicht ist und es ein positives Limit gibt
|
self.logger.info(f"Zeilenlimit ({row_limit}) fuer Re-Evaluation erreicht. Breche weitere Verarbeitung ab. Processed: {processed_count}")
|
||||||
self.logger.info(f"Zeilenlimit ({row_limit}) fuer Re-Evaluation erreicht. Breche weitere Verarbeitung ab.") # <<< GEÄNDERT
|
break
|
||||||
break # Brich die Schleife ab
|
|
||||||
|
|
||||||
|
row_num = task['row_num']
|
||||||
|
row_data = task['data']
|
||||||
|
|
||||||
row_num = task['row_num'] # 1-basierte Zeilennummer
|
self.logger.info(f"Bearbeite Re-Eval Zeile {row_num}...")
|
||||||
row_data = task['data'] # Die Rohdaten fuer diese Zeile
|
|
||||||
|
|
||||||
self.logger.info(f"Bearbeite Re-Eval Zeile {row_num}...") # <<< GEÄNDERT
|
|
||||||
try:
|
try:
|
||||||
# Rufe die Methode zur Verarbeitung einer einzelnen Zeile auf (_process_single_row Block 19).
|
|
||||||
# In diesem Modus setzen wir immer force_reeval=True.
|
|
||||||
# Wir uebergeben die aus CLI/Menue ausgewaehlten Schritte in steps_to_run_set.
|
|
||||||
# Wir uebergeben das clear_flag, damit _process_single_row weiss, ob das 'x' geloescht werden soll.
|
|
||||||
# _process_single_row fuehrt die Schritte durch, sammelt Updates (inkl. 'x'-Flag Update wenn clear_x_flag=True)
|
|
||||||
# und sendet das Batch-Update fuer diese Zeile.
|
|
||||||
self._process_single_row(
|
self._process_single_row(
|
||||||
row_num_in_sheet = row_num,
|
row_num_in_sheet = row_num,
|
||||||
row_data = row_data,
|
row_data = row_data,
|
||||||
steps_to_run = steps_to_run_set, # <-- Uebergibt die aus CLI/Menue ausgewaehlten Schritte
|
steps_to_run = steps_to_run_set,
|
||||||
force_reeval = True, # <-- Erzwingt Re-Evaluation unabhaengig von Timestamps fuer die ausgewaehlten Schritte
|
force_reeval = True,
|
||||||
clear_x_flag = clear_flag # <-- Uebergibt, ob das 'x'-Flag von _process_single_row geloescht werden soll
|
clear_x_flag = clear_flag
|
||||||
)
|
)
|
||||||
|
processed_count += 1
|
||||||
# Zaehlen, wenn _process_single_row erfolgreich aufgerufen wurde (unabhaengig von internen Ueberspringungen in _process_single_row).
|
|
||||||
processed_count += 1
|
|
||||||
# Die Liste rows_actually_processed wird nicht mehr benoetigt.
|
|
||||||
|
|
||||||
except Exception as e_proc:
|
except Exception as e_proc:
|
||||||
# Wenn _process_single_row einen Fehler wirft (nachdem interne Retries aufgaben),
|
self.logger.exception(f"FEHLER bei Re-Evaluation von Zeile {row_num}: {e_proc}")
|
||||||
# fangen wir ihn hier, loggen ihn und fahren mit der naechsten Zeile fort.
|
|
||||||
# Das 'x'-Flag wird in diesem Fall NICHT geloescht, da _process_single_row nicht bis zum Ende kam.
|
|
||||||
self.logger.exception(f"FEHLER bei Re-Evaluation von Zeile {row_num}: {e_proc}") # <<< GEÄNDERT
|
|
||||||
# Hier koennen Sie z.B. einen Fehlerindikator in eine spezielle Spalte im Sheet schreiben lassen.
|
# Hier koennen Sie z.B. einen Fehlerindikator in eine spezielle Spalte im Sheet schreiben lassen.
|
||||||
# Dieses Update muesste dann separat oder im naechsten Lauf behandelt werden.
|
# Dieses Update muesste dann separat oder im naechsten Lauf behandelt werden.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user