From c1418c7283ae1f4ee4866a6b71df9a551f56b2e7 Mon Sep 17 00:00:00 2001 From: Floke Date: Wed, 2 Jul 2025 05:14:39 +0000 Subject: [PATCH] =?UTF-8?q?Initiales=20Setup=20f=C3=BCr=20Dealfront-Automa?= =?UTF-8?q?tisierung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Erstellt neues Hauptskript dealfront_enrichment.py - Integriert Selenium und webdriver-manager als neue Abhängigkeiten - Implementiert sichere Speicherung der Dealfront-Credentials in separater .json-Datei - Fügt dealfront_credentials.json zur .gitignore hinzu - Implementiert eine robuste Login-Klasse DealfrontScraper mit Verifizierung --- dealfront_enrichment.py | 169 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 dealfront_enrichment.py diff --git a/dealfront_enrichment.py b/dealfront_enrichment.py new file mode 100644 index 00000000..2d5f1762 --- /dev/null +++ b/dealfront_enrichment.py @@ -0,0 +1,169 @@ +import os +import json +import time +import logging +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.chrome.service import Service as ChromeService +from selenium.webdriver.chrome.options import Options as ChromeOptions +from webdriver_manager.chrome import ChromeDriverManager +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.common.exceptions import TimeoutException, NoSuchElementException + +from config import Config, DEALFRONT_LOGIN_URL, DEALFRONT_CREDENTIALS_FILE +from helpers import setup_logging + +# Logging aus dem helpers-Modul initialisieren +setup_logging(log_level=logging.DEBUG if Config.DEBUG else logging.INFO) +# Spezifischen Logger für dieses Modul erstellen +logger = logging.getLogger(__name__) + + +class DealfrontScraper: + """ + Kapselt alle Interaktionen mit der Dealfront-Plattform mittels Selenium. + """ + + def __init__(self): + """ + Initialisiert den WebDriver und den WebDriverWait. + """ + logger.info("Initialisiere den DealfrontScraper und den Chrome WebDriver.") + chrome_options = ChromeOptions() + # Optional: Führen Sie den Browser im "headless" Modus aus (ohne sichtbares Fenster) + # chrome_options.add_argument("--headless") + chrome_options.add_argument("--window-size=1920,1080") + chrome_options.add_argument("--disable-blink-features=AutomationControlled") + chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) + chrome_options.add_experimental_option('useAutomationExtension', False) + + # Stellt sicher, dass der korrekte ChromeDriver automatisch heruntergeladen und verwendet wird + try: + service = ChromeService(ChromeDriverManager().install()) + self.driver = webdriver.Chrome(service=service, options=chrome_options) + # Wichtig, um als "echter" Browser zu erscheinen + self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") + except Exception as e: + logger.critical(f"WebDriver konnte nicht initialisiert werden. Stellen Sie sicher, dass Chrome installiert ist. Fehler: {e}") + self.driver = None + raise + + # Zentraler WebDriverWait mit einem Timeout von 20 Sekunden + self.wait = WebDriverWait(self.driver, 20) + logger.info("WebDriver erfolgreich initialisiert.") + + def _load_credentials(self): + """Lädt Dealfront-Zugangsdaten sicher aus der JSON-Datei.""" + try: + with open(DEALFRONT_CREDENTIALS_FILE, 'r') as f: + creds = json.load(f) + username = creds.get("username") + password = creds.get("password") + if not username or "DEIN_DEALFRONT_BENUTZERNAME" in username or not password or "DEIN_DEALFRONT_PASSWORT" in password: + logger.error(f"Zugangsdaten in '{DEALFRONT_CREDENTIALS_FILE}' sind ungültig oder Platzhalter.") + return None, None + return username, password + except FileNotFoundError: + logger.error(f"Credentials-Datei nicht gefunden: '{DEALFRONT_CREDENTIALS_FILE}'") + return None, None + except json.JSONDecodeError: + logger.error(f"Fehler beim Parsen der Credentials-Datei: '{DEALFRONT_CREDENTIALS_FILE}'") + return None, None + + def login(self): + """ + Führt den Login-Prozess auf der Dealfront-Plattform durch. + """ + if not self.driver: + logger.error("Login nicht möglich, da der WebDriver nicht initialisiert wurde.") + return False + + username, password = self._load_credentials() + if not username or not password: + return False + + try: + logger.info(f"Navigiere zur Login-Seite: {DEALFRONT_LOGIN_URL}") + self.driver.get(DEALFRONT_LOGIN_URL) + + # 1. Cookie-Banner behandeln (falls vorhanden) + try: + logger.debug("Suche nach Cookie-Banner...") + # Expliziter Wait für den Button, der durch die ID identifiziert wird + cookie_button_id = "CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll" + cookie_button = self.wait.until(EC.element_to_be_clickable((By.ID, cookie_button_id))) + cookie_button.click() + logger.info("Cookie-Banner akzeptiert.") + # Kurze Pause nach dem Klick, damit sich die Seite anpassen kann + time.sleep(1) + except TimeoutException: + logger.warning("Cookie-Banner wurde nicht gefunden oder war nicht klickbar. Fahre fort.") + + # 2. Anmeldedaten ausfüllen + logger.info("Fülle Anmeldeformular aus...") + username_field = self.wait.until(EC.visibility_of_element_located((By.ID, "username"))) + password_field = self.driver.find_element(By.ID, "password") + + username_field.send_keys(username) + password_field.send_keys(password) + logger.info("Benutzername und Passwort eingetragen.") + + # 3. Login-Button klicken + login_button = self.driver.find_element(By.CSS_SELECTOR, "button[type='submit']") + login_button.click() + logger.info("Login-Button geklickt. Warte auf die Verifizierung...") + + # 4. Login-Erfolg verifizieren + # Wir warten auf ein Element, das nur nach erfolgreichem Login existiert, + # z.B. das Haupt-Suchfeld auf dem Dashboard. + verification_element_xpath = "//input[@data-cy='header-search-input']" + self.wait.until(EC.visibility_of_element_located((By.XPATH, verification_element_xpath))) + + logger.info("Login erfolgreich! Dashboard-Element gefunden.") + return True + + except TimeoutException as e: + logger.error(f"Login fehlgeschlagen. Timeout beim Warten auf ein Element.") + self.driver.save_screenshot("login_error_screenshot.png") + logger.error("Screenshot 'login_error_screenshot.png' wurde für die Analyse gespeichert.") + return False + except NoSuchElementException as e: + logger.error(f"Login fehlgeschlagen. Ein Element konnte nicht gefunden werden.") + self.driver.save_screenshot("login_error_screenshot.png") + return False + except Exception as e: + logger.critical(f"Ein unerwarteter Fehler ist während des Logins aufgetreten: {e}", exc_info=True) + self.driver.save_screenshot("login_error_screenshot.png") + return False + + def close(self): + """ + Schließt den WebDriver und beendet die Browser-Session. + """ + if self.driver: + logger.info("Schließe den WebDriver.") + self.driver.quit() + +if __name__ == "__main__": + logger.info("Starte Dealfront Automatisierung - Phase 1: Login-Test") + + scraper = None + try: + scraper = DealfrontScraper() + if scraper.driver: # Nur wenn der Driver erfolgreich gestartet wurde + if scraper.login(): + logger.info("Login-Prozess erfolgreich abgeschlossen. Der Bot ist nun eingeloggt.") + # Hier würde in Zukunft die weitere Logik (Suche, Extraktion) folgen. + # Für den Test warten wir 5 Sekunden, damit man das Ergebnis sehen kann. + time.sleep(5) + else: + logger.error("Login-Prozess ist fehlgeschlagen. Bitte Log-Meldungen und Screenshot prüfen.") + except Exception as e: + logger.critical(f"Ein kritischer Fehler ist im Hauptprozess aufgetreten: {e}", exc_info=True) + finally: + # Stellt sicher, dass der Browser immer geschlossen wird, auch bei einem Fehler. + if scraper: + scraper.close() + + logger.info("Login-Test beendet.") \ No newline at end of file