bugfix
This commit is contained in:
@@ -4068,240 +4068,162 @@ class DataProcessor:
|
||||
# --- Der Code fuer den naechsten Verarbeitungsschritt (Wikipedia) folgt im naechsten Block ---
|
||||
# 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
|
||||
# (_needs_wiki_processing True ist ODER force_reeval True ist).
|
||||
# _needs_wiki_processing prueft AN und S='X (URL Copied)'.
|
||||
# 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.
|
||||
# _needs_wiki_processing prueft V (alt AN) und Y="X (URL Copied)" (alt S).
|
||||
|
||||
# Pruefen Sie, ob der Wiki-Schritt im aktuellen Lauf angefordert wurde
|
||||
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)
|
||||
|
||||
|
||||
# Wenn der Wiki-Schritt angefordert wurde UND laut Status/Re-Eval noetig ist
|
||||
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 = []
|
||||
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('AN leer')
|
||||
# Pruefe, ob Status S "X (URL Copied)" ist (nutzt interne Helfer)
|
||||
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)
|
||||
if not self._get_cell_value_safe(row_data, "Wikipedia Timestamp").strip(): grund_message_parts.append('V (Wikipedia Timestamp) leer') # Neuer Schlüssel
|
||||
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
|
||||
grund_message = ", ".join(filter(None, grund_message_parts)) or "Unbekannter Grund"
|
||||
|
||||
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)
|
||||
url_in_m = self._get_cell_value_safe(row_data, "Wiki URL").strip()
|
||||
url_to_extract = None # Die URL, von der wir am Ende Daten extrahieren werden
|
||||
search_was_needed = False # Flag, ob eine neue Suche durchgefuehrt wurde
|
||||
# Aktuelle Wiki URL aus Spalte N (alt M)
|
||||
url_in_n_sheet = self._get_cell_value_safe(row_data, "Wiki URL").strip() # Neuer Schlüssel "Wiki URL"
|
||||
url_to_extract_from = None
|
||||
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
|
||||
|
||||
# --- Logik zur Bestimmung der URL, die verwendet werden soll ---
|
||||
# Prioritaet (bei Ausfuehrung des Wiki-Schritts):
|
||||
# 1. Wenn Status S == "X (URL Copied)": Ignoriere URL in M, fuehre neue Suche aus.
|
||||
# 2. Wenn force_reeval True: Nimm URL in M, WENN gueltig aussehend. Sonst neue Suche.
|
||||
# 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
|
||||
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 und Priorisierung von SerpAPI ---
|
||||
if status_y_indicates_reparse:
|
||||
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)...")
|
||||
search_was_needed_flag = True
|
||||
elif force_reeval:
|
||||
# Wenn Re-Eval erzwungen wird
|
||||
self.logger.debug(" -> Re-Eval Modus aktiv fuer Wiki-Schritt.") # <<< GEÄNDERT
|
||||
# Wenn die URL in M existiert und gueltig aussieht
|
||||
if m_url_exists_and_looks_valid:
|
||||
# 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
|
||||
self.logger.debug(" -> Re-Eval Modus aktiv fuer Wiki-Schritt.")
|
||||
if n_url_looks_valid_in_sheet:
|
||||
self.logger.info(f" -> Re-Eval: Nutze vorhandene URL aus Spalte N direkt: {url_in_n_sheet[:100]}...")
|
||||
url_to_extract_from = url_in_n_sheet
|
||||
else:
|
||||
# Wenn M leer/ungueltig ist, auch im Re-Eval Modus neu suchen
|
||||
self.logger.debug(f" -> Re-Eval: Spalte M ist leer oder ungueltig ('{url_in_m[:100]}...'). Starte neue Suche...") # <<< GEÄNDERT
|
||||
search_was_needed = True # Suche ist noetig
|
||||
|
||||
elif not an_value:
|
||||
# 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
|
||||
self.logger.debug(f" -> Re-Eval: Spalte N leer/ungueltig ('{url_in_n_sheet[:100]}...'). Starte neue Suche (primär SerpAPI)...")
|
||||
search_was_needed_flag = True
|
||||
elif timestamp_v_is_empty: # Wikipedia Timestamp (V, alt AN) ist leer
|
||||
if n_url_looks_valid_in_sheet:
|
||||
self.logger.debug(f" -> Wikipedia Timestamp (V) fehlt, pruefe Validitaet der URL aus N: {url_in_n_sheet[:100]}...")
|
||||
try:
|
||||
# Extrahieren des Titels aus der URL fuer wikipedia.page (nutzt globale Helfer)
|
||||
# Dieser Aufruf kann Exceptions werfen (PageError, DisambiguationError).
|
||||
title_from_url_part = url_in_m.split('/wiki/', 1)[1].split('#')[0] # Titelteil nach /wiki/, Anker entfernen
|
||||
title_from_url = unquote(title_from_url_part).replace('_', ' ') # Dekodieren und Unterstriche ersetzen
|
||||
# Validierung mit der wiki_scraper Instanz
|
||||
# _validate_article erwartet ein Page-Objekt. Wir müssen es zuerst holen.
|
||||
title_from_url_part = url_in_n_sheet.split('/wiki/', 1)[1].split('#')[0]
|
||||
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.
|
||||
# wikipedia.page selbst kann wikipedia.exceptions werfen.
|
||||
# Wir fangen diese spezifischen wikipedia.exceptions hier ab, aber andere RequestsExceptions
|
||||
# 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
|
||||
if self.wiki_scraper._validate_article(page_object_from_n, company_name, website_url):
|
||||
url_to_extract_from = page_object_from_n.url
|
||||
self.logger.info(f" -> Vorhandene URL aus N '{url_to_extract_from[:100]}...' ist valide und wird verwendet.")
|
||||
else:
|
||||
# Wenn der Artikel aus M nicht validiert wird
|
||||
self.logger.warning(f" -> Vorhandene URL aus M '{page_from_m.title[:100]}...' ist NICHT valide. Starte neue Suche...") # <<< GEÄNDERT
|
||||
search_was_needed = True # Suche ist noetig
|
||||
|
||||
except (wikipedia.exceptions.PageError, wikipedia.exceptions.DisambiguationError) as e_wiki_m:
|
||||
# Wenn die URL in M zu einem nicht existierenden Artikel oder einer Begriffsklaerung fuehrt
|
||||
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
|
||||
# Logge die Disambiguation Optionen auf Debug, falls vorhanden
|
||||
if isinstance(e_wiki_m, wikipedia.exceptions.DisambiguationError):
|
||||
self.logger.debug(f" -> Disambiguation Optionen: {str(e_wiki_m.options)[:100]}...") # <<< GEÄNDERT
|
||||
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
|
||||
|
||||
self.logger.warning(f" -> Vorhandene URL aus N '{page_object_from_n.title[:100]}...' ist NICHT valide. Starte neue Suche (primär SerpAPI)...")
|
||||
search_was_needed_flag = True
|
||||
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)...")
|
||||
if isinstance(e_wiki_val, wikipedia.exceptions.DisambiguationError):
|
||||
self.logger.debug(f" -> Disambiguation Optionen: {str(e_wiki_val.options)[:100]}...")
|
||||
search_was_needed_flag = True
|
||||
except Exception as e_val_m_general:
|
||||
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)...")
|
||||
search_was_needed_flag = True
|
||||
else:
|
||||
# M ist leer/ungueltig und AN fehlt -> Suche starten
|
||||
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 = True # Suche ist noetig
|
||||
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]}...'...")
|
||||
search_was_needed_flag = True
|
||||
|
||||
# --- Führe die Suche aus, wenn search_was_needed True ist ---
|
||||
if search_was_needed:
|
||||
self.logger.debug(f" -> Fuehre Wikipedia Suche ueber scraper durch...") # <<< GEÄNDERT
|
||||
if search_was_needed_flag:
|
||||
self.logger.info(f" -> Suche nach Wikipedia-Artikel für '{company_name[:50]}...' via SerpAPI...")
|
||||
search_name_for_serp = crm_kurzform if crm_kurzform and len(crm_kurzform) > 2 else company_name
|
||||
self.logger.debug(f" Verwende Suchnamen für SerpAPI: '{search_name_for_serp}'")
|
||||
try:
|
||||
# Rufe die search_company_article Methode des Scrapers auf.
|
||||
# search_company_article ist mit retry_on_failure dekoriert und wirft bei endgueltigem Fehler eine Exception.
|
||||
# Nutzt die ggf. neue Website URL fuer Kontext im search_company_article.
|
||||
validated_page = self.wiki_scraper.search_company_article(company_name, website_url) # Nutzt die uebergebene scraper Instanz
|
||||
|
||||
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
|
||||
# serp_wikipedia_lookup ist global und nutzt retry
|
||||
new_url_from_serp = serp_wikipedia_lookup(search_name_for_serp, website=website_url)
|
||||
if new_url_from_serp:
|
||||
url_to_extract_from = new_url_from_serp
|
||||
self.logger.info(f" -> SerpAPI Suche erfolgreich, gefundene URL: {url_to_extract_from[:100]}...")
|
||||
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
|
||||
self.logger.warning(f" -> SerpAPI Suche fand keinen passenden Wikipedia-Artikel für '{search_name_for_serp}'.")
|
||||
url_to_extract_from = 'Kein Artikel gefunden' # Expliziter Wert
|
||||
except Exception as e_serp_wiki_search:
|
||||
self.logger.error(f"FEHLER bei SerpAPI Wikipedia Suche für '{search_name_for_serp}': {e_serp_wiki_search}")
|
||||
url_to_extract_from = f"FEHLER bei Suche (SerpAPI): {str(e_serp_wiki_search)[:50]}..."
|
||||
|
||||
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
|
||||
# --- 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:
|
||||
# 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
|
||||
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:
|
||||
# Wenn extrahierte Daten leer oder ungueltig sind (z.B. parse Fehler intern)
|
||||
self.logger.error(f" -> Fehler bei Datenextraktion von {url_to_extract[:100]}... oder Extraktion war leer. Setze Daten auf 'k.A.'") # <<< GEÄNDERT
|
||||
# Behalte die URL, aber setze alle anderen Felder auf k.A. oder Fehler.
|
||||
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.'}
|
||||
wiki_data_updated_in_this_run = True # Markieren, dass die Daten ueberschrieben werden.
|
||||
|
||||
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:
|
||||
# Wenn extract_company_data eine Exception wirft (nach Retries)
|
||||
self.logger.error(f"FEHLER bei Wikipedia Datenextraktion von {url_to_extract[:100]}...: {e_wiki_extract}") # <<< GEÄNDERT
|
||||
# Setze Daten auf k.A., behalte aber die URL, von der extrahiert werden sollte
|
||||
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
|
||||
wiki_data_updated_in_this_run = True # Markieren, dass die Daten ueberschrieben werden.
|
||||
pass # Faert fort
|
||||
self.logger.error(f"FEHLER bei Wikipedia Datenextraktion von {url_to_extract_from[:100]}...: {e_wiki_extract}")
|
||||
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.'}
|
||||
wiki_data_updated_in_this_run = True
|
||||
else: # Wenn keine gueltige URL zum Extrahieren bestimmt wurde
|
||||
self.logger.debug(f" -> Keine gueltige URL zum Extrahieren bestimmt ('{url_to_extract_from}'). Wiki-Daten nicht extrahiert oder bleiben auf Fehlerstatus.")
|
||||
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:
|
||||
# Wenn keine gueltige URL zum Extrahieren bestimmt wurde (z.B. Suche fand nichts oder Fehler bei Suche)
|
||||
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.
|
||||
# --- Sheet Updates für N-AB (Wiki-Daten) und Timestamps V, W, X ---
|
||||
# Verwende die NEUEN Spaltenschlüssel aus der aktuellen COLUMN_MAP
|
||||
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 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 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.')]]})
|
||||
|
||||
# Setze den Wikipedia Timestamp (AN), da der Wiki-Schritt lief (auch wenn fehlerhaft)
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wikipedia Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
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 Y (Chat Wiki Konsistenzpruefung) und W (Wiki Verif. Timestamp) zurück, wenn Neubewertung nötig
|
||||
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")
|
||||
|
||||
# --- Setze S ('Chat Wiki Konsistenzpruefung') und AX ('Wiki Verif. Timestamp') zurueck, wenn Neubewertung noetig ist ---
|
||||
# Eine Neubewertung (Zuruecksetzen von S und AX) ist noetig, wenn:
|
||||
# - force_reeval True ist (immer bei Re-Eval des Wiki-Schritts)
|
||||
# - Status S zuvor "X (URL Copied)" war (der Trigger fuer die Re-Extraktion)
|
||||
# - 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.
|
||||
|
||||
status_s_indicates_reparse = self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)"
|
||||
# Pruefe, ob die FINAL_wiki_data URL (nach Suche/Extraktion) anders ist als die URSPRUENGLICHE URL in M im Sheet.
|
||||
# UND stelle sicher, dass die neue URL eine gueltige URL ist (nicht "k.A." oder Fehlerstring).
|
||||
new_wiki_url = final_wiki_data.get('url')
|
||||
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
|
||||
|
||||
# Bestimme, ob S und AX zurueckgesetzt werden sollen
|
||||
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
|
||||
if force_reeval or status_y_from_sheet == "X (URL COPIED)" or url_changed_and_is_valid_wiki_link:
|
||||
y_idx = COLUMN_MAP.get("Chat Wiki Konsistenzpruefung")
|
||||
w_idx = COLUMN_MAP.get("Wiki Verif. Timestamp")
|
||||
if y_idx is not None and w_idx is not None:
|
||||
y_let = self.sheet_handler._get_col_letter(y_idx + 1)
|
||||
w_let = self.sheet_handler._get_col_letter(w_idx + 1)
|
||||
updates.append({'range': f'{y_let}{row_num_in_sheet}', 'values': [["?"]]})
|
||||
updates.append({'range': f'{w_let}{row_num_in_sheet}', 'values': [[""]]}) # W (alt AX) leeren
|
||||
# Grund für Reset loggen
|
||||
reset_reason_parts = []
|
||||
if force_reeval: reset_reason_parts.append('Re-Eval')
|
||||
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')
|
||||
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'}).")
|
||||
else:
|
||||
# Logge Fehler, wenn Spaltenindizes fehlen
|
||||
self.logger.error("FEHLER: Konnte Spaltenbuchstaben fuer S oder AX nicht ermitteln. Zuruecksetzen uebersprungen.") # <<< GEÄNDERT
|
||||
self.logger.error("FEHLER: Konnte Spaltenbuchstaben fuer Y oder W nicht ermitteln. Zuruecksetzen uebersprungen.")
|
||||
|
||||
# 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:
|
||||
@@ -4962,47 +4884,33 @@ class DataProcessor:
|
||||
|
||||
|
||||
# Verarbeitung der markierten Zeilen
|
||||
processed_count = 0 # Zaehlt Zeilen, fuer die _process_single_row aufgerufen wurde (im Rahmen des Limits).
|
||||
# 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.
|
||||
processed_count = 0
|
||||
|
||||
# Iteriere ueber die gefundenen markierten Zeilen
|
||||
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:
|
||||
# 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.") # <<< GEÄNDERT
|
||||
break # Brich die Schleife ab
|
||||
self.logger.info(f"Zeilenlimit ({row_limit}) fuer Re-Evaluation erreicht. Breche weitere Verarbeitung ab. Processed: {processed_count}")
|
||||
break
|
||||
|
||||
row_num = task['row_num']
|
||||
row_data = task['data']
|
||||
|
||||
row_num = task['row_num'] # 1-basierte Zeilennummer
|
||||
row_data = task['data'] # Die Rohdaten fuer diese Zeile
|
||||
|
||||
self.logger.info(f"Bearbeite Re-Eval Zeile {row_num}...") # <<< GEÄNDERT
|
||||
self.logger.info(f"Bearbeite Re-Eval Zeile {row_num}...")
|
||||
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(
|
||||
row_num_in_sheet = row_num,
|
||||
row_data = row_data,
|
||||
steps_to_run = steps_to_run_set, # <-- Uebergibt die aus CLI/Menue ausgewaehlten Schritte
|
||||
force_reeval = True, # <-- Erzwingt Re-Evaluation unabhaengig von Timestamps fuer die ausgewaehlten Schritte
|
||||
clear_x_flag = clear_flag # <-- Uebergibt, ob das 'x'-Flag von _process_single_row geloescht werden soll
|
||||
steps_to_run = steps_to_run_set,
|
||||
force_reeval = True,
|
||||
clear_x_flag = clear_flag
|
||||
)
|
||||
|
||||
# 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:
|
||||
# Wenn _process_single_row einen Fehler wirft (nachdem interne Retries aufgaben),
|
||||
# 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
|
||||
self.logger.exception(f"FEHLER bei Re-Evaluation von Zeile {row_num}: {e_proc}")
|
||||
# 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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user