v1.6.3: Beschleunige Website-Scraping durch gebündelte Sheet-Updates

- Überarbeite `process_website_batch` zur Leistungssteigerung.
- Implementiere das Sammeln von Zell-Updates (`AR`, `AS`, `AT`, `AP`) für mehrere Zeilen in einer Liste (`all_sheet_updates`).
- Sende die gesammelten Updates gebündelt über einen einzigen `batch_update_cells`-Aufruf an Google Sheets, wenn ein Limit (`update_batch_row_limit`) erreicht ist oder die Schleife endet.
- Ziel: Reduzierung der Anzahl von Google Sheets API-Aufrufen und Beschleunigung des Website-Scraping-Prozesses.
- Stelle sicher, dass auch ein letzter, unvollständiger Batch nach der Hauptschleife gesendet wird.
This commit is contained in:
2025-04-17 08:45:18 +00:00
parent b0c792d706
commit 8922c7d41b

View File

@@ -1,14 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
v1.6.2: Verfeinere Timestamp-Logik & integriere ML-Datenvorbereitung v1.6.3: Beschleunige Website-Scraping durch gebündelte Sheet-Updates
Git-Änderungsbeschreibung: Git-Änderungsbeschreibung:
- Passe Dispatcher (`run_dispatcher`) und `GoogleSheetHandler.get_start_row_index` an, um den Startpunkt basierend auf dem Website Scrape Timestamp (Spalte AT) zu bestimmen. - Überarbeite `process_website_batch` zur Leistungssteigerung.
- Implementiere individuelle Timestamp-Prüfungen in den Batch-Funktionen (`process_verification_only` (AN), `process_website_batch` (AT), `process_branch_batch` (AO)), um das erneute Verarbeiten abgeschlossener Zeilen zu verhindern. - Implementiere das Sammeln von Zell-Updates (`AR`, `AS`, `AT`, `AP`) für mehrere Zeilen in einer Liste (`all_sheet_updates`).
- Überarbeite `_process_single_row` (`full_run`, `reeval`), um für jeden Teilbereich (Wiki, Website, Chat) den zugehörigen Timestamp zu prüfen und nur bei Bedarf auszuführen. - Sende die gesammelten Updates gebündelt über einen einzigen `batch_update_cells`-Aufruf an Google Sheets, wenn ein Limit (`update_batch_row_limit`) erreicht ist oder die Schleife endet.
- Passe `_process_batch` an, sodass es nur noch Ergebnisspalten (S-Y) schreibt; Timestamps werden jetzt von der aufrufenden Funktion gesetzt. - Ziel: Reduzierung der Anzahl von Google Sheets API-Aufrufen und Beschleunigung des Website-Scraping-Prozesses.
- Füge neue Spalten (AT: Website TS, AU: Gesch. Techniker Bucket, AV: Finaler Umsatz, AW: Finaler MA) zur `alignment_demo` und `COLUMN_MAP` hinzu. - Stelle sicher, dass auch ein letzter, unvollständiger Batch nach der Hauptschleife gesendet wird.
- Integriere die Funktion `prepare_data_for_modeling` als Methode in die `DataProcessor`-Klasse (wird noch nicht aktiv in einem Modus aufgerufen).
""" """
import os import os
@@ -52,7 +51,7 @@ LOG_DIR = "Log"
# ==================== KONFIGURATION ==================== # ==================== KONFIGURATION ====================
class Config: class Config:
VERSION = "v1.6.2" VERSION = "v1.6.3"
LANG = "de" LANG = "de"
SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo" SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo"
MAX_RETRIES = 3 MAX_RETRIES = 3
@@ -2207,11 +2206,12 @@ def _process_batch(sheet, batches, row_numbers):
# time.sleep(Config.RETRY_DELAY) # Entfernt # time.sleep(Config.RETRY_DELAY) # Entfernt
# Komplette Funktion process_website_batch (prüft jetzt Timestamp AT mit erzwungenem Debugging) # Komplette Funktion process_website_batch (prüft jetzt Timestamp AT mit erzwungenem Debugging)
# Komplette Funktion process_website_batch (MIT Batched Google Sheet Updates)
def process_website_batch(sheet_handler, start_row_index_in_sheet, end_row_index_in_sheet): def process_website_batch(sheet_handler, start_row_index_in_sheet, end_row_index_in_sheet):
""" """
Batch-Prozess für Website-Scraping. Lädt Daten neu, prüft für jede Zeile Batch-Prozess für Website-Scraping. Lädt Daten neu, prüft für jede Zeile
im Bereich, ob Timestamp AT bereits gesetzt ist und überspringt diese ggf. im Bereich, ob Timestamp AT bereits gesetzt ist und überspringt diese ggf.
Setzt AT + AP für bearbeitete Zeilen. Setzt AT + AP für bearbeitete Zeilen. Sendet Updates in Batches an Google Sheets.
""" """
debug_print(f"Starte Website-Scraping (Batch) für Zeilen {start_row_index_in_sheet} bis {end_row_index_in_sheet}...") debug_print(f"Starte Website-Scraping (Batch) für Zeilen {start_row_index_in_sheet} bis {end_row_index_in_sheet}...")
@@ -2223,7 +2223,7 @@ def process_website_batch(sheet_handler, start_row_index_in_sheet, end_row_index
debug_print("FEHLER/WARNUNG: Keine Daten zum Verarbeiten in process_website_batch gefunden.") debug_print("FEHLER/WARNUNG: Keine Daten zum Verarbeiten in process_website_batch gefunden.")
return return
sheet = sheet_handler.sheet # Hole Indizes und Spaltenbuchstaben (wie zuvor)
timestamp_col_key = "Website Scrape Timestamp" timestamp_col_key = "Website Scrape Timestamp"
timestamp_col_index = COLUMN_MAP.get(timestamp_col_key) timestamp_col_index = COLUMN_MAP.get(timestamp_col_key)
website_col_idx = COLUMN_MAP.get("CRM Website") website_col_idx = COLUMN_MAP.get("CRM Website")
@@ -2240,71 +2240,88 @@ def process_website_batch(sheet_handler, start_row_index_in_sheet, end_row_index
summary_col_letter = sheet_handler._get_col_letter(summary_col_idx + 1) summary_col_letter = sheet_handler._get_col_letter(summary_col_idx + 1)
version_col_letter = sheet_handler._get_col_letter(version_col_idx + 1) version_col_letter = sheet_handler._get_col_letter(version_col_idx + 1)
# --- NEU: Liste für gesammelte Updates ---
all_sheet_updates = []
rows_in_current_batch = 0
update_batch_size = Config.BATCH_SIZE * 4 # Da wir 4 Zellen pro Zeile updaten, Batch entsprechend anpassen? Oder einfach 50?
# Nehmen wir eine feste Anzahl von Zeilen, deren Updates wir sammeln
update_batch_row_limit = 50 # Sammle Updates für 50 Zeilen, bevor gesendet wird
processed_count = 0 processed_count = 0
skipped_count = 0 skipped_count = 0
skipped_url_count = 0 skipped_url_count = 0
for i in range(start_row_index_in_sheet, end_row_index_in_sheet + 1): for i in range(start_row_index_in_sheet, end_row_index_in_sheet + 1):
row_index_in_list = i - 1 row_index_in_list = i - 1
if row_index_in_list >= len(all_data): if row_index_in_list >= len(all_data): continue
debug_print(f"Warnung (Website): Zeilenindex {row_index_in_list} außerhalb des Datenbereichs ({len(all_data)} Zeilen).")
continue
row = all_data[row_index_in_list] row = all_data[row_index_in_list]
# --- Timestamp-Prüfung für jede Zeile (AT) --- # --- Timestamp-Prüfung (AT) ---
ts_value_at = "INDEX_FEHLER"
should_skip = False should_skip = False
if len(row) > timestamp_col_index: if len(row) > timestamp_col_index:
ts_value_at = row[timestamp_col_index] if str(row[timestamp_col_index]).strip():
if str(ts_value_at).strip():
should_skip = True should_skip = True
# Optional: Debugging der Prüfung reduzieren
# if i % 100 == 0: debug_print(f"Zeile {i} (Website Check): Prüfe TS {ts_col_letter}. Überspringen? -> {should_skip}")
# Debug Log
log_debug = (i < start_row_index_in_sheet + 5 or i > end_row_index_in_sheet - 5 or i % 500 == 0 or i in range(2122, 2132))
if log_debug:
debug_print(f"Zeile {i} (Website Check): Prüfe Timestamp {ts_col_letter}. Rohwert='{ts_value_at}'. Überspringen? -> {should_skip}")
# --- ABSOLUT KRITISCH: Korrekte IF/ELSE Struktur ---
if should_skip: if should_skip:
# Wenn should_skip True ist, wird NUR das hier ausgeführt
# debug_print(f"Zeile {i}: *** WIRD ÜBERSPRUNGEN (Timestamp AT vorhanden) ***") # Jetzt wirklich übersprungen
skipped_count += 1 skipped_count += 1
continue # Springt DIREKT zur nächsten Iteration der for-Schleife continue
else: else:
# --- Verarbeitung NUR, wenn should_skip False war --- # --- Verarbeitung (wenn nicht übersprungen) ---
debug_print(f"Zeile {i}: Timestamp AT nicht vorhanden oder leer. Verarbeitung wird gestartet.")
website_url = row[website_col_idx] if len(row) > website_col_idx else "" website_url = row[website_col_idx] if len(row) > website_col_idx else ""
if not website_url or website_url.strip().lower() == "k.a.": if not website_url or website_url.strip().lower() == "k.a.":
skipped_url_count += 1 skipped_url_count += 1
# Wichtig: Auch hier continue, um leere Updates zu vermeiden
continue continue
debug_print(f"Zeile {i}: Verarbeite Website {website_url}...") # Scrapen und Zusammenfassen
raw_text = get_website_raw(website_url) raw_text = get_website_raw(website_url)
summary = summarize_website_content(raw_text) summary = summarize_website_content(raw_text)
processed_count += 1 processed_count += 1
updates = [] # Einzelne Updates für diese Zeile vorbereiten
current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
current_version = Config.VERSION current_version = Config.VERSION
row_updates = [
{'range': f'{rohtext_col_letter}{i}', 'values': [[raw_text]]},
{'range': f'{summary_col_letter}{i}', 'values': [[summary]]},
{'range': f'{ts_col_letter}{i}', 'values': [[current_timestamp]]}, # AT Timestamp
{'range': f'{version_col_letter}{i}', 'values': [[current_version]]} # AP Version
]
updates.append({'range': f'{rohtext_col_letter}{i}', 'values': [[raw_text]]}) # --- NEU: Updates sammeln ---
updates.append({'range': f'{summary_col_letter}{i}', 'values': [[summary]]}) all_sheet_updates.extend(row_updates)
updates.append({'range': f'{ts_col_letter}{i}', 'values': [[current_timestamp]]}) # AT Timestamp rows_in_current_batch += 1
updates.append({'range': f'{version_col_letter}{i}', 'values': [[current_version]]}) # AP Version
if updates: # --- NEU: Batch senden, wenn Limit erreicht oder letzte Zeile ---
success = sheet_handler.batch_update_cells(updates) # Prüfe, ob die Anzahl der *Zeilen*, deren Updates gesammelt wurden, das Limit erreicht
if success: if rows_in_current_batch >= update_batch_row_limit or i == end_row_index_in_sheet:
debug_print(f"Zeile {i}: Website-Daten erfolgreich aktualisiert.") if all_sheet_updates: # Nur senden, wenn Updates vorhanden sind
else: debug_print(f"Sende Batch-Update für {rows_in_current_batch} Zeilen (insgesamt {len(all_sheet_updates)} Zellen)...")
debug_print(f"FEHLER beim Schreiben der Website-Updates für Zeile {i}.") success = sheet_handler.batch_update_cells(all_sheet_updates)
if success:
debug_print(f"Sheet-Update für Zeilen bis {i} erfolgreich.")
else:
debug_print(f"FEHLER beim Sheet-Update für Zeilen bis {i}.")
# Optional: Hier überlegen, ob man abbricht oder weitermacht
# Liste und Zähler zurücksetzen
all_sheet_updates = []
rows_in_current_batch = 0
# Kurze Pause nach jeder Website-Verarbeitung (oder nur nach Batch-Update?)
# Besser hier lassen, um APIs nicht zu überlasten
time.sleep(Config.RETRY_DELAY) time.sleep(Config.RETRY_DELAY)
# --- Ende des ELSE-Blocks --- # --- Ende ELSE-Block ---
# --- NEU: Ggf. letzte gesammelte Updates senden ---
if all_sheet_updates:
debug_print(f"Sende letztes Batch-Update für {rows_in_current_batch} Zeilen ({len(all_sheet_updates)} Zellen)...")
success = sheet_handler.batch_update_cells(all_sheet_updates)
if success:
debug_print(f"Letztes Sheet-Update erfolgreich.")
else:
debug_print(f"FEHLER beim letzten Sheet-Update.")
debug_print(f"Website-Scraping (Batch) abgeschlossen. {processed_count} Websites gescraped, {skipped_count} Zeilen wg. Timestamp übersprungen, {skipped_url_count} Zeilen ohne URL übersprungen.") debug_print(f"Website-Scraping (Batch) abgeschlossen. {processed_count} Websites gescraped, {skipped_count} Zeilen wg. Timestamp übersprungen, {skipped_url_count} Zeilen ohne URL übersprungen.")