From dc481c1786466262ab5fedabefd92e53cbf7dd84 Mon Sep 17 00:00:00 2001 From: Floke Date: Thu, 3 Jul 2025 20:35:37 +0000 Subject: [PATCH] dealfront_enrichment.py aktualisiert --- dealfront_enrichment.py | 84 +++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 54 deletions(-) diff --git a/dealfront_enrichment.py b/dealfront_enrichment.py index 5a8d4c5e..adb21771 100644 --- a/dealfront_enrichment.py +++ b/dealfront_enrichment.py @@ -25,6 +25,11 @@ class DealfrontScraper: def __init__(self): logger.info("Initialisiere DealfrontScraper und Chrome WebDriver.") chrome_options = ChromeOptions() + + # NEU: Lade-Optimierungen + prefs = {"profile.managed_default_content_settings.images": 2} + chrome_options.add_experimental_option("prefs", prefs) + chrome_options.add_argument("--headless") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--disable-dev-shm-usage") @@ -41,8 +46,8 @@ class DealfrontScraper: self.driver = None raise - self.wait = WebDriverWait(self.driver, 30) # Timeout auf 30s erhöht für mehr Stabilität - logger.info("WebDriver erfolgreich initialisiert.") + self.wait = WebDriverWait(self.driver, 30) + logger.info("WebDriver erfolgreich initialisiert (Bild-Laden deaktiviert).") def _load_credentials(self): # (Diese Methode bleibt unverändert) @@ -81,50 +86,33 @@ class DealfrontScraper: def login_and_navigate_to_target(self): """ - Führt den Login durch und navigiert zur Target-URL. - Dieser kombinierte Ansatz wartet nach jeder Aktion explizit auf den Erfolg. + Führt Login durch und navigiert direkt zur Target-URL. """ - if not self.driver: - return False - + if not self.driver: return False username, password = self._load_credentials() - if not username or not password: - return False + if not username or not password: return False try: - # --- SCHRITT 1: LOGIN-SEITE LADEN --- + # SCHRITT 1: LOGIN logger.info(f"Navigiere zur Login-Seite: {DEALFRONT_LOGIN_URL}") self.driver.get(DEALFRONT_LOGIN_URL) - # --- SCHRITT 2: DATEN EINGEBEN UND KLICKEN --- - logger.info("Warte auf Login-Formular und fülle es aus...") - email_field = self.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input[name='email']"))) - email_field.send_keys(username) - password_field = self.driver.find_element(By.CSS_SELECTOR, "input[type='password']") - password_field.send_keys(password) - login_button = self.driver.find_element(By.XPATH, "//button[normalize-space()='Log in']") - login_button.click() - logger.info("Login-Button geklickt.") + self.wait.until(EC.visibility_of_element_located((By.NAME, "email"))).send_keys(username) + self.driver.find_element(By.CSS_SELECTOR, "input[type='password']").send_keys(password) + self.driver.find_element(By.XPATH, "//button[normalize-space()='Log in']").click() + logger.info("Login-Befehl gesendet.") - # --- SCHRITT 3: AUF ERFOLGREICHEN LOGIN WARTEN (Dashboard) --- - logger.info("Warte auf Dashboard nach dem Login...") - verification_dashboard_selector = (By.XPATH, "//input[@data-cy='header-search-input']") - self.wait.until(EC.visibility_of_element_located(verification_dashboard_selector)) - logger.info("Dashboard erfolgreich erreicht.") - time.sleep(2) # Eine kleine Pause, damit alle Hintergrund-Skripte laden können. - - # --- SCHRITT 4: DIREKTE NAVIGATION ZUR TARGET-URL --- + # SCHRITT 2: DIREKTE NAVIGATION (robuster als auf Dashboard zu warten) + # Eine kurze, feste Pause nach dem Klick, bevor wir die URL wechseln. + time.sleep(3) logger.info(f"Navigiere direkt zur Target-URL: {Config.DEALFRONT_TARGET_URL}") self.driver.get(Config.DEALFRONT_TARGET_URL) - # --- SCHRITT 5: ERFOLG DER NAVIGATION VERIFIZIEREN --- - logger.info("Warte auf Bestätigung der Target-Seite...") - verification_target_selector = (By.XPATH, "//button[normalize-space()='+ Neue Suche']") - self.wait.until(EC.visibility_of_element_located(verification_target_selector)) - logger.info("'Target'-Seite erfolgreich und vollständig geladen.") - + # SCHRITT 3: NAVIGATION VERIFIZIEREN + verification_selector = (By.XPATH, "//button[normalize-space()='+ Neue Suche']") + self.wait.until(EC.visibility_of_element_located(verification_selector)) + logger.info("'Target'-Seite erfolgreich geladen.") return True - except Exception as e: logger.critical(f"Login- oder Navigationsprozess fehlgeschlagen: {type(e).__name__}", exc_info=True) self._save_debug_artifacts() @@ -157,13 +145,9 @@ class DealfrontScraper: logger.info("Extrahiere Ergebnisse von der aktuellen Seite...") results = [] - # 1. Finde alle Zeilen der Tabelle. - # Jede Zeile ist ein ``-Element mit einer einzigartigen ID. rows_selector = (By.CSS_SELECTOR, "table#t-result-table tbody > tr[id]") - - # Wir warten explizit, bis mindestens eine Zeile geladen ist. self.wait.until(EC.presence_of_element_located(rows_selector)) - time.sleep(3) # Kurze zusätzliche Pause, um sicherzustellen, dass JS die Tabelle vollständig rendert. + time.sleep(3) rows = self.driver.find_elements(*rows_selector) if not rows: @@ -173,36 +157,28 @@ class DealfrontScraper: logger.info(f"{len(rows)} Ergebniszeilen zur Verarbeitung gefunden.") - # 2. Iteriere durch jede Zeile und extrahiere die Daten. for i, row in enumerate(rows): - company_name = "" - website = "" + company_name, website = "", "" try: - # --- KORRIGIERTER FIRMENNAMEN-SELEKTOR --- - company_name_selector = (By.CSS_SELECTOR, ".sticky-column a.t-highlight-text") - company_name_element = row.find_element(*company_name_selector) - # Wir holen uns das 'title'-Attribut, da der Text abgeschnitten sein könnte. + # --- IHR SELEKTOR FÜR FIRMENNAMEN --- + company_name_element = row.find_element(By.CSS_SELECTOR, ".sticky-column a.t-highlight-text") company_name = company_name_element.get_attribute("title").strip() - # --- KORRIGIERTER WEBSEITEN-SELEKTOR --- - website_selector = (By.CSS_SELECTOR, "a.text-gray-400.t-highlight-text") - website_element = row.find_element(*website_selector) + # --- IHR SELEKTOR FÜR WEBSITES --- + website_element = row.find_element(By.CSS_SELECTOR, "a.text-gray-400.t-highlight-text") website = website_element.text.strip() if company_name and website: results.append({'name': company_name, 'website': website}) - else: - logger.warning(f"Zeile {i+1}: Unvollständige Daten (Name: '{company_name}', Webseite: '{website}').") - except NoSuchElementException: - logger.warning(f"Zeile {i+1}: Ein erwartetes Element (Name oder Webseite) wurde nicht gefunden. Überspringe diese Zeile.") + logger.warning(f"Zeile {i+1}: Name oder Webseite nicht gefunden. Überspringe.") continue logger.info(f"{len(results)} Firmen erfolgreich extrahiert.") return results except Exception as e: - logger.error(f"Ein schwerwiegender Fehler ist bei der Extraktion der Ergebnisse aufgetreten: {type(e).__name__}", exc_info=True) + logger.error(f"Schwerwiegender Fehler bei der Extraktion: {type(e).__name__}", exc_info=True) self._save_debug_artifacts() return []