bugfix
This commit is contained in:
@@ -359,18 +359,112 @@ def serp_wikipedia_lookup(company_name, website=None, min_score=0.4):
|
||||
logging.error(f"Allgemeiner Fehler bei der SerpAPI Wikipedia Suche für '{company_name}': {e}")
|
||||
return None # Bei unerwarteten Fehlern None zurückgeben
|
||||
|
||||
# Kann als eigenständige Funktion oder Methode in DataProcessor implementiert werden
|
||||
# Annahme: COLUMN_MAP ist global definiert und enthält mindestens:
|
||||
# "CRM Name" (B), "CRM Anzahl Mitarbeiter" (K), "CRM Umsatz" (J),
|
||||
# "Wiki URL" (M), "ReEval Flag" (A), "Wiki Absatz" (N), ..., "Wiki Verif. Timestamp" (AX), "SerpAPI Wiki Search Timestamp" (AY)
|
||||
# Annahme: serp_wikipedia_lookup und simple_normalize_url sind definiert und nutzen logging/retry
|
||||
# Annahme: clean_text und normalize_company_name sind definiert
|
||||
# Annahme: get_valid_numeric (oder ähnliche Logik zur numerischen Extraktion) ist verfügbar/implementiert.
|
||||
|
||||
# Die extract_numeric_value Funktion wird für die Extraktion aus Wikipedia-Daten verwendet.
|
||||
# Wir benötigen hier eine ähnliche Logik, die aber 0 statt 'k.A.' zurückgibt.
|
||||
|
||||
# --- Hilfsfunktion zur sicheren numerischen Extraktion FÜR DIE FILTERLOGIK ---
|
||||
def get_numeric_filter_value(value_str, is_umsatz=False):
|
||||
"""
|
||||
Extrahiert und normalisiert Zahlenwerte für die Filterlogik (Umsatz in Mio, Mitarbeiter int).
|
||||
Gibt 0 zurück, wenn der Wert leer, k.A., nicht numerisch ist, oder 0 ergibt.
|
||||
Beachtet Einheiten (Tsd, Mio, Mrd) für Umsatz.
|
||||
"""
|
||||
if value_str is None or pd.isna(value_str) or str(value_str).strip() == '':
|
||||
return 0 # Leer oder k.A. -> 0
|
||||
|
||||
raw_value_str = str(value_str).strip()
|
||||
if raw_value_str.lower() in ['k.a.', 'n/a', '-']:
|
||||
return 0
|
||||
|
||||
try:
|
||||
# Bereinigung ähnlich wie in clean_text und extract_numeric_value
|
||||
processed_value = clean_text(raw_value_str) # Annahme: clean_text existiert
|
||||
if processed_value == "k.A.": return 0
|
||||
|
||||
processed_value = re.sub(r'(?i)^\s*(ca\.?|circa|rund|etwa|über|unter|mehr als|weniger als|bis zu)\s+', '', processed_value)
|
||||
processed_value = re.sub(r'[€$£¥]', '', processed_value).strip()
|
||||
processed_value = re.split(r'\s*(-|–|bis)\s*', processed_value, 1)[0].strip()
|
||||
processed_value_no_thousands = processed_value.replace('.', '').replace("'", "") # Entferne Punkte UND Apostrophe als Tausendertrenner
|
||||
processed_value_final = processed_value_no_thousands.replace(',', '.') # Ersetze Komma durch Punkt für Dezimaltrennung
|
||||
|
||||
match = re.search(r'([\d.]+)', processed_value_final)
|
||||
if not match:
|
||||
# logging.debug(f"get_numeric_filter_value: Keine numerischen Zeichen gefunden in '{processed_value_final}'")
|
||||
return 0 # Keine numerischen Zeichen gefunden
|
||||
|
||||
num_str = match.group(1)
|
||||
if not num_str or num_str == '.': return 0 # Leerer oder nur Punkt String
|
||||
|
||||
num = float(num_str) # Konvertiere zum float
|
||||
|
||||
# --- Einheiten-Skalierung basierend auf ORIGINALSTRING ---
|
||||
# Dies ist der kritische Teil für den Umsatz aus Spalte J, wenn er Einheiten enthalten kann
|
||||
original_lower = raw_value_str.lower()
|
||||
scale_factor = 1.0 # Skalierungsfaktor, um alles in die Basiseinheit zu bringen (z.B. 1 für Tsd, 1000 für Mio, 1000000 für Mrd)
|
||||
is_scaled = False # Flag, ob eine Einheit gefunden wurde
|
||||
|
||||
if re.search(r'\bmrd\s*\b|\bmilliarden\s*\b|\bbillion\s*\b', original_lower):
|
||||
scale_factor = 1000000.0 # 1 Mrd = 1000 Mio, also 1000*1000 = 1.000.000 Base units (assuming base is 1)
|
||||
is_scaled = True
|
||||
elif re.search(r'\bmio\s*\b|\bmillionen\s*\b|\bmill\.\s*\b', original_lower):
|
||||
# Wenn der Wert bereits in Millionen angegeben ist (wie Spalte J),
|
||||
# und die Einheit 'Mio' gefunden wird, muss keine Skalierung angewendet werden,
|
||||
# da wir das Ergebnis in Millionen benötigen.
|
||||
# ABER: Wir müssen prüfen, ob der *Schwellenwert* in Millionen ist.
|
||||
# Der min_umsatz ist in Millionen (z.B. 200). Wir wollen den Wert in Spalte J
|
||||
# auch in Millionen haben für den Vergleich.
|
||||
# Wenn Original "6815", Einheit "Mio" -> num=6815, scale_factor=1, Ergebnis=6815 (Mio)
|
||||
# Wenn Original "6.8 Mrd", Einheit "Mrd" -> num=6.8, scale_factor=1000 (Mio), Ergebnis=6800 (Mio)
|
||||
# Das ist komplex. Vereinfachte Annahme: Wenn "Mrd" gefunden, multipliziere mit 1000 für Mio.
|
||||
# Wenn "Tsd" gefunden, teile durch 1000 für Mio.
|
||||
# Wenn "Mio" oder keine Einheit gefunden, nehme Zahl direkt als Mio.
|
||||
if is_umsatz:
|
||||
if re.search(r'\bmrd\s*\b|\bmilliarden\s*\b|\bbillion\s*\b', original_lower): # Wenn Mrd gefunden
|
||||
num = num * 1000.0 # Skaliere zu Millionen
|
||||
is_scaled = True
|
||||
elif re.search(r'\btsd\s*\b|\btausend\s*\b', original_lower): # Wenn Tsd gefunden
|
||||
num = num / 1000.0 # Skaliere zu Millionen
|
||||
is_scaled = True
|
||||
# Wenn "Mio" gefunden oder keine Einheit und is_umsatz=True,
|
||||
# nehmen wir an, der Wert ist bereits in Millionen, keine weitere Skalierung nötig.
|
||||
elif re.search(r'\btsd\s*\b|\btausend\s*\b', original_lower): # Wenn Tsd gefunden (für MA)
|
||||
num = num * 1000.0 # Skaliere zu Tausendern
|
||||
is_scaled = True
|
||||
# Andere Einheiten (Mio, Mrd für MA) werden hier ignoriert, was bei MA OK ist.
|
||||
|
||||
|
||||
# Das Ergebnis muss 0 oder positiv sein für die Filterlogik
|
||||
result_num = num if num > 0 else 0 # Werte <= 0 zählen nicht
|
||||
|
||||
if is_umsatz:
|
||||
# Rückgabe als Wert in Millionen
|
||||
# Wenn keine Einheit gefunden wurde (und is_umsatz), gehen wir davon aus, dass es Millionen sind.
|
||||
# Wenn eine Einheit (Tsd, Mrd) gefunden und skaliert wurde, ist es auch in Millionen.
|
||||
return result_num # Der Wert sollte jetzt in Millionen sein, bereit für Vergleich mit min_umsatz
|
||||
|
||||
else: # Mitarbeiterzahl
|
||||
# Rückgabe als ganze Zahl
|
||||
return round(result_num) # Mitarbeiterzahl runden
|
||||
|
||||
except Exception as e:
|
||||
logging.debug(f"Fehler in get_numeric_filter_value für Wert '{raw_value_str}': {e}")
|
||||
return 0
|
||||
|
||||
# --- Ende Hilfsfunktion für Filter ---
|
||||
|
||||
|
||||
# Nun die process_find_wiki_with_serp Funktion mit der neuen Logik
|
||||
|
||||
def process_find_wiki_with_serp(sheet_handler, row_limit=None, min_employees=500, min_umsatz=200):
|
||||
"""
|
||||
Sucht fehlende Wikipedia-URLs (Spalte M = k.A.) für Unternehmen mit
|
||||
(Umsatz CRM > min_umsatz ODER Mitarbeiter CRM > min_employees)
|
||||
(Umsatz CRM > min_umsatz MIO € ODER Mitarbeiter CRM > min_employees)
|
||||
über SerpAPI und trägt gefundene URLs in Spalte M ein. Setzt ReEval-Flag (A)
|
||||
und löscht abhängige Wiki-Spalten (N-V, AN, AO, AP, AX).
|
||||
Merkt sich in Spalte AY, wann die Suche durchgeführt wurde.
|
||||
@@ -379,9 +473,9 @@ def process_find_wiki_with_serp(sheet_handler, row_limit=None, min_employees=500
|
||||
sheet_handler (GoogleSheetHandler): Initialisierte Instanz.
|
||||
row_limit (int, optional): Maximale Anzahl zu prüfender Zeilen. Defaults to None.
|
||||
min_employees (int, optional): Mindestanzahl Mitarbeiter (Spalte K) als Teilfilter. Defaults to 500.
|
||||
min_umsatz (int, optional): Mindestumsatz (Spalte J) als Teilfilter. Defaults to 200.
|
||||
min_umsatz (int, optional): Mindestumsatz in MIO € (Spalte J) als Teilfilter. Defaults to 200.
|
||||
"""
|
||||
logging.info(f"Starte Modus 'find_wiki_serp': Suche fehlende Wiki-URLs für Firmen mit (Umsatz CRM > {min_umsatz} ODER Mitarbeiter CRM > {min_employees})...")
|
||||
logging.info(f"Starte Modus 'find_wiki_serp': Suche fehlende Wiki-URLs für Firmen mit (Umsatz CRM > {min_umsatz} MIO € ODER Mitarbeiter CRM > {min_employees})...")
|
||||
|
||||
if not sheet_handler.load_data(): return
|
||||
all_data = sheet_handler.get_all_data_with_headers()
|
||||
@@ -396,7 +490,7 @@ def process_find_wiki_with_serp(sheet_handler, row_limit=None, min_employees=500
|
||||
# Verwenden Sie hier das COLUMN_MAP robust
|
||||
col_indices = {}
|
||||
required_keys = [
|
||||
"ReEval Flag", "CRM Anzahl Mitarbeiter", "CRM Umsatz", "Wiki URL", "CRM Name",
|
||||
"ReEval Flag", "CRM Anzahl Mitarbeiter", "CRM Umsatz", "Wiki URL", "CRM Name", "CRM Website", # Website wird jetzt für SerpAPI Suche benötigt
|
||||
"Wiki Absatz", "Wiki Branche", "Wiki Umsatz", "Wiki Mitarbeiter", "Wiki Kategorien",
|
||||
"Chat Wiki Konsistenzprüfung", "Chat Begründung Wiki Inkonsistenz", "Chat Vorschlag Wiki Artikel",
|
||||
"Begründung bei Abweichung", "Wikipedia Timestamp", "Timestamp letzte Prüfung",
|
||||
@@ -426,48 +520,6 @@ def process_find_wiki_with_serp(sheet_handler, row_limit=None, min_employees=500
|
||||
|
||||
now_timestamp_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# --- Hilfsfunktion zur sicheren numerischen Extraktion (adaptiert von prepare_data_for_modeling) ---
|
||||
def safe_numeric_extract(value_str):
|
||||
if value_str is None or pd.isna(value_str) or str(value_str).strip() == '': return 0 # Return 0, nicht NaN, für die Vergleichslogik
|
||||
try:
|
||||
# Annahme: clean_text existiert
|
||||
processed_value = clean_text(str(value_str))
|
||||
if processed_value == "k.A.": return 0
|
||||
|
||||
processed_value = re.sub(r'(?i)^\s*(ca\.?|circa|rund|etwa|über|unter|mehr als|weniger als|bis zu)\s+', '', processed_value)
|
||||
processed_value = re.sub(r'[€$£¥]', '', processed_value).strip()
|
||||
processed_value = re.split(r'\s*(-|–|bis)\s*', processed_value, 1)[0].strip()
|
||||
# Entferne Punkte UND Apostrophe als Tausendertrenner, ersetze Komma durch Punkt
|
||||
processed_value = processed_value.replace('.', '').replace("'", "").replace(',', '.')
|
||||
|
||||
match = re.search(r'([\d.]+)', processed_value)
|
||||
if not match: return 0 # Keine numerischen Zeichen gefunden
|
||||
|
||||
num_str = match.group(1)
|
||||
if not num_str or num_str == '.': return 0
|
||||
|
||||
num = float(num_str)
|
||||
|
||||
# Einheiten-Multiplikatoren (Mrd, Mio, Tsd) - Wichtig für Umsatz
|
||||
multiplier = 1.0
|
||||
original_lower = str(value_str).lower() # Nutze den Originalstring für Einheiten
|
||||
if "mrd" in original_lower or "milliarden" in original_lower or "billion" in original_lower: multiplier = 1000000000.0
|
||||
elif "mio" in original_lower or "millionen" in original_lower or "mill." in original_lower: multiplier = 1000000.0
|
||||
elif "tsd" in original_lower or "tausend" in original_lower: multiplier = 1000.0
|
||||
|
||||
num = num * multiplier
|
||||
|
||||
# Für den Vergleich (Umsatz in Mio, Mitarbeiter int)
|
||||
# Umsatz soll > 200 MIO sein, also num direkt mit 200,000,000 vergleichen
|
||||
# Mitarbeiter > 500, num direkt mit 500 vergleichen
|
||||
# Geben Sie den Rohwert nach Multiplikator zurück
|
||||
return num if num > 0 else 0 # Nur positive Werte zählen
|
||||
|
||||
except Exception as e:
|
||||
logging.debug(f"Fehler in safe_numeric_extract für Wert '{str(value_str)[:50]}...': {e}")
|
||||
return 0
|
||||
# --- Ende Hilfsfunktion ---
|
||||
|
||||
|
||||
# Iteriere durch die Datenzeilen
|
||||
for idx, row in enumerate(data_rows):
|
||||
@@ -493,7 +545,7 @@ def process_find_wiki_with_serp(sheet_handler, row_limit=None, min_employees=500
|
||||
|
||||
# Prüfe Wiki URL (M): Überspringe, wenn bereits gefüllt (nicht k.A. oder leer)
|
||||
m_value = row[col_indices["Wiki URL"]]
|
||||
if m_value and str(m_value).strip().lower() != "k.a.": # Jetzt auch 'leer' abfangen? Nein, '' ist schon abgedeckt
|
||||
if m_value and str(m_value).strip().lower() != "k.a.":
|
||||
skipped_m_filled_count += 1
|
||||
continue
|
||||
|
||||
@@ -501,20 +553,21 @@ def process_find_wiki_with_serp(sheet_handler, row_limit=None, min_employees=500
|
||||
umsatz_val_str = row[col_indices["CRM Umsatz"]]
|
||||
ma_val_str = row[col_indices["CRM Anzahl Mitarbeiter"]]
|
||||
|
||||
umsatz_val_num = safe_numeric_extract(umsatz_val_str)
|
||||
ma_val_num = safe_numeric_extract(ma_val_str)
|
||||
# Nutze die neue Hilfsfunktion, um die Werte für den Vergleich zu bekommen
|
||||
umsatz_val_mio = get_numeric_filter_value(umsatz_val_str, is_umsatz=True) # Ergebnis in Mio €
|
||||
ma_val_num = get_numeric_filter_value(ma_val_str, is_umsatz=False) # Ergebnis als Integer
|
||||
|
||||
# Filterlogik: Umsatz > min_umsatz ODER Mitarbeiter > min_employees
|
||||
# Filterlogik: Umsatz > min_umsatz MIO € ODER Mitarbeiter > min_employees
|
||||
# Wenn *nicht* (Umsatz > min_umsatz ODER Mitarbeiter > min_employees), dann überspringe
|
||||
if not (umsatz_val_num > min_umsatz * 1000000 or ma_val_num > min_employees):
|
||||
logging.debug(f"Zeile {row_num_in_sheet}: Übersprungen (Größe nicht ausreichend. Umsatz: {umsatz_val_num:.0f}, MA: {ma_val_num}).")
|
||||
if not (umsatz_val_mio > min_umsatz or ma_val_num > min_employees):
|
||||
logging.debug(f"Zeile {row_num_in_sheet}: Übersprungen (Größe nicht ausreichend. Umsatz (Mio): {umsatz_val_mio:.2f}, MA: {ma_val_num}). Schwellen: Umsatz > {min_umsatz} Mio, MA > {min_employees}.")
|
||||
skipped_size_count += 1
|
||||
continue
|
||||
# --- Ende Größenprüfung ---
|
||||
|
||||
|
||||
# Kandidat gefunden: M leer/k.A., AY leer, und Größe passt
|
||||
company_name = row[col_indices["CRM Name"]] if len(row) > col_indices["CRM Name"] else ""
|
||||
company_name = row[col_indices["CRM Name"]]
|
||||
if not company_name or str(company_name).strip() == "":
|
||||
logging.warning(f"Zeile {row_num_in_sheet}: Übersprungen, kein Firmenname für Suche vorhanden.")
|
||||
# Setze AY Timestamp, damit wir nicht immer wieder versuchen
|
||||
@@ -523,12 +576,13 @@ def process_find_wiki_with_serp(sheet_handler, row_limit=None, min_employees=500
|
||||
continue
|
||||
|
||||
# SerpAPI Suche
|
||||
logging.info(f"Zeile {row_num_in_sheet}: Suche Wiki-URL für '{company_name}' (Umsatz: {umsatz_val_num:.0f}, MA: {ma_val_num})...")
|
||||
logging.info(f"Zeile {row_num_in_sheet}: Suche Wiki-URL für '{company_name}' (Umsatz (Mio): {umsatz_val_mio:.2f}, MA: {ma_val_num})...")
|
||||
processed_rows_count += 1 # Zähle VOR dem Call, dass ein Versuch gestartet wird
|
||||
|
||||
# Hole Website für SerpAPI Kontext
|
||||
website_url = row[col_indices["CRM Website"]] if col_indices["CRM Website"] is not None and len(row) > col_indices["CRM Website"] else None
|
||||
|
||||
# Annahme: serp_wikipedia_lookup existiert und nutzt logging/retry
|
||||
# website_url wird nicht direkt im SerpAPI Lookup verwendet, kann aber als Kontext hilfreich sein
|
||||
website_url = row[COLUMN_MAP.get("CRM Website", -1)] if COLUMN_MAP.get("CRM Website", -1) != -1 and len(row) > COLUMN_MAP.get("CRM Website", -1) else None
|
||||
wiki_url_found = serp_wikipedia_lookup(company_name, website=website_url)
|
||||
|
||||
# Updates vorbereiten
|
||||
@@ -541,12 +595,14 @@ def process_find_wiki_with_serp(sheet_handler, row_limit=None, min_employees=500
|
||||
logging.info(f" -> URL gefunden: {wiki_url_found}. Bereite Update vor (Setze M, A; Lösche N-V, AN, AO, AP, AX).")
|
||||
found_urls_count += 1
|
||||
|
||||
# Zusätzliche Updates für gefundene URL
|
||||
# Indizes und Buchstaben für Updates holen
|
||||
m_l = col_letters["Wiki URL"]
|
||||
a_l = col_letters["ReEval Flag"]
|
||||
# Spalten N-V leeren
|
||||
n_l = col_letters["Wiki Absatz"]
|
||||
v_l = col_letters["Begründung bei Abweichung"]
|
||||
n_idx = col_indices["Wiki Absatz"]
|
||||
v_idx = col_indices["Begründung bei Abweichung"]
|
||||
n_l=sheet_handler._get_col_letter(n_idx+1)
|
||||
v_l=sheet_handler._get_col_letter(v_idx+1)
|
||||
# Timestamps AN, AO, AX, Version AP leeren
|
||||
an_l = col_letters["Wikipedia Timestamp"]
|
||||
ao_l = col_letters["Timestamp letzte Prüfung"]
|
||||
@@ -557,9 +613,9 @@ def process_find_wiki_with_serp(sheet_handler, row_limit=None, min_employees=500
|
||||
all_sheet_updates.extend([
|
||||
{'range': f'{m_l}{row_num_in_sheet}', 'values': [[wiki_url_found]]}, # URL setzen in M
|
||||
{'range': f'{a_l}{row_num_in_sheet}', 'values': [['x']]}, # ReEval Flag setzen in A
|
||||
# --- Spalten leeren, damit sie neu befüllt werden ---
|
||||
# --- Spalten N-V leeren, damit sie neu befüllt werden ---
|
||||
# Range N:V leeren
|
||||
{'range': f'{n_l}{row_num_in_sheet}:{v_l}{row_num_in_sheet}', 'values': [[''] * (col_indices["Begründung bei Abweichung"] - col_indices["Wiki Absatz"] + 1)]},
|
||||
{'range': f'{n_l}{row_num_in_sheet}:{v_l}{row_num_in_sheet}', 'values': [[''] * (v_idx - n_idx + 1)]},
|
||||
{'range': f'{an_l}{row_num_in_sheet}', 'values': [['']]}, # AN leeren
|
||||
{'range': f'{ao_l}{row_num_in_sheet}', 'values': [['']]}, # AO leeren
|
||||
{'range': f'{ap_l}{row_num_in_sheet}', 'values': [['']]}, # AP leeren
|
||||
|
||||
Reference in New Issue
Block a user