From 3e0a3f10b9209bd5764b5a94acae95c8f03f1ee8 Mon Sep 17 00:00:00 2001 From: Floke Date: Fri, 4 Jul 2025 04:10:34 +0000 Subject: [PATCH] =?UTF-8?q?R=C3=BCckgang=20zur=20stabilen=20Version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dealfront_enrichment.py | 84 +++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/dealfront_enrichment.py b/dealfront_enrichment.py index 007fc6ed..ade61690 100644 --- a/dealfront_enrichment.py +++ b/dealfront_enrichment.py @@ -84,43 +84,62 @@ class DealfrontScraper: except Exception as e: logger.error(f"Konnte Debug-Artefakte nicht speichern: {e}") - def login_and_navigate_to_target(self): - """ - Führt den Login durch und navigiert zur Target-Seite via Klick auf den "Quick Link". - Dieser Ansatz ist maximal robust. - """ + def login(self): + """Führt NUR den Login-Prozess durch.""" if not self.driver: return False username, password = self._load_credentials() if not username or not password: return False try: - # SCHRITT 1: LOGIN logger.info(f"Navigiere zur Login-Seite: {DEALFRONT_LOGIN_URL}") self.driver.get(DEALFRONT_LOGIN_URL) - 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.") + email_field = self.wait.until(EC.visibility_of_element_located((By.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() + + # Verifizieren, dass der Login erfolgreich war, indem wir auf das Dashboard-Element warten + verification_dashboard_selector = (By.XPATH, "//input[@data-cy='header-search-input']") + self.wait.until(EC.visibility_of_element_located(verification_dashboard_selector)) + logger.info("Login erfolgreich! Dashboard erreicht.") + return True + + except Exception as e: + logger.critical(f"Login-Prozess fehlgeschlagen: {type(e).__name__}", exc_info=True) + self._save_debug_artifacts() + return False - # SCHRITT 2: NAVIGATION VIA QUICK-LINK-KACHEL - logger.info("Warte auf Dashboard und 'Prospects finden'-Link in den Quick Links.") - - # Dieser XPath zielt auf den Link in der "Quick links"-Kachel - prospects_link_selector = (By.XPATH, "//a[contains(@href, '/t/prospector/companies')]") - prospects_link = self.wait.until(EC.element_to_be_clickable(prospects_link_selector)) - logger.info("'Prospects finden'-Link gefunden. Klicke darauf...") - prospects_link.click() - - # SCHRITT 3: NAVIGATION VERIFIZIEREN - verification_target_selector = (By.XPATH, "//button[normalize-space()='+ Neue Suche']") - self.wait.until(EC.visibility_of_element_located(verification_target_selector)) + def navigate_to_target(self): + """ + Navigiert zum 'Target'-Bereich und verifiziert den Erfolg in drei Schritten. + Dieser Ansatz ist maximal robust gegen Timing-Probleme von SPAs. + """ + try: + # SCHRITT 1: Befehl zur Navigation geben + logger.info(f"Gebe Navigationsbefehl zur Target-URL: {Config.DEALFRONT_TARGET_URL}") + self.driver.get(Config.DEALFRONT_TARGET_URL) + + # SCHRITT 2: Warten, bis die URL in der Adresszeile sich tatsächlich ändert. + url_part_to_wait_for = "/t/prospector/" + logger.info(f"Warte, bis die Browser-URL '{url_part_to_wait_for}' enthält...") + self.wait.until(EC.url_contains(url_part_to_wait_for)) + logger.info(f"URL-Wechsel bestätigt. Aktuelle URL: {self.driver.current_url}") + + # SCHRITT 3: ERST JETZT auf ein sichtbares Element auf der neuen Seite warten. + verification_selector = (By.XPATH, "//button[normalize-space()='+ Neue Suche']") + logger.info(f"Warte auf Sichtbarkeit des Verifizierungs-Elements auf der Target-Seite: {verification_selector}") + self.wait.until(EC.visibility_of_element_located(verification_selector)) logger.info("'Target'-Seite erfolgreich und vollständig geladen.") return True - + except Exception as e: - logger.critical(f"Login- oder Navigationsprozess fehlgeschlagen: {type(e).__name__}", exc_info=True) + logger.critical(f"Navigation zur 'Target'-Seite endgültig fehlgeschlagen: {type(e).__name__}", exc_info=True) self._save_debug_artifacts() return False @@ -202,15 +221,22 @@ if __name__ == "__main__": if not scraper.driver: raise Exception("WebDriver konnte nicht initialisiert werden.") - # === NEUER AUFRUF DER KOMBINIERTEN FUNKTION === - if not scraper.login_and_navigate_to_target(): - raise Exception("Login und Navigation fehlgeschlagen.") + # === GETRENNTE AUFRUFE === + # Schritt 1: Login + if not scraper.login(): + raise Exception("Login fehlgeschlagen.") - # Suche laden + time.sleep(2) # Kurze Pause nach dem Login + + # Schritt 2: Navigation + if not scraper.navigate_to_target(): + raise Exception("Navigation zur Target-Seite fehlgeschlagen.") + + # Schritt 3: Suche laden if not scraper.load_search(Config.TARGET_SEARCH_NAME): raise Exception(f"Laden der Suche '{Config.TARGET_SEARCH_NAME}' fehlgeschlagen.") - # Ergebnisse extrahieren und ausgeben + # Schritt 4: Ergebnisse extrahieren und ausgeben companies = scraper.extract_current_page_results() if companies: df = pd.DataFrame(companies)