Selen bietet "erwartete_Bedingungen" zum Untersuchen von Änderungen des Elementzustands. Aber,
Es gibt viele Aspekte, die schwer zu verwenden sind. Der Zweck dieses Artikels ist es, diese loszuwerden.
Es ist für diejenigen gedacht, die vorerst Selen verwendet haben.
Es ist jedoch nicht für fortgeschrittene Benutzer.
Für diejenigen, die wissen, was XPATH oder find_element ()
ist.
Python 3.8.3 selenium 3.141.0 geckodriver v0.26.0 Firefox 77.0.1 (64-Bit)
Derzeit wird nur die Quelle des Ergebnisses ohne Erklärung angezeigt. (Obwohl es Python ist, ist es nicht snake_case, sondern camelCase, also scheint es, dass ein Stein geworfen werden kann) Ich habe es nicht vollständig getestet, da es einige bedingte Zweige gibt, die ich nicht verwendet habe.
In diesem Artikel gehen wir außerdem davon aus, dass das in der folgenden Quelle gezeigte Modul "Import" ist.
python
import logging
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import (UnexpectedAlertPresentException, NoAlertPresentException,
ElementNotVisibleException, TimeoutException, NoSuchElementException)
logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())
class CheckState():
def __init__(self, locator=(), element=None, state="enabled"):
self.locator = locator
self.element = element
self.state = state
def __call__(self, driver):
try:
if self.element is not None and self.locator == ():
element = self.element
elif self.element is not None and self.locator != ():
element = self.element.find_element(*self.locator)
elif self.locator != ():
element = driver.find_element(*self.locator)
else:
return False
if self.state == "enabled":
return element if element.is_enabled() == True else False
elif self.state == "disabled":
return element if element.is_enabled() == False else False
elif self.state == "selected":
return element if element.is_selected() == True else False
elif self.state == "unselected":
return element if element.is_selected() == False else False
elif self.state == "displayed":
return element if element.is_displayed() == True else False
elif self.state == "undisplayed":
return element if element.is_displayed() == False else False
elif self.state == "clickable":
if element.is_enabled() == False:
return False
return element if element.is_displayed() == True else False
else:
return False
except Exception as e:
logger.debug(f"CheckState: {type(e)}, {e}, {self.locator}, {self.element}, {self.state}")
return False
def findElement(driver, locator=(), element=None, state="enabled", must=True, wait=30, interval=0.5, ignore=False):
try:
if element is None and locator == ():
raise ValueError
driverWait = WebDriverWait(driver, wait, interval)
return driverWait.until(CheckState(locator=locator, element=element, state=state))
except TimeoutException:
if must == True and ignore == False:
logger.error(f"findElement: {locator}, {element}, {state}, {must}, {wait}, {interval}, {ignore}")
raise ValueError
return None
except Exception as e:
if ignore == True:
return None
logger.error(f"findElement: {type(e)}, {e}")
raise e
def isDriver(driver):
if isinstance(driver, webdriver.remote.webdriver.WebDriver):
return True
return False
Zum Beispiel
element = driver.find_element(by, value)
Wenn Sie das Element von erhalten
--element.is_enabled ()
: Gibt an, ob es enabled
ist
--element.is_displayed ()
: Gibt an, ob es auf dem Bildschirm angezeigt wird
--element.is_selected ()
: Gibt an, ob es ausgewählt ist
--element.get_attribute (name)
: Attribut oder Eigenschaft abrufen
--element.get_property (name)
: Eigenschaft abrufen
--element.value_of_css_property (property_name)
: Liefert den Wert der CSS-Eigenschaft
Sie können den Status mit überprüfen. In diesem Artikel betrachten wir das einfachste "element.is_enabled ()", "element.is_displayed ()" und "element.is_selected ()".
expected_conditions
In expected_conditions
element.is_displayed()
element.is_selected()
Die folgenden Funktionen dienen zur Überprüfung der Zustandsänderung von.
--EC.element_to_be_selected (element)
: Gibt an, ob element
is_selected () == True ist --
EC.element_located_to_be_selected (locator) : Gibt an, ob das durch
locator angegebene Element
is_selected () == True ist --
EC.element_selection_state_to_be (element, is_selected) : Gibt an, ob
element is_selected () == is_selected
ist
--EC.element_located_selection_state_to_be (locator, is_selected)
: is_selected () == is_selected
--EC.visibility_of (element)
: Ob element
is is_displayed () == True
ist
--EC.visibility_of_element_located (locator)
: Ob das durch locator
angegebene Element is_displayed () == True
ist
--EC.invisibility_of_element (element)
: Ob element
is_displayed () == False ist --
EC.invisibility_of_element_located (locator) : Ob das durch
locator angegebene Element
is_displayed () == False` ist
Das Argument hier ist
element
:element = driver.find_element(By.XPATH, "//div[@class='cat']")
Übergeben Sie das Element "Element", das von usw. erhalten wurde.
--locator
: (By.XPATH," // div [@ class = 'cat'] ")
etc. wird übergeben.
--is_selected
: Pass True
Wenn Sie den ausgewählten Status erkennen möchten, übergeben Sie andernfalls False
.Es wird sein. Auf der anderen Seite
element.is_enabled()
Die nur zu überprüfende Funktion ist nicht vorbereitet und kann ersetzt werden
expected_conditions.element_to_be_clickable(locator)
Es wird sein. "Klickbar" erfüllt jedoch häufig nicht den Zweck, da es "element.is_enabled ()" und "element.is_displayed ()" betrachtet.
Im Allgemeinen ist die Funktion von "expected_conditions"
python
driver = webdriver.Firefox(executable_path=path, options=options, service_log_path="nul")
driver.get(url)
locator = (By.XPATH, "//div[@id='cat']")
element = WebDriverWait(driver, 30, 1).until(EC.visibility_of_element_located(locator))
Verwendung in Kombination mit WebDriverWait (). Bis ()
usw.
Schauen wir uns das genauer an.
Expected conditions
Zuerst "EC.visibility_of_element_located ()". Dies kann wie folgt erfolgen
python
func = EC.visibility_of_element_located(locator)
element = func(driver)
func
gibt eine Funktion zurück, die ein Argument akzeptiert (unter der Annahme von driver
).
Wenn Sie dann "driver" an "func" übergeben und ausführen, wird dieses Element zurückgegeben, wenn das durch "locator" angegebene Element "angezeigt" wird, und wenn es nicht "angezeigt" wird, wird "False" zurückgegeben.
Mit anderen Worten, func
ist eine Funktion wie find_element (locator)
, die keine Ausnahme auslöst, wenn sie fehlschlägt.
Außerdem kann find_element () wie folgt geändert werden:
python
relativeLocator = (By.XPATH, "./div[@class='meow']") #Relativer Pfad
child = element.find_element(*relativeLocator)
Sie können das Element (child
) auch unter element
abrufen.
Wenn Sie versuchen, mit "EC.element_to_be_clickable" etwas Ähnliches zu tun, erhalten Sie:
python
child = EC.visibility_of_element_located(relativeLocator)(element)
Es scheint, dass andere "erwartete_Zustände" -Funktionen auch Elemente relativer Pfade erhalten können. Wenn ich jedoch die Erklärung (gefunden) lese, scheint es, dass ich den absoluten Pfad von "Treiber" annehme. Ein Blick auf die Quelle auf GitHub scheint in Ordnung zu sein, aber ich mache mir ein wenig Sorgen. Daher möchte ich beim Umgang mit relativen Pfaden einige andere Mittel bereitstellen.
WebDriverWait
Gehen wir ein wenig zurück und schauen uns WebDriverWait (). Until ()
an.
"WebDriverWait ()" verwendet die folgenden Argumente (eines weggelassen):
timeout
: Maximale Wartezeit
--poll_frequency
: TestintervallUnd wait.until ()
nimmt ein Argument wie unten beschrieben.
--method
: Eine Funktion, die einen Treiber
als Argument verwendet. Diese Funktion gibt bei Fehler "False" und bei Erfolg "Nicht-False" zurück
Wenn Sie wie folgt schreiben,
python
timeout = 30
poll_frequency = 1
wait = WebDriverWait(driver, timeout, poll_frequency)
element = wait.until(method)
Das Verhalten von wait.until (Methode)
ist
method (driver)
erfolgreich ist (gibt etwas anderes als False
zurück).method (driver)
erfolgreich ist, wird der Rückgabewert zurückgegeben.Es wird sein.
Wenn Sie aus der obigen Erklärung wie folgt schreiben:
python
locator = (By.XPATH, "//div[@id='cat']")
element = WebDriverWait(driver, 30).until(EC.visibility_of_element_located(locator))
Wenn das durch "locator" angegebene Element vorhanden ist und "angezeigt" wird, wird dieses Element "element" zugewiesen.
Wenn das Element nach 30 Sekunden nicht gefunden wird oder angezeigt wird, wird eine Ausnahme ausgelöst.
Wie Sie vielleicht bemerkt haben, können Sie das relative Element von element
erhalten, indem Sie die folgenden Schritte ausführen.
python
relativeLocator = (By.XPATH, "./div[@class='meow']") #Relativer Pfad
child = WebDriverWait(element, 30).until(EC.visibility_of_element_located(relativeLocator))
expected_conditions
hat keine Funktion, die enabled
( disabled
) entspricht, aber es ist einfach, eine zu erstellen, die dies unterstützt.
Angenommen, es wird von "WebDriverWait (). Until ()" aufgerufen
Sie können sehen, dass Sie die Funktion erstellen sollten. Wenn es sich jedoch um eine Funktion handelt, können Sie "Treiber" nur übergeben, wenn Sie eine globale Variable verwenden, sodass Sie "Klasse" erstellen. Der einfachste Weg, dies zu tun, ist wie folgt.
python
class IsEnabled():
def __init__(self, locator=(), state=True):
self.locator = locator
self.state = state
def __call__(self, driver):
try:
if self.locator == ():
return False
element = driver.find_element(*self.locator)
return element if element.is_enabled() == self.state else False
except Exception as e:
return False
Es kann wie folgt verwendet werden:
python
locator = (By.XPATH, "//div[@id='cat']")
element = WebDriverWait(driver, 30, 1).until(IsEnabled(locator))
Es gibt zwei Arten von "erwarteten_Zuständen", einen mit "Locator" und einen mit "Element". Der von Ihnen erstellte muss jedoch "locator" angeben. Relative Pfade werden nicht unterstützt. Ich werde versuchen, es zu verbessern, damit es damit umgehen kann.
python
class IsEnabled():
def __init__(self, locator=(), element=None, state=True):
self.locator = locator
self.element = element
self.state = state
def __call__(self, driver):
try:
if self.element is not None and self.locator == ():
element = self.element
elif self.element is not None and self.locator != ():
element = self.element.find_element(*self.locator)
elif self.locator != ():
element = driver.find_element(*self.locator)
else:
return False
return element if element.is_enabled() == state else False
except Exception as e:
return False
Auf diese Weise können Sie es wie folgt verwenden.
python
#Ruft das vom Locator angegebene Element ab, wenn es aktiviert ist
element = WebDriverWait(driver, 30, 1).until(IsEnabled(locator=locator))
#Gibt ein Element zurück, wenn das Element aktiviert ist
element = WebDriverWait(driver, 30, 1).until(IsEnabled(element=element))
#Abrufen, wenn das relative Element von Element aktiviert wird
child = WebDriverWait(driver, 30, 1).until(IsEnabled(element=element, locator=relativeLocator))
Der am Anfang angezeigte "CheckState" entspricht einem weiteren Status.
Jetzt können Sie das Element mit der gleichen Beschreibung wie find_element () erhalten. Außerdem können Sie dies erhalten, während Sie die Zustandsänderung beobachten. Es ist jedoch mühsam, jedes Mal Folgendes zu schreiben, und es kann verwirrend sein, wenn es in Kombination mit "find_element ()" verwendet wird.
python
element = WebDriverWait(driver, 30, 1).until(CheckState(element=element, state="clickable"))
Also definieren wir eine Wrapper-Funktion, die find_element ()
ändert.
Persönlich scheint es nicht so, als würde ich das Element aus dem Namen der Funktion erhalten.
Ich denke, es ist auch ein Problem, dass Sie zu viele Wrapper-Funktionen erstellen und nicht wissen, was Sie verwenden.
python
def findElement(driver, locator=(), element=None, state="enabled", must=True, wait=30, interval=0.5, ignore=False):
try:
if element is None and locator == ():
raise ValueError
driverWait = WebDriverWait(driver, wait, interval)
return driverWait.until(CheckState(locator=locator, element=element, state=state))
except TimeoutException:
if must == True and ignore == False:
logger.error(f"findElement: {locator}, {element}, {state}, {must}, {wait}, {interval}, {ignore}")
raise ValueError
return None
except Exception as e:
if ignore == True:
return None
logger.error(f"findElement: {type(e)}, {e}")
raise e
Es wird wie folgt verwendet.
python
locator = (By.XPATH, "//div[@id='cat']")
element = findElement(driver, locator=locator):
Jetzt denke ich, dass Sie es ordentlich schreiben können.
Abhängig vom Verhalten der Site ist es jedoch schwierig, verschiedene Anpassungen vorzunehmen.
Selbst wenn es bisher funktioniert hat, ist die Site häufig langsam und stolpert an unerwarteten Stellen.
Immerhin kann ich time.sleep ()
nicht loslassen
Es gibt eine Geschichte, in der ich nicht gut bin (´ ・ ω ・ `)