Überprüfen, ob mit Python Selenium ein Element vorhanden ist

73

Ich habe ein Problem - ich verwende den Selenium (Firefox) Web-Treiber, um eine Webseite zu öffnen, auf ein paar Links zu klicken usw. und dann einen Screenshot aufzunehmen.

Mein Skript läuft gut über die CLI, aber wenn es über einen Cronjob ausgeführt wird, kommt es nicht über den ersten find_element () -Test hinaus. Ich muss ein Debug hinzufügen oder etwas, um herauszufinden, warum es fehlschlägt.

Grundsätzlich muss ich auf einen Anmeldeanker klicken, bevor ich zur Anmeldeseite gehe. Das Konstrukt des Elements ist:

<a class="lnk" rel="nofollow" href="/login.jsp?destination=/secure/Dash.jspa">log in</a>

Ich verwende die Methode find_element By LINK_TEXT:

login = driver.find_element(By.LINK_TEXT, "log in").click()

Ich bin ein bisschen ein Python Noob, also kämpfe ich ein bisschen mit der Sprache ...

A) Wie überprüfe ich, ob der Link tatsächlich von Python aufgenommen wird? Soll ich try / catch block verwenden?

B) Gibt es eine bessere / zuverlässigere Möglichkeit, das DOM-Element zu lokalisieren als mit LINK_TEXT? In JQuery können Sie beispielsweise einen spezifischeren Selektor $ ('a.lnk: enthält (Login)') verwenden. Do_something ();


Ich habe das Hauptproblem gelöst und es war nur ein Fingerproblem - ich habe das Skript mit falschen Parametern aufgerufen - Einfacher Fehler.

Ich möchte noch einige Hinweise, wie Sie überprüfen können, ob ein Element vorhanden ist. Auch ein Beispiel / eine Erklärung für implizite / explizite Wartezeiten anstelle eines beschissenen Aufrufs von time.sleep ().

Prost, ns

Nicht zerbrechen
quelle
Sie können Elemente auch über den CSS-Locator oder xpath finden. Neigt dazu, weniger spröde zu sein als durch Textinhalte.
Silas Ray
Ich glaube, dass beide - unter Verwendung von Inhaltstext und XPATH / CSS - eher für geringfügige Änderungen im Design als für die Anwendungslogik anfällig sind. Ein besserer Weg wäre Element entweder zu finden id, class_nameoder name.
Kshitij Saraogi

Antworten:

56

A) Ja. Der einfachste Weg , um zu überprüfen , ob ein Element vorhanden ist, rufen Sie einfach im find_elementInnern ein try/catch.

B) Ja, ich versuche aus zwei Gründen immer, Elemente zu identifizieren, ohne ihren Text zu verwenden:

  1. der Text ändert sich eher und;
  2. Wenn es Ihnen wichtig ist, können Sie Ihre Tests nicht für lokalisierte Builds ausführen.

Lösung entweder:

  1. Sie können xpath verwenden, um ein übergeordnetes oder Vorfahrenelement zu finden, das eine ID oder eine andere eindeutige Kennung hat, und dann das Kind / den Nachkommen zu finden, das mit oder übereinstimmt.
  2. Sie können eine ID oder einen Namen oder eine andere eindeutige Kennung für den Link selbst anfordern.

Bei den folgenden Fragen können Sie anhand von try/catchfeststellen, ob ein Element vorhanden ist oder nicht. Gute Beispiele für Wartezeiten finden Sie hier: http://seleniumhq.org/docs/04_webdriver_advanced.html

Sam Woods
quelle
Eine Verwendung, die ich zum Suchen von Text habe, besteht darin, zu sehen, ob eine erfolgreiche / nicht erfolgreiche Flash-Nachricht angezeigt wird. Sie sind sich nicht sicher, ob es einen besseren Weg gibt?
Rob Grant
Das sind absolut gute Gründe, um eine Auswahl per Text zu vermeiden
kevlarr
114

ein)

from selenium.common.exceptions import NoSuchElementException        
def check_exists_by_xpath(xpath):
    try:
        webdriver.find_element_by_xpath(xpath)
    except NoSuchElementException:
        return False
    return True

b) Verwenden Sie xpath - das zuverlässigste. Darüber hinaus können Sie den xpath in all Ihren Skripten als Standard verwenden und Funktionen wie oben erwähnt für den universellen Gebrauch erstellen.

UPDATE : Ich habe die erste Antwort vor über 4 Jahren geschrieben und damals dachte ich, xpath wäre die beste Option. Jetzt empfehle ich die Verwendung von CSS-Selektoren . Ich empfehle immer noch, "nach ID", "nach Name" usw. nicht zu mischen / zu verwenden und stattdessen einen einzigen Ansatz zu verwenden.

Alex Okrushko
quelle
Sie sollten auch das Objekt browser = webdriver.Firefox () an Ihre benutzerdefinierte Funktion übergeben
Spectral
Im Allgemeinen bin ich selten auf HTML-Seiten gestoßen, die der Idee eines einheitlichen Abgleichs entsprechen. Gibt es eine Möglichkeit, Mix-Matches der Locator-Methoden auf solchen Seiten zu umgehen?
Kshitij Saraogi
@ KshitijSaraogi Ich bin mir nicht sicher, ob ich deine Frage vollständig verstehe. Wenn Sie bleiben, dass es unmöglich ist, nur "CSS-Selektoren" in Ihren Webdriver-Tests zu haben, ist dies tatsächlich durchaus möglich. Ich mache genau das seit 6 Jahren.
Alex Okrushko
@AlexOkrushko Was sind Ihre Gründe, CSS-Selektoren über xpath zu empfehlen?
BoZenKhaa
1
@BoZenKhaa, mindestens zwei Gründe: Vertrautheit der CSS-Selektoren mit den Entwicklern, was zur Lesbarkeit des Codes beiträgt; xpath hatte eine schreckliche Leistung im IE.
Alex Okrushko
71

Keine der angebotenen Lösungen schien mir am einfachsten zu sein, daher möchte ich meinen eigenen Weg hinzufügen.

Grundsätzlich erhalten Sie die Liste der Elemente anstelle nur des Elements und zählen dann die Ergebnisse. Wenn es Null ist, existiert es nicht. Beispiel:

if driver.find_elements_by_css_selector('#element'):
    print "Element exists"

Beachten Sie das "s" find_elements_by_css_selector, um sicherzustellen, dass es zählbar ist.

BEARBEITEN : Ich habe len(die Liste überprüft , aber ich habe kürzlich erfahren, dass eine leere Liste falsch ist, sodass Sie die Länge der Liste überhaupt nicht ermitteln müssen, um noch einfacheren Code zu erhalten.

Eine andere Antwort besagt, dass die Verwendung von xpath zuverlässiger ist, was einfach nicht stimmt. Siehe Was ist der Unterschied zwischen CSS-Selektor und Xpath? Was ist besser (je nach Leistung und für Cross-Browser-Tests)?

Brian Leishman
quelle
2
Ist dies schneller als die oben beschriebene Methode zur Behandlung von Ausnahmen?
Gal Bracha
2
@GalBracha Gute Frage, ich gehe davon aus, dass dies wahrscheinlich von der Version und der Plattform abhängt. Wenn der Geschwindigkeitsunterschied für Sie hier so wichtig ist, würde ich empfehlen, ihn auf Ihrer Zielplattform zu testen, um die besten Ergebnisse zu erzielen. Es ist jedoch ein Punkt zu beachten, der Voroptimierungen betrifft, und die Lesbarkeit des Codes könnte in diesem Fall wichtiger sein als die vernachlässigbare Leistungsverbesserung
Brian Leishman,
Tolle Lösung, aber nur erkannt, dass dies nicht funktioniert, wenn der Eingabetyp ausgeblendet ist. Also solltest du eigentlich verwenden find_elements_by_id. Übrigens find_element_by_xpathwirft ein Fehler, wenn das Element nicht verfügbar ist
Raunak Thomas
find_element_by_xpathwirft einen Fehler aus, wenn es kein Element finden kann, weil es nicht die Pluralversion der Funktion ist
Brian Leishman
@RaunakThomas ist es auch find_elements_by_css_selectoregal, ob ein Eingabeelement vorhanden ist type="hidden", da ich es genau dafür in einem meiner Anwendungsfälle verwende
Brian Leishman
12

Lösung ohne Try & Catch und ohne Neuimporte:

if len(driver.find_elements_by_id('blah')) > 0: #pay attention: find_element*s*
    driver.find_element_by_id('blah').click #pay attention: find_element
Super Mario
quelle
1
Wenn Sie es zweimal finden, wäre es sicherlich effizienter, die Sammlung zu speichern, und wenn es wahr ist, klicken Sie auf das erste, z. B.e = driver.find_elements_by_id('blah') if e: e[0].click
Brian Leishman
1
@ BrianLeishman Ich stimme dir zu, es ist effizienter, aber ich denke, meine ist leichter zu lesen und zu verstehen
Super Mario
3
Gute Lösung, aber ich stimme Brian zu you're finding twice.
ivanleoncz
Ich nehme an: if len(driver.find_elements_by_id('blah')): #do somethingsollte auch das Gleiche tun. ( > 0) ist nicht erforderlich.
atb00ker
5

Das gleiche wie Brian, aber fügen Sie dieser Antwort von tstempko hinzu:

/sqa/3481/quicker-way-to-assert-that-an-element-does-not-exist

Also habe ich es versucht und es funktioniert schnell:

driver.implicitly_wait(0)

if driver.find_element_by_id("show_reflist"):        
 driver.find_element_by_id("show_reflist").find_element_by_tag_name("img").click()

Danach stelle ich meinen Standardwert wieder her

driver.implicitly_wait(30)
vmk
quelle
Ja! Wenn Sie wissen, dass die Seite bereits geladen ist, möchten Sie nicht 30 Sekunden warten, um Ihre "nicht vorhandene Rückgabe" zu erhalten. Dies kehrt sofort zurück, genau das, was ich brauchte.
Welch
3

Sie können es auch präziser verwenden

driver.find_element_by_id("some_id").size != 0
Codeslord
quelle
Dies gibt einen Fehler zurück. Überprüfen Sie Lopi Dani auf den Grund und die richtige Vorgehensweise.
Sameh
1

driver.find_element_by_id("some_id").size() ist Klassenmethode.

Was wir brauchen ist:

driver.find_element_by_id("some_id").size Welches ist Wörterbuch so:

if driver.find_element_by_id("some_id").size['width'] != 0 : print 'button exist'

Lopi Dani
quelle
Dies ist nicht immer richtig. Die Breite kann Null sein, wenn auch ein Element vorhanden ist. el = driver.find_element_by_class_name ('gNO89b') el.size Dies ist ein gültiges Element auf der Google-Suchseite, aber die Breite ist 0
Codeslord
1

Sie können is_displayed () wie unten verwenden

res = driver.find_element_by_id("some_id").is_displayed()
assert res, 'element not displayed!'
Rajesh Selvaraj
quelle