Ich suche einen einheitlichen Weg, um auf Statusänderungen von Selenium für Python-Elemente zu warten

Einführung

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.

Angenommener Leser

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.

Umgebung

Python 3.8.3 selenium 3.141.0 geckodriver v0.26.0 Firefox 77.0.1 (64-Bit)

Ergebnisquelle

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

Eine Funktion, die den aktuellen Status eines Elements überprüft

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 ()".

Funktion zum Überprüfen von Statusänderungen mit expected_conditions

In expected_conditions

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

Es wird sein. Auf der anderen Seite

Die nur zu überprüfende Funktion ist nicht vorbereitet und kann ersetzt werden

Es wird sein. "Klickbar" erfüllt jedoch häufig nicht den Zweck, da es "element.is_enabled ()" und "element.is_displayed ()" betrachtet.

Wie benutzt man

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):

Und 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

  1. Der Inhalt der Variablen "driver" (normalerweise als "Treiber" -Instanz angenommen) wird an "method" übergeben.
  2. Fahren Sie bis zu 30 Sekunden lang in Intervallen von 1 Sekunde fort, bis method (driver) erfolgreich ist (gibt etwas anderes als False zurück).
  3. Wenn method (driver) erfolgreich ist, wird der Rückgabewert zurückgegeben.
  4. Wenn dies nach 30 Sekunden nicht erfolgreich ist, wird eine Ausnahme ausgelöst.

Es wird sein.

Kombination

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))

Entspricht "aktiviert" / "deaktiviert"

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.

Bereiten Sie eine Funktion vor, die sich in "find_element ()" ändert

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):

Schließlich

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 (´ ・ ω ・ `)

Recommended Posts

Ich suche einen einheitlichen Weg, um auf Statusänderungen von Selenium für Python-Elemente zu warten
Eine einfache Möglichkeit, mehrere for-Schleifen in Python zu vermeiden
Eine Standardmethode zum Entwickeln und Verteilen von Paketen in Python
Möchten Sie mit Python Selenium auf allgemeine Zwecke warten?
Wie bekomme ich Stacktrace in Python?
Holen Sie sich ein Zeichen für Conoha mit Python
Warten Sie, bis sich in Selen ein weiteres Fenster öffnet
Eine clevere Möglichkeit zur Zeitverarbeitung mit Python
Auf der Suche nach einer effizienten Möglichkeit, eine Docker-Datei mit Python mit Gedichten zu schreiben
[Mac] Eine supereinfache Möglichkeit, Systembefehle in Python auszuführen und die Ergebnisse auszugeben
So tauschen Sie Elemente in einem Array in Python aus und wie kehren Sie ein Array um.
Holen Sie sich die Anzahl der spezifischen Elemente in der Python-Liste
Entwickelte eine Bibliothek, um die Kindle-Sammlungsliste in Python abzurufen
So definieren Sie mehrere Variablen in einer Python for-Anweisung
Tipps zum Codieren kurz und einfach in Python zu lesen
Rufen Sie die Excel-Liste rekursiv in einem bestimmten Ordner mit Python ab und schreiben Sie sie in Excel.
Ich habe versucht "Wie man eine Methode in Python dekoriert"
Nützliche Tricks in Bezug auf Listen und Anweisungen in Python
So erhalten Sie den letzten (letzten) Wert in einer Liste in Python
So erhalten Sie eine Liste der integrierten Ausnahmen für Python
Ich habe auch versucht, die Funktionsmonade und die Zustandsmonade mit dem Generator in Python nachzuahmen
Einführung einer guten Methode zur Verwaltung von DB-Verbindungen in Python
Versuchen Sie einfach, einen Webhook mit ngrok und Python zu erhalten
Eine einfache Möglichkeit, die in Python benötigte Zeit anzuzeigen und sie intelligenter zu verbessern
So bestimmen Sie die Existenz eines Selenelements in Python
So vergleichen Sie Listen und rufen allgemeine Elemente in einer Liste ab
Was tun, wenn in Python minus Null angezeigt wird?
So erhalten Sie eine Zeichenfolge aus einem Befehlszeilenargument in Python
[Einführung in Python] Wie verwende ich den Operator in in der for-Anweisung?
Ich habe versucht, mit Selenium und Python einen regelmäßigen Ausführungsprozess durchzuführen
Tipps zur Verwendung von Selen und Headless Chrome in einer CUI-Umgebung
So zeigen Sie Bytes in Java und Python auf die gleiche Weise an
Zuweisungen und Änderungen in Python-Objekten
Selen und Python zum Öffnen von Google
[Python] Erstellen einer Wörterbuchtypliste, Hinzufügen / Ändern / Löschen von Elementen und Extrahieren mit einer for-Anweisung
Python VBA, um mit Selenium die gesamte WEB-Seite zu erfassen
So erhalten Sie mit pandas DataFrame einen bestimmten Spaltennamen und Indexnamen
Klicken Sie auf die Selenium-Links, um die Elemente der einzelnen Seiten abzurufen
So erhalten Sie den Wert aus dem Parameterspeicher in Lambda (mit Python)
So setzen Sie in Python ein Leerzeichen mit halber Breite vor Buchstaben und Zahlen.
Stellen Sie von Python aus eine Verbindung zu postgreSQL her und verwenden Sie gespeicherte Prozeduren in einer Schleife.
Implementierung des Partikelfilters durch Python und Anwendung auf das Zustandsraummodell
So stoppen Sie das Programm bis zu einem bestimmten Datum und einer bestimmten Uhrzeit in Python
Erstellen Sie einen leichtgewichtigen Server in Python und hören Sie sich die HTTP-Erweiterungen von Scratch 2 an
Selen: Warten Sie mit UND / ODER auf das Element
Einfache Möglichkeit, Wikipedia mit Python zu verwenden
Verwendung ist und == in Python
Ich habe versucht, einen periodischen Prozess mit CentOS7, Selenium, Python und Chrome durchzuführen
Schritte, um dlib in Python Tools für Visual Studio einzufügen und Spaß zu haben
Tipps für diejenigen, die verwirrt sind, wie man is und == in Python verwendet
So zählen Sie die Anzahl der Elemente in Django und geben sie in die Vorlage aus
Verwenden Sie libsixel, um Sixel in Python auszugeben und das Matplotlib-Diagramm an das Terminal auszugeben.
Für diejenigen, die Excel VBA lernen und mit Python beginnen möchten
Ich suchte nach den Fähigkeiten, die erforderlich sind, um Webingenieur bei Python zu werden
Python-Skript zum Abrufen einer Liste von Eingabebeispielen für den AtCoder-Wettbewerb