Selenium: Seite vollständig geladen

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
Matthias0911
User
Beiträge: 10
Registriert: Montag 4. September 2023, 12:18

Hallo,

ich verwende momentan folgenden Code, um mit Selenium durch eine Shop-Kategorie zu navigieren:

Code: Alles auswählen

        
        logging.info("8. Kategorie wird geladen")
        start_time = time.monotonic()
        expected_condition = EC.visibility_of_element_located((By.XPATH, "//h2[contains(text(),'Kategorie')]"))
        wait = WebDriverWait(self.driver, 10000)
        wait.until(expected_condition)
        end_time = time.monotonic()
        self.testcase_navigation = self.testcase_navigation + "Kategorie /"
        logging.info(self.testcase_project + ";" + datetime.datetime.now().strftime("%w.%m.%Y;%H:%M") + ";" + self.testcase_name + ";" + self.testcase_browser + ";" + self.testcase_navigation + ";Top Seller;" + f"{end_time - start_time:.1f}")
  time.sleep(10)
        self.driver.find_element(By.XPATH, "//h3[normalize-space()='Unterkategorie']").click()
Jetzt ist mir aufgefallen, dass ohne die Verzögerung von time.sleep(10) der Aufruf der Folgekategorie nicht funktioniert und der gesamte Testfall somit abbricht.
Sprich, mein Warten auf die expected-condition greift zu früh, weil der Link dann noch nicht vollständig aufgebaut ist und nicht geklickt werden kann.

Kennt Ihr Tricks, wie ich in so einem Fall umgehen kann?
Kann man z.B. irgendwie herausfinden, bis wann die Seite vollständig geladen wurde?
Die Inhalte werden aber an der Stelle dynamisch nachgeladen.

Nachtrag: Mir ist aufgefallen, dass die Kategorien keine Klicks haben, sondern da wohl ein Javascript sein Unwesen treibt.
Wie kann ich denn abfragen, ob alle JavaSkripte geladen sind?
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Es gibt neben WebDriverWait() noch die Möglichkeit des impliziten Wartens mittels driver.implicitly_wait(anzahl_sekunden). Damit kann man eine Zeitspanne einstellen zum Warten auf nachgeladene Elemente.

Außerdem kann man auch auf ein ganz bestimmtest Element warten, welches man zuvor per ID ermittelt hat:

Code: Alles auswählen

revealed = driver.find_element(By.ID, "revealed")
wait = WebDriverWait(driver, timeout=2)

driver.find_element(By.ID, "reveal").click()
wait.until(lambda d : revealed.is_displayed())

revealed.send_keys("Displayed")
Quelle des Code-Snippets und für weitere Infos zum Thema:
https://www.selenium.dev/documentation/webdriver/waits/

time.sleep() erscheint mir in Verbindung mit Selenium übrigens unsinnig. Es gibt ja schon das besagte WebDriverWait(), welches du auch bereits in deinem Code stehen hast.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Grundsätzlich ist die Frage nicht beantwortbar, denn ein Browser (oder Selenium) kann nie wissen, ob nicht vielleicht doch noch irgendwas nachgeladen werden muss. Du musst schon konkreter hinschauen, wie in deinem speziellen Fall die Seite aufgebaut wird, und welche Teile genau vorhanden sein müssen, um den nächsten Schritt beginnen zu können.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Matthias0911: Der Logging-Aufruf sieht komisch aus. Die Zeit gehört da nicht rein, das kann Logging schon selber machen.

Mal davon abgesehen, dass man das mit ``+`` zusammenbasteln würde, das ist BASIC und nicht Python, benutzt Du für ein Teilstück ja bereits selbst ein f-Zeichenkettenliteral. Allerdings würde man auch das nicht für alles verwenden wenn man Teilstücke zusammensetzen will die durch das immer gleiche Zeichen getrennt sind:

Code: Alles auswählen

        logging.info(
            ";".join(
                [
                    self.testcase_project,
                    self.testcase_name,
                    self.testcase_browser,
                    self.testcase_navigation,
                    "Top Seller",
                    f"{end_time - start_time:.1f}",
                ]
            )
        )
Was daran ein bisschen schräg ist: Das sieht nach CSV-Daten aus. Die haben weder etwas als INFO im Protokoll zu suchen, noch würde man die selbst zusammenbasteln. Dafür gibt es das `csv`-Modul.

Falls man etwas automatisiert Auswertbares protokollieren möchte, sollte man vielleich auch eher auf Module wie `structlog` zurückgreifen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten