From 2d9d2f8fe2a347478d8f24fdf2dd8c574d0f437f Mon Sep 17 00:00:00 2001 From: Floke Date: Thu, 3 Jul 2025 11:21:28 +0000 Subject: [PATCH] =?UTF-8?q?Erg=C3=A4nzung=20gehe=20zu=20Liste?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dealfront_enrichment.py | 101 +++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 28 deletions(-) diff --git a/dealfront_enrichment.py b/dealfront_enrichment.py index eaaa30ee..42da3f3e 100644 --- a/dealfront_enrichment.py +++ b/dealfront_enrichment.py @@ -134,43 +134,88 @@ class DealfrontScraper: self._save_debug_artifacts() return False - def navigate_to_target_list(self, list_name: str): - """ - Navigiert nach dem Login zu einer spezifischen Zielliste im Target-Modul. - :param list_name: Der exakte Name der Zielliste, die angeklickt werden soll. - """ + def navigate_to_target(self): + """Navigiert zum 'Target'-Bereich der Anwendung.""" try: - # --- SCHRITT 1: Zum Target-Modul navigieren --- - # Wir verwenden die Basis-URL, da die spezifische URL Session-IDs enthalten könnte. - target_url = "https://app.dealfront.com/t" - logger.info(f"Navigiere zum Target-Modul: {target_url}") - self.driver.get(target_url) - - # --- SCHRITT 2: Auf die Liste in der Seitenleiste warten und klicken --- - # Wir suchen nach einem Link, dessen Text genau mit dem Listennamen übereinstimmt. - # Dieser XPath ist sehr spezifisch und robust. - list_selector = (By.XPATH, f"//div[contains(@class, 'list-group-item')]//a[normalize-space()='{list_name}']") - logger.debug(f"Warte darauf, dass die Zielliste '{list_name}' klickbar ist.") + logger.info("Navigiere zum 'Target'-Bereich...") + target_button_selector = (By.XPATH, "//a[contains(@class, 'text-base') and .//span[normalize-space()='Target']] | //a[.//div[normalize-space()='Target']]") - target_list_element = self.wait.until(EC.element_to_be_clickable(list_selector)) - target_list_element.click() - logger.info(f"Zielliste '{list_name}' erfolgreich angeklickt.") - - # --- SCHRITT 3: Warten, bis die Ergebnisseite geladen ist --- - # Wir verifizieren, dass der Header der Tabelle sichtbar ist. - # Ein guter Indikator ist die Spaltenüberschrift "Firma". - results_header_selector = (By.XPATH, "//th[normalize-space()='Firma']") - self.wait.until(EC.visibility_of_element_located(results_header_selector)) - logger.info("Ergebnistabelle erfolgreich geladen.") + # Alternative, falls der obere Selektor nicht klappt: + # target_button_selector = (By.CSS_SELECTOR, "a[data-test-product-link-for='Target']") + target_button = self.wait.until(EC.element_to_be_clickable(target_button_selector)) + target_button.click() + + # Verifizieren, dass die Seite geladen ist, indem wir auf den "+ Neue Suche"-Button warten + new_search_button_selector = (By.XPATH, "//button[normalize-space()='+ Neue Suche']") + self.wait.until(EC.visibility_of_element_located(new_search_button_selector)) + + logger.info("'Target'-Seite erfolgreich geladen.") return True - except Exception as e: - logger.critical(f"Fehler beim Navigieren zur Zielliste '{list_name}': {type(e).__name__}", exc_info=True) + logger.critical(f"Navigation zur 'Target'-Seite fehlgeschlagen: {type(e).__name__}", exc_info=True) self._save_debug_artifacts() return False + def load_search(self, search_name): + """Lädt eine vordefinierte Suche anhand ihres Namens.""" + try: + logger.info(f"Suche und lade die vordefinierte Suche: '{search_name}'") + # Der XPath sucht nach einem Link, dessen Text den Suchnamen enthält + search_link_selector = (By.XPATH, f"//a[contains(., '{search_name}')] | //div[contains(., '{search_name}') and contains(@class, 'list-item')]") + search_link = self.wait.until(EC.element_to_be_clickable(search_link_selector)) + search_link.click() + + # Verifizieren, dass die Ergebnisse geladen sind, indem wir auf die Ergebnistabelle warten. + # Ein guter Indikator ist die Tabellenüberschrift "Firma". + results_table_header_selector = (By.XPATH, "//th[normalize-space()='Firma']") + self.wait.until(EC.visibility_of_element_located(results_table_header_selector)) + logger.info(f"Suche '{search_name}' erfolgreich geladen und Ergebnisse angezeigt.") + # Eine kleine, feste Wartezeit kann helfen, damit alle Daten nachgeladen sind. + time.sleep(3) + return True + except Exception as e: + logger.critical(f"Laden der Suche '{search_name}' fehlgeschlagen: {type(e).__name__}", exc_info=True) + self._save_debug_artifacts() + return False + + def extract_current_page_results(self): + """Extrahiert die Firmennamen und Webseiten von der aktuellen Ergebnisseite.""" + try: + logger.info("Extrahiere Ergebnisse von der aktuellen Seite...") + results = [] + # Finde alle Zeilen in der Ergebnistabelle. Wir gehen davon aus, dass es `tr`-Elemente sind. + # Ein stabiler Selektor könnte die `data-test`-Attribute nutzen, falls vorhanden. + rows_selector = (By.XPATH, "//tbody/tr") + rows = self.driver.find_elements(*rows_selector) + + if not rows: + logger.warning("Keine Ergebniszeilen auf der Seite gefunden.") + return [] + + logger.info(f"{len(rows)} Ergebniszeilen gefunden.") + + for row in rows: + try: + # Extrahiere Firmenname und Webseite. + # Diese XPaths sind Annahmen und müssen ggf. nach Analyse des HTML angepasst werden. + company_name = row.find_element(By.XPATH, ".//td[2]//a").text.strip() + website = row.find_element(By.XPATH, ".//td[3]//a").text.strip() + + if company_name and website: + results.append({'name': company_name, 'website': website}) + except NoSuchElementException: + logger.warning("Konnte Name oder Webseite in einer Zeile nicht finden, überspringe Zeile.") + continue + + logger.info(f"{len(results)} Firmen erfolgreich extrahiert.") + return results + except Exception as e: + logger.error(f"Fehler bei der Extraktion der Ergebnisse: {type(e).__name__}", exc_info=True) + self._save_debug_artifacts() + return [] + def close(self): if self.driver: logger.info("Schließe den WebDriver.")