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.")