Files
Brancheneinstufung2/dealfront_enrichment.py

177 lines
8.1 KiB
Python

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__)
# ... (Kontext: Zeile davor)
class DealfrontScraper:
"""
Kapselt alle Interaktionen mit der Dealfront-Plattform mittels Selenium.
"""
def __init__(self):
"""
Initialisiert den WebDriver und den WebDriverWait.
Verwendet den system-installierten chromedriver im Docker-Container.
"""
logger.info("Initialisiere den DealfrontScraper und den Chrome WebDriver.")
chrome_options = ChromeOptions()
# Docker-optimierte und Headless-Argumente
chrome_options.add_argument("--headless")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--window-size=1920,1080")
# Anti-Detection-Maßnahmen
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
# Da der chromedriver im Dockerfile systemweit installiert wird,
# ist der webdriver-manager nicht mehr nötig. Selenium findet den Treiber von selbst.
try:
self.driver = webdriver.Chrome(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. Fehler: {e}", exc_info=True)
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...")
# NEU: Robusterer XPath-Selektor, der nach einem Button mit spezifischem Text sucht.
# Dies ist weniger anfällig für ID-Änderungen.
cookie_button_xpath = "//button[contains(text(), 'Alle zulassen') or contains(text(), 'Alle akzeptieren')]"
cookie_button = self.wait.until(EC.element_to_be_clickable((By.XPATH, cookie_button_xpath)))
cookie_button.click()
logger.info("Cookie-Banner erfolgreich via XPath geklickt.")
# Kurze Pause nach dem Klick, damit sich die Seite anpassen kann
time.sleep(1)
except TimeoutException:
logger.warning("Cookie-Banner konnte nicht via XPath gefunden werden. Das kann OK sein, wenn kein Banner da war.")
# 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.")