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
"""
v1.6.2: Verfeinere Timestamp-Logik & integriere ML-Datenvorbereitung
v1.6.3: Beschleunige Website-Scraping durch gebündelte Sheet-Updates
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.
- 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.
- Ü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.
- Passe `_process_batch` an, sodass es nur noch Ergebnisspalten (S-Y) schreibt; Timestamps werden jetzt von der aufrufenden Funktion gesetzt.
- Füge neue Spalten (AT: Website TS, AU: Gesch. Techniker Bucket, AV: Finaler Umsatz, AW: Finaler MA) zur `alignment_demo` und `COLUMN_MAP` hinzu.
- Integriere die Funktion `prepare_data_for_modeling` als Methode in die `DataProcessor`-Klasse (wird noch nicht aktiv in einem Modus aufgerufen).
- Ü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.
"""
import os
@@ -52,7 +51,7 @@ LOG_DIR = "Log"
# ==================== KONFIGURATION ====================
class Config:
VERSION = "v1.6.2"
VERSION = "v1.6.3"
LANG = "de"
SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo"
MAX_RETRIES = 3
@@ -2207,11 +2206,12 @@ def _process_batch(sheet, batches, row_numbers):
# time.sleep(Config.RETRY_DELAY) # Entfernt
# 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):
"""
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.
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}...")
@@ -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.")
return
sheet = sheet_handler.sheet
# Hole Indizes und Spaltenbuchstaben (wie zuvor)
timestamp_col_key = "Website Scrape Timestamp"
timestamp_col_index = COLUMN_MAP.get(timestamp_col_key)
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)
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
skipped_count = 0
skipped_url_count = 0
for i in range(start_row_index_in_sheet, end_row_index_in_sheet + 1):
row_index_in_list = i - 1
if row_index_in_list >= len(all_data):
debug_print(f"Warnung (Website): Zeilenindex {row_index_in_list} außerhalb des Datenbereichs ({len(all_data)} Zeilen).")
continue
if row_index_in_list >= len(all_data): continue
row = all_data[row_index_in_list]
# --- Timestamp-Prüfung für jede Zeile (AT) ---
ts_value_at = "INDEX_FEHLER"
# --- Timestamp-Prüfung (AT) ---
should_skip = False
if len(row) > timestamp_col_index:
ts_value_at = row[timestamp_col_index]
if str(ts_value_at).strip():
if str(row[timestamp_col_index]).strip():
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:
# 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
continue # Springt DIREKT zur nächsten Iteration der for-Schleife
continue
else:
# --- Verarbeitung NUR, wenn should_skip False war ---
debug_print(f"Zeile {i}: Timestamp AT nicht vorhanden oder leer. Verarbeitung wird gestartet.")
# --- Verarbeitung (wenn nicht übersprungen) ---
website_url = row[website_col_idx] if len(row) > website_col_idx else ""
if not website_url or website_url.strip().lower() == "k.a.":
skipped_url_count += 1
# Wichtig: Auch hier continue, um leere Updates zu vermeiden
continue
debug_print(f"Zeile {i}: Verarbeite Website {website_url}...")
# Scrapen und Zusammenfassen
raw_text = get_website_raw(website_url)
summary = summarize_website_content(raw_text)
processed_count += 1
updates = []
# Einzelne Updates für diese Zeile vorbereiten
current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
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]]})
updates.append({'range': f'{summary_col_letter}{i}', 'values': [[summary]]})
updates.append({'range': f'{ts_col_letter}{i}', 'values': [[current_timestamp]]}) # AT Timestamp
updates.append({'range': f'{version_col_letter}{i}', 'values': [[current_version]]}) # AP Version
# --- NEU: Updates sammeln ---
all_sheet_updates.extend(row_updates)
rows_in_current_batch += 1
if updates:
success = sheet_handler.batch_update_cells(updates)
if success:
debug_print(f"Zeile {i}: Website-Daten erfolgreich aktualisiert.")
else:
debug_print(f"FEHLER beim Schreiben der Website-Updates für Zeile {i}.")
# --- NEU: Batch senden, wenn Limit erreicht oder letzte Zeile ---
# Prüfe, ob die Anzahl der *Zeilen*, deren Updates gesammelt wurden, das Limit erreicht
if rows_in_current_batch >= update_batch_row_limit or i == end_row_index_in_sheet:
if all_sheet_updates: # Nur senden, wenn Updates vorhanden sind
debug_print(f"Sende Batch-Update für {rows_in_current_batch} Zeilen (insgesamt {len(all_sheet_updates)} Zellen)...")
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)
# --- 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.")