This commit is contained in:
2025-04-15 14:54:01 +00:00
parent 28d43cd4d4
commit c5b3089c1c

View File

@@ -2465,13 +2465,16 @@ class DataProcessor:
# ==================== MAIN FUNCTION ====================
# ==================== MAIN FUNCTION ====================
def main():
global MODE, LOG_FILE # MODE wieder global, da es in älteren Teilen evtl. noch referenziert wird? Besser wäre es zu übergeben.
# global MODE, LOG_FILE # MODE wird nicht mehr global benötigt, aber LOG_FILE schon
# -> MODE wird unten neu gesetzt, kein global nötig. LOG_FILE wird global gesetzt.
global LOG_FILE
# --- Initialisierung ---
# Argument Parser
parser = argparse.ArgumentParser(description="Firmen-Datenanreicherungs-Skript")
parser.add_argument("--mode", type=str, help="Betriebsmodus (z.B. combined, wiki, website, branch, reeval, website_lookup, website_details, contacts, full_run)")
parser.add_argument("--limit", type=int, help="Maximale Anzahl zu verarbeitender Zeilen (für Batch/sequentielle Modi)", default=None) # Korrekter Name: --limit
# HIER KORRIGIERT: --limit statt --row_limit
parser.add_argument("--limit", type=int, help="Maximale Anzahl zu verarbeitender Zeilen (für Batch/sequentielle Modi)", default=None)
args = parser.parse_args()
# Lade API Keys
@@ -2480,60 +2483,168 @@ def main():
# Betriebsmodus ermitteln
valid_modes = ["combined", "wiki", "website", "branch", "reeval", "website_lookup", "website_details", "contacts", "full_run"]
mode = None
# --> NEUE LOGIK: Priorisiere Kommandozeilenargumente
# Priorisiere Kommandozeilenargumente
if args.mode and args.mode.lower() in valid_modes:
mode = args.mode.lower()
print(f"Betriebsmodus (aus Kommandozeile): {mode}")
else:
# Nur wenn KEIN Modus über die Kommandozeile kam, FRAGE interaktiv
print("Bitte wählen Sie den Betriebsmodus:")
# ... (Liste der Modi ausgeben) ...
mode_input = input(f"Geben Sie den Modus ein ({', '.join(valid_modes)}): ").strip().lower()
if mode_input in valid_modes:
mode = mode_input
else:
print("Ungültige Eingabe. Standardmodus 'combined' wird verwendet.")
mode = "combined" # Standardmodus
print(" combined: Wiki-Verifizierung, Website-Scraping & Branch-Einschätzung (Batch, ab erster leerer Zeile)")
print(" wiki: Nur Wikipedia-Verifizierung (Batch, ab erster leerer Zeile)")
print(" website: Nur Website-Scraping & Zusammenfassung (Batch, ab erster leerer Zeile)")
print(" branch: Nur Branchen-Einschätzung (Batch, ab erster leerer Zeile)")
print(" reeval: Verarbeitet alle Zeilen mit 'x' in Spalte A (volle Verarbeitung)")
print(" website_lookup: Sucht fehlende Websites (Spalte D) via SERP API")
print(" website_details:Extrahiert Title/Desc/H-Tags für Zeilen mit 'x' in Spalte A")
print(" contacts: Sucht LinkedIn Kontakte via SERP API und schreibt in 'Contacts' Blatt")
print(" full_run: Verarbeitet alle Zeilen sequentiell ab der ersten ohne Zeitstempel (AO)")
try:
mode_input = input(f"Geben Sie den Modus ein ({', '.join(valid_modes)}): ").strip().lower()
if mode_input in valid_modes:
mode = mode_input
else:
print("Ungültige Eingabe. Standardmodus 'combined' wird verwendet.")
mode = "combined" # Standardmodus
# Füge eine Sicherheitsprüfung hinzu, falls input() in nohup aufgerufen wird
except OSError as e:
if e.errno == 9: # Bad file descriptor
print("Fehler: Interaktive Modus-Abfrage nicht möglich (läuft im Hintergrund?). Standardmodus 'combined' wird verwendet.")
mode = "combined"
else:
print(f"Unerwarteter OS-Fehler bei Modus-Abfrage: {e}")
print("Standardmodus 'combined' wird verwendet.")
mode = "combined"
except EOFError: # Kann auftreten, wenn stdin geschlossen ist (z.B. bei nohup)
print("Fehler: Interaktive Modus-Abfrage nicht möglich (EOF). Standardmodus 'combined' wird verwendet.")
mode = "combined"
# Zeilenlimit ermitteln
row_limit = None
# --> NEUE LOGIK: Priorisiere Kommandozeilenargumente
if args.limit is not None: # Prüfe, ob --limit gesetzt wurde
row_limit = args.limit
print(f"Zeilenlimit (aus Kommandozeile): {row_limit}")
# Priorisiere Kommandozeilenargumente
if args.limit is not None: # Prüfe, ob --limit explizit gesetzt wurde (auch wenn 0)
# Erlaube auch 0 als Limit (obwohl es nichts tut, ist es eine gültige Angabe)
if args.limit >= 0:
row_limit = args.limit
print(f"Zeilenlimit (aus Kommandozeile): {row_limit}")
else:
print("Warnung: Negatives Zeilenlimit ignoriert. Kein Limit gesetzt.")
row_limit = None
# Nur wenn KEIN Limit über die Kommandozeile kam UND es ein Modus ist, der ein Limit brauchen könnte, FRAGE interaktiv
elif mode in ["combined", "wiki", "website", "branch", "full_run"]:
try:
limit_input = input("Wie viele Zeilen sollen maximal bearbeitet werden? (Enter für alle) ")
if limit_input.strip():
row_limit = int(limit_input)
print(f"Zeilenlimit: {row_limit}")
limit_val = int(limit_input)
if limit_val >= 0:
row_limit = limit_val
print(f"Zeilenlimit: {row_limit}")
else:
print("Warnung: Negatives Zeilenlimit ignoriert. Kein Limit gesetzt.")
row_limit = None
else:
row_limit = None # Alle verarbeiten
print("Kein Zeilenlimit gesetzt.")
except ValueError:
print("Ungültige Eingabe für Zeilenlimit. Es werden alle Zeilen verarbeitet.")
print("Ungültige Eingabe für Zeilenlimit. Kein Limit gesetzt.")
row_limit = None
# Füge eine Sicherheitsprüfung hinzu, falls input() in nohup aufgerufen würde
# Füge eine Sicherheitsprüfung hinzu, falls input() in nohup aufgerufen wird
except OSError as e:
if e.errno == 9: # Bad file descriptor
print("Warnung: Interaktive Abfrage des Limits nicht möglich (läuft im Hintergrund?). Kein Limit gesetzt.")
row_limit = None
else:
raise # Anderen OSError weiterwerfen
print(f"Unerwarteter OS-Fehler bei Limit-Abfrage: {e}")
print("Kein Limit gesetzt.")
row_limit = None
except EOFError: # Kann auftreten, wenn stdin geschlossen ist
print("Warnung: Interaktive Abfrage des Limits nicht möglich (EOF). Kein Limit gesetzt.")
row_limit = None
# --- Rest der main() Funktion bleibt gleich ---
# Logfile initialisieren
LOG_FILE = create_log_filename(mode)
# ... (Logging der Startparameter) ...
# ... (Schema laden) ...
# ... (Sheet Handler initialisieren) ...
# ... (DataProcessor initialisieren) ...
# ... (Modusausführung) ...
# ... (Abschluss) ...
debug_print(f"===== Skript gestartet =====")
debug_print(f"Version: {Config.VERSION}")
debug_print(f"Betriebsmodus: {mode}")
debug_print(f"Zeilenlimit: {row_limit if row_limit is not None else 'Unbegrenzt'}")
debug_print(f"Logdatei: {LOG_FILE}")
# (Der Rest der Datei bleibt unverändert)
# --- Vorbereitung ---
# Lade Branchenschema
load_target_schema() # Stellt sicher, dass globale Variablen gesetzt sind
# Initialisiere Google Sheet Handler
try:
sheet_handler = GoogleSheetHandler()
except Exception as e:
debug_print(f"FATAL: Konnte Google Sheet Handler nicht initialisieren: {e}")
return # Abbruch
# Initialisiere DataProcessor
data_processor = DataProcessor(sheet_handler)
# Optional: Alignment Demo für Hauptblatt ausführen? (Bleibt auskommentiert)
# run_alignment = input("Sollen die Header im Hauptblatt aktualisiert werden (Alignment Demo)? (j/N): ").lower()
# if run_alignment == 'j':
# alignment_demo(sheet_handler.sheet)
# --- Modusausführung ---
start_time = time.time()
debug_print(f"Starte Verarbeitung um {datetime.now().strftime('%H:%M:%S')}...")
try:
if mode in ["wiki", "website", "branch", "combined"]:
run_dispatcher(mode, sheet_handler, row_limit)
elif mode == "reeval":
data_processor.process_reevaluation_rows()
elif mode == "website_lookup":
data_processor.process_serp_website_lookup_for_empty()
elif mode == "website_details":
data_processor.process_website_details_for_marked_rows()
elif mode == "contacts":
process_contact_research(sheet_handler) # Übergib den Handler
elif mode == "full_run":
start_index = sheet_handler.get_start_row_index() # Index in Datenliste (0-basiert)
if start_index < len(sheet_handler.get_data()): # Nur starten, wenn Startindex valide ist
num_available = len(sheet_handler.get_data()) - start_index
# Berechne Anzahl zu verarbeitender Zeilen basierend auf Limit
if row_limit is not None and row_limit >= 0:
num_to_process = min(row_limit, num_available)
else: # Kein Limit oder negatives Limit -> alle verfügbaren
num_to_process = num_available
if num_to_process > 0:
data_processor.process_rows_sequentially(start_index, num_to_process, process_wiki=True, process_chatgpt=True, process_website=True)
else:
debug_print("Keine Zeilen für 'full_run' zu verarbeiten (Limit 0 oder Startindex am Ende).")
else:
debug_print(f"Startindex {start_index} liegt hinter der letzten Datenzeile. Keine Verarbeitung für 'full_run'.")
else:
debug_print(f"Unbekannter Modus '{mode}' - keine Aktion ausgeführt.")
except Exception as e:
debug_print(f"FATAL: Unerwarteter Fehler auf oberster Ebene während der Modusausführung: {e}")
import traceback
debug_print(traceback.format_exc()) # Detaillierten Stacktrace loggen
# --- Abschluss ---
end_time = time.time()
duration = end_time - start_time
debug_print(f"Verarbeitung abgeschlossen um {datetime.now().strftime('%H:%M:%S')}.")
debug_print(f"Gesamtdauer: {duration:.2f} Sekunden.")
debug_print(f"===== Skript beendet =====")
# Sicherstellen, dass die letzte Log-Nachricht auch geschrieben wird
if LOG_FILE:
try:
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.write(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] ===== Skript wirklich beendet =====\n")
except: pass # Ignoriere Fehler beim letzten Schreiben
print(f"Verarbeitung abgeschlossen. Logfile: {LOG_FILE}")
# Führt die main-Funktion aus, wenn das Skript direkt gestartet wird
if __name__ == '__main__':
main()