From 4d3c2ded52fa5b4f0069ad2c671b6ba7fc30eb2f Mon Sep 17 00:00:00 2001 From: Floke Date: Fri, 18 Apr 2025 06:18:56 +0000 Subject: [PATCH] bugfix --- brancheneinstufung.py | 183 ++++++++++++++++++++++++++++-------------- 1 file changed, 122 insertions(+), 61 deletions(-) diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 04201cbc..49c8de6f 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -573,18 +573,89 @@ def normalize_company_name(name): return normalized.lower() +@retry_on_failure # API Calls können fehlschlagen +def is_valid_wikipedia_article_url(wiki_url): + """ + Prüft über die MediaWiki API, ob eine gegebene Wikipedia-URL + auf einen existierenden Artikel verweist (und keine Weiterleitung/Begriffsklärung ist). + + Args: + wiki_url (str): Die zu prüfende Wikipedia URL. + + Returns: + bool: True, wenn es ein valider Artikel zu sein scheint, sonst False. + """ + if not wiki_url or not wiki_url.lower().startswith(("http://", "https://")) or "wikipedia.org/wiki/" not in wiki_url: + return False + + try: + # Extrahiere den Artikel-Titel aus der URL + # Beispiel: https://de.wikipedia.org/wiki/B._Braun_Melsungen -> B._Braun_Melsungen + title = wiki_url.split('/wiki/', 1)[1] + # Dekodiere URL-kodierte Zeichen (z.B. %C3%BC -> ü) + title = unquote(title) + # Ersetze Unterstriche durch Leerzeichen für die API-Suche + title = title.replace('_', ' ') + + # Baue die API URL (für deutsche Wikipedia) + # Doku: https://www.mediawiki.org/wiki/API:Query + api_url = "https://de.wikipedia.org/w/api.php" + params = { + "action": "query", + "titles": title, + "format": "json", + "formatversion": 2, # Moderneres JSON-Format + "redirects": 1 # Folge Weiterleitungen (optional, aber oft sinnvoll) + } + + # Führe den API Call durch + response = requests.get(api_url, params=params, timeout=5) + response.raise_for_status() + data = response.json() + + # Analysiere die Antwort + if 'query' in data and 'pages' in data['query']: + pages = data['query']['pages'] + if pages: + page_info = pages[0] # Nimm die erste (und einzige) Seite + # Prüfe auf 'missing': Seite existiert nicht + if page_info.get('missing', False): + debug_print(f" API Check für '{title}': Seite fehlt (missing=True).") + return False + # Prüfe auf 'invalid': Titel ist ungültig + if page_info.get('invalid', False): + debug_print(f" API Check für '{title}': Titel ungültig (invalid=True).") + return False + # Prüfe auf 'disambiguation': Ist eine Begriffsklärungsseite + # (Hinweis: 'pageprops' ist nicht immer vorhanden) + if 'pageprops' in page_info and 'disambiguation' in page_info['pageprops']: + debug_print(f" API Check für '{title}': Seite ist eine Begriffsklärung.") + return False + # Wenn nichts davon zutrifft, scheint es ein valider Artikel zu sein + debug_print(f" API Check für '{title}': Scheint ein valider Artikel zu sein.") + return True + else: + debug_print(f" API Check für '{title}': Leere 'pages'-Liste in Antwort.") + return False # Unerwartete Antwort + else: + debug_print(f" API Check für '{title}': Unerwartetes Format der API-Antwort: {data}") + return False + + except requests.exceptions.RequestException as e: + debug_print(f" API Check für '{title}': Netzwerkfehler - {e}") + return False # Im Zweifel als ungültig werten + except Exception as e: + debug_print(f" API Check für '{title}': Allgemeiner Fehler - {e}") + return False # Im Zweifel als ungültig werten + # NEUE Funktion für Wiki-Updates basierend auf ChatGPT Vorschlägen # NEUE Funktion für Wiki-Updates basierend auf ChatGPT Vorschlägen (mit Status-Update in S) def process_wiki_updates_from_chatgpt(sheet_handler, data_processor, row_limit=None): """ - Identifiziert Zeilen, bei denen Wiki-Konsistenz (S) NICHT 'OK'/'X (Updated)'/'X (URL Copied)' ist - und ein alternativer Artikel in U vorgeschlagen wurde (URL, != M). - Kopiert die neue URL nach M, markiert S als 'X (URL Copied)', U als 'URL übernommen', - LÖSCHT die Timestamps AN, AX, AO sowie die Version AP UND SETZT 'x' in Spalte A, - um eine Neuverarbeitung durch den 'reeval'-Modus zu triggern. - Verarbeitet maximal row_limit Kandidaten. + Identifiziert Zeilen (S nicht OK/Updated), prüft ob U eine *valide* und *andere* Wiki-URL ist. + Wenn ja: Kopiert U->M, markiert S/U, löscht Timestamps/Version, setzt ReEval-Flag A. """ - debug_print("Starte Modus: Wiki-Updates Schritt 1 (URL U -> M kopieren, TS löschen, ReEval Flag setzen)...") # Angepasste Beschreibung + debug_print("Starte Modus: Wiki-Updates mit URL-Validierung...") if not sheet_handler.load_data(): return all_data = sheet_handler.get_all_data_with_headers() @@ -592,87 +663,77 @@ def process_wiki_updates_from_chatgpt(sheet_handler, data_processor, row_limit=N header_rows = 5 data_rows = all_data[header_rows:] - # Indizes holen (inkl. ReEval Flag) - required_keys = [ - "Chat Wiki Konsistenzprüfung", "Chat Vorschlag Wiki Artikel", "Wiki URL", - "Wikipedia Timestamp", "Wiki Verif. Timestamp", "Timestamp letzte Prüfung", "Version", - "ReEval Flag" # NEU - ] - col_indices = {} - all_keys_found = True - for key in required_keys: - idx = COLUMN_MAP.get(key) - if idx is None: debug_print(f"FEHLER: Schlüssel '{key}' fehlt!"); all_keys_found = False - col_indices[key] = idx - if not all_keys_found: return debug_print("Breche Wiki-Updates ab.") + # Indizes holen (wie gehabt) + required_keys = [...] # Alle benötigten Schlüssel + col_indices = {}; all_keys_found = True + for key in required_keys: idx = COLUMN_MAP.get(key); col_indices[key] = idx; if idx is None: debug_print(f"FEHLER: Key '{key}' fehlt!"); all_keys_found = False + if not all_keys_found: return debug_print("Breche ab.") - all_sheet_updates = [] - processed_rows_count = 0 - # error_rows_count nicht mehr relevant, da try/except pro Zeile fehlt (kann wieder rein) + all_sheet_updates = []; processed_rows_count = 0; error_rows_count = 0 # error_rows_count hier nicht genutzt for idx, row in enumerate(data_rows): row_num_in_sheet = idx + header_rows + 1 if row_limit is not None and processed_rows_count >= row_limit: - debug_print(f"Zeilenlimit ({row_limit}) erreicht.") - break + debug_print(f"Zeilenlimit ({row_limit}) erreicht."); break - def get_value(key): - index = col_indices.get(key) - if index is not None and len(row) > index: return row[index] - return "" + def get_value(key): idx = col_indices.get(key); return row[idx] if idx is not None and len(row) > idx else "" + konsistenz_s = get_value("Chat Wiki Konsistenzprüfung"); vorschlag_u = get_value("Chat Vorschlag Wiki Artikel"); url_m = get_value("Wiki URL") - konsistenz_s = get_value("Chat Wiki Konsistenzprüfung") - vorschlag_u = get_value("Chat Vorschlag Wiki Artikel") - url_m = get_value("Wiki URL") - - # Bedingung prüfen (wie zuletzt) + # --- Bedingung prüfen mit URL-Validierung --- is_update_candidate = False; new_url = "" konsistenz_s_upper = konsistenz_s.strip().upper() vorschlag_u_cleaned = vorschlag_u.strip() url_m_cleaned = url_m.strip() - condition1_status_nok = konsistenz_s_upper not in ["OK", "X (UPDATED)", "X (URL COPIED)", ""] - condition2_u_is_url = vorschlag_u_cleaned.lower().startswith(("http://", "https://")) - condition3_u_differs_m = False - if condition2_u_is_url: new_url = vorschlag_u_cleaned; condition3_u_differs_m = new_url != url_m_cleaned - is_update_candidate = condition1_status_nok and condition2_u_is_url and condition3_u_differs_m + # Bedingung 1: Status NOK? + condition1_status_nok = konsistenz_s_upper not in ["OK", "X (UPDATED)", "X (URL COPIED)", ""] + # Bedingung 2: Vorschlag U ist eine URL? + condition2_u_is_url = vorschlag_u_cleaned.lower().startswith(("http://", "https://")) and "wikipedia.org/wiki/" in vorschlag_u_cleaned.lower() + + # Nur wenn beides True, prüfen wir weiter + if condition1_status_nok and condition2_u_is_url: + new_url = vorschlag_u_cleaned + # Bedingung 3: U anders als M? + condition3_u_differs_m = new_url != url_m_cleaned + if condition3_u_differs_m: + # --- NEU: Bedingung 4: Ist U eine VALIDE Wiki-Artikelseite? --- + debug_print(f"Zeile {row_num_in_sheet}: Potenzieller Kandidat. Prüfe Validität von URL: {new_url}...") + condition4_u_is_valid = is_valid_wikipedia_article_url(new_url) + if condition4_u_is_valid: + is_update_candidate = True # Alle Bedingungen erfüllt + else: + debug_print(f"Zeile {row_num_in_sheet}: Vorgeschlagene URL '{new_url}' ist KEIN valider Artikel. Überspringe Update.") + # else: debug_print(f"Zeile {row_num_in_sheet}: URL in U ist gleich wie in M. Überspringe.") + # else: debug_print(f"Zeile {row_num_in_sheet}: Status S ok/leer oder U keine URL. Überspringe.") + + # --- Verarbeitung (nur wenn is_update_candidate True ist) --- if is_update_candidate: - debug_print(f"Zeile {row_num_in_sheet}: Update-Kandidat gefunden. Setze ReEval-Flag und bereite Updates vor.") + debug_print(f"Zeile {row_num_in_sheet}: Update-Kandidat VALIDIERUNG ERFOLGREICH. Setze ReEval-Flag und bereite Updates vor.") processed_rows_count += 1 - # --- Updates sammeln (M, S, U, Timestamps/Version löschen, A setzen) --- - url_m_letter = sheet_handler._get_col_letter(col_indices["Wiki URL"] + 1) - konsistenz_s_letter = sheet_handler._get_col_letter(col_indices["Chat Wiki Konsistenzprüfung"] + 1) - vorschlag_u_letter = sheet_handler._get_col_letter(col_indices["Chat Vorschlag Wiki Artikel"] + 1) - ts_an_letter = sheet_handler._get_col_letter(col_indices["Wikipedia Timestamp"] + 1) - ts_ax_letter = sheet_handler._get_col_letter(col_indices["Wiki Verif. Timestamp"] + 1) - ts_ao_letter = sheet_handler._get_col_letter(col_indices["Timestamp letzte Prüfung"] + 1) - version_ap_letter = sheet_handler._get_col_letter(col_indices["Version"] + 1) - reeval_a_letter = sheet_handler._get_col_letter(col_indices["ReEval Flag"] + 1) # Buchstabe für Spalte A + # Updates sammeln (M, S, U, Timestamps/Version löschen, A setzen) + m_l=sheet_handler._get_col_letter(col_indices["Wiki URL"]+1); s_l=sheet_handler._get_col_letter(col_indices["Chat Wiki Konsistenzprüfung"]+1); u_l=sheet_handler._get_col_letter(col_indices["Chat Vorschlag Wiki Artikel"]+1); an_l=sheet_handler._get_col_letter(col_indices["Wikipedia Timestamp"]+1); ax_l=sheet_handler._get_col_letter(col_indices["Wiki Verif. Timestamp"]+1); ao_l=sheet_handler._get_col_letter(col_indices["Timestamp letzte Prüfung"]+1); ap_l=sheet_handler._get_col_letter(col_indices["Version"]+1); a_l=sheet_handler._get_col_letter(col_indices["ReEval Flag"]+1) row_updates = [ - {'range': f'{url_m_letter}{row_num_in_sheet}', 'values': [[new_url]]}, # Neue URL nach M - {'range': f'{konsistenz_s_letter}{row_num_in_sheet}', 'values': [["X (URL Copied)"]]}, # Neuer Status in S - {'range': f'{vorschlag_u_letter}{row_num_in_sheet}', 'values': [["URL übernommen"]]},# Markierung in U - {'range': f'{ts_an_letter}{row_num_in_sheet}', 'values': [[""]]}, # AN löschen - {'range': f'{ts_ax_letter}{row_num_in_sheet}', 'values': [[""]]}, # AX löschen - {'range': f'{ts_ao_letter}{row_num_in_sheet}', 'values': [[""]]}, # AO löschen - {'range': f'{version_ap_letter}{row_num_in_sheet}', 'values': [[""]]}, # AP löschen - # --- NEU: Setze 'x' in Spalte A --- - {'range': f'{reeval_a_letter}{row_num_in_sheet}', 'values': [["x"]]}, + {'range': f'{m_l}{row_num_in_sheet}', 'values': [[new_url]]}, # Neue URL + {'range': f'{s_l}{row_num_in_sheet}', 'values': [["X (URL Copied)"]]}, # Status + {'range': f'{u_l}{row_num_in_sheet}', 'values': [["URL übernommen"]]}, # Marker + {'range': f'{an_l}{row_num_in_sheet}', 'values': [[""]]}, {'range': f'{ax_l}{row_num_in_sheet}', 'values': [[""]]}, # TS löschen + {'range': f'{ao_l}{row_num_in_sheet}', 'values': [[""]]}, {'range': f'{ap_l}{row_num_in_sheet}', 'values': [[""]]}, + {'range': f'{a_l}{row_num_in_sheet}', 'values': [["x"]]}, # ReEval setzen ] all_sheet_updates.extend(row_updates) # Kein Reparsing/Rebranching hier! - # Batch Update am Ende + # --- Batch Update am Ende --- if all_sheet_updates: - debug_print(f"BEREIT ZUM SENDEN: Batch-Update für {processed_rows_count} Zeilen (URL-Kopie/TS-Reset/ReEval-Flag)...") + debug_print(f"BEREIT ZUM SENDEN: Batch-Update für {processed_rows_count} validierte URL-Kopien/Resets ({len(all_sheet_updates)} Zellen)...") success = sheet_handler.batch_update_cells(all_sheet_updates) if success: debug_print(f"Sheet-Update für Wiki-Korrektur-Vorbereitung erfolgreich.") else: debug_print(f"FEHLER beim Sheet-Update für Wiki-Korrektur-Vorbereitung.") else: - debug_print("Keine Zeilen für Wiki-URL-Korrektur gefunden/benötigt.") + debug_print("Keine Zeilen gefunden, die eine validierte Wiki-URL-Korrektur benötigen.") debug_print(f"Wiki-Updates Vorbereitung abgeschlossen. {processed_rows_count} Zeilen für Re-Evaluation markiert.")