Voulez-vous attendre un usage général avec Python Selenium?

introduction

Eh bien, je n'aimais pas le flottement de la souris dans le système d'entreprise (gestion des présences).

Choses courantes dans l'exploration

Fondamentalement, il s'agit d'un système dans lequel les humains flottent avec une souris, il n'est donc pas considéré comme étant actionné par une machine. Il y a une prémisse que vous n'appuierez jamais sur un bouton que vous n'avez pas encore vu, donc si vous pensez à le déplacer en fonction de la personne, faites quelque chose lorsque vous pouvez appuyer correctement ou lorsque vous pouvez le saisir. Il est nécessaire de contrôler le timing de cette manière.

Naturellement, le sélénium a un tel mécanisme.

document: waits, Waits, Wait (traduction ci-dessus)

Les deuxième et troisième documents montrent deux manières. Cependant, attendre un certain temps dans les nuages sombres est une attente implicite, et time.sleep est bien sans le laisser au sélénium. Eh bien, il est facile de dire que c'est facile car vous n'avez pas besoin de taper les coûts ou d'oublier de les insérer, mais si la vitesse de réponse diffère en fonction des conditions du réseau et des conditions de charge du PC, vous risquez de ne pas obtenir les résultats attendus, c'est donc essentiellement explicite. L'attente est souhaitable. Mais [interrogation interne pendant une certaine période (0,5 s par défaut)](https://seleniumhq.github.io/selenium/docs/api/py/_modules/selenium/webdriver/support/wait.html# WebDriverWait), donc la charge de traitement sera légèrement plus élevée.

Comment attendre

Ainsi, dans l'exemple écrit dans le document ci-dessus, il est présenté comme suit.

#Le premier
element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id(“someId”))

#2e et 3e
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    #Gestion des exceptions

Personnalisez les conditions d'attente

De plus, ce document décrit comment personnaliser. .. Classe d'assistance définie dans ExceptedConditions telle que presence_of_element_located dispose également de ce mécanisme. J'utilise. Cependant, cette méthode peut être comprise si elle est un peu plus compliquée, mais si elle est aussi simple que celle présentée, elle peut se faire plus facilement.

Vous pouvez créer une condition d'attente personnalisée à l'aide d'une classe qui a une méthode call qui renvoie False si les conditions ne correspondent pas.

Vous n'avez qu'à conserver les conditions telles que, pour pouvoir utiliser une expression lambda ou quelque chose. (Il est mentionné dans le tout premier document.)

def proc(driver, type, name, cname):
  #Créez le processus que vous souhaitez personnaliser, renvoyez False lorsque les conditions ne correspondent pas, renvoyez l'élément en cas de succès
  element = driver.find_element(type, name)
  if cname in element.get_attribute("class"):
    return element
  else:
    return False

wait = WebDriverWait(driver, 10)
try:
  element = wait.until(lambda drv: proc(drv, By.ID, 'myNewInput', 'myCSSClass'))
except TimeoutException:
  print("timeout..")
  sys.exit()

Un exemple d'expression de lamda est [ce document](https://seleniumhq.github.io/selenium/docs/api/py/webdriver_support/selenium.webdriver.support.wait.html?highlight=webdriverwait#selenium.webdriver.support .wait.WebDriverWait ) Est également décrite. Ce document a un lien vers la source, donc je pense que c'est très utile. Si vous faites référence à ici, le fait est que vous pouvez ajouter une condition telle que non seulement obtenir un élément lorsqu'il est trouvé, mais également obtenir un élément avec un certain attribut.

Le sujet principal?

Eh bien, dans le premier exemple, nous avons confirmé que l'ID existe dans le DOM, mais par exemple, l'élément que vous souhaitez confirmer peut être la classe ou le nom, et l'élément à attendre des changements en fonction de la page et de la configuration. À ce moment-là, il s'agit de By.CLASS_NAME, et je voulais éviter d'être au courant des identifiants tels que By.NAME (en termes de codage). Bien sûr, lors de l'exploration, vous devez penser à la facilité avec laquelle cet élément est tiré par l'ID, et comment l'identifier de manière unique car il s'agit d'une classe. Donc, pour le moment, j'ai fait un petit processus d'attente basé sur l'exemple ci-dessus. Je ne l'ai pas confirmé correctement.

def wait(drv, sec, selector):
    def chk(selector):
        elem = drv.find_element(By.ID, selector)
        if elem:
            return elem
        elem = drv.find_element(By.CLASS_NAME, selector)
        #print("css:",type(elem), elem)
        if elem:
            return elem
        elem = drv.find_element(By.XPATH, selector)
        if elem:
            return elem
        elem = drv.find_elements(By.ID, selector)
        if elem:
            return elem
        elem = drv.find_elements(By.CLASS_NAME, selector)
        if elem:
            return elem
        return False

    try:
        elem = WebDriverWait(drv, sec).until(
            lambda _: chk(selector)
        )
        return elem
    except TimeoutException:
        print(f"wait timeout.. {selector} not found")
        return None

elem = wait(driver, 10, "elem_name")
if not elem:
    print("wow, unknown error.")

C'est un peu comme ça, mais je ne peux pas pardonner le fait que le chk est un peu redondant et que find_element est fait plusieurs fois. De plus, les éléments pouvant être obtenus peuvent être des listes. .. En ce sens, il semble préférable de changer un peu la façon de penser.

De plus, stackoverflow fournit un exemple de solution pour créer votre propre classe. Passez la partie de contrôle dans une liste, et si l'un d'eux frappe, c'est OK. C'est assez intelligent, alors organisons-le pour qu'il fonctionne correctement avec cette idée.

Forme définitive

Attendez la mise en œuvre comme ça

class AnyEc:
        """ Use with WebDriverWait to combine expected_conditions
                in an OR.
        """""
        def __init__(self, *args):
                if type(args) is tuple:
                        lval = list(args)
                else:
                        lval = args

                self.ecs = []
                for v in lval:
                        if type(v) is list:
                                self.ecs += v
                        else:
                                self.ecs.append(v)

                print("ecs type: ", type(self.ecs))
        def __call__(self, driver):
                #print("ecs: ", self.ecs)
                for fn, param in self.ecs:
                        r = fn(param)
                        print("param: ", param, r)
                        if r :
                                return r
                return False

def wait_any(drv, sec, *args):
        try:
                elem = WebDriverWait(drv, sec).until(
                        AnyEc(*args)
                )
                return elem
        except TimeoutException:
                print(f"wait timeout.. {args} not found")
                return False

Comment utiliser

def make_css_selector(key):
        value = []
        value += ['[id="%s"]' % key]
        value += ['#%s' % key]
        value += [key]
        value += ['[name="%s"]' % key]
        value += [".%s" % key]
        return value

#Exemple d'utilisation

#URL d'accès
url='https://ja.stackoverflow.com/'
#La balise que vous souhaitez trouver
str='question-mini-list h3'
#Laisse le moi
val = make_css_selector(str)
fn = [(driver.find_elements_by_css_selector, x) for x in val]

driver = webdriver.Chrome()
driver.get(url)

try :
  #Attendez jusqu'à ce que vous trouviez l'étiquette que vous recherchez, délai d'attente après 10 secondes
  elem = wait_any(driver, 10, fn)
  for e in elem:
    print(e.text)

finally:
  driver.close()
  driver.quit()

Cela n'a pas l'air si intelligent après tout: sweat_smile:

De côté

À l'origine, je voulais combiner XPath avec ou pour que cela puisse être fait en un seul coup, mais j'ai abandonné car il était difficile de convertir en XPath: stuck_out_tongue_winking_eye:

Au fait, jetons un coup d'œil à la source de find_element. https://seleniumhq.github.io/selenium/docs/api/py/_modules/selenium/webdriver/remote/webdriver.html#WebDriver.find_element

        if self.w3c:
            if by == By.ID:
                by = By.CSS_SELECTOR
                value = '[id="%s"]' % value
            elif by == By.TAG_NAME:
                by = By.CSS_SELECTOR
            elif by == By.CLASS_NAME:
                by = By.CSS_SELECTOR
                value = ".%s" % value
            elif by == By.NAME:
                by = By.CSS_SELECTOR
                value = '[name="%s"]' % value
        return self.execute(Command.FIND_ELEMENT, {
            'using': by,
            'value': value})['value']

En fait, il a presque changé en CSS_SELECTOR. Donc, si je n'avais pas besoin de le spécifier dans XPath, je pensais que je devrais pouvoir utiliser une seule recherche, mais cela n'a pas fonctionné, alors j'ai abandonné ici.

Recommended Posts

Voulez-vous attendre un usage général avec Python Selenium?
Je veux faire le test de Dunnett en Python
Attendez qu'une autre fenêtre s'ouvre dans Selenium
Lorsque vous voulez plt.save dans l'instruction for
Je veux faire quelque chose avec Python à la fin
Que faire quand "Aucun noyau pour le langage python trouvé" apparaît dans Hydrogen
Que faire lorsque ʻarguments [0] .scrollIntoView (); `échoue dans python sélénium
Je veux faire quelque chose comme sort uniq en Python
[Python] Comment faire PCA avec Python
Recherche d'un moyen unifié d'attendre et d'obtenir les changements d'état de Selenium pour les éléments Python
[Sous-processus] Lorsque vous souhaitez exécuter un autre programme Python en code Python
Que faire si vous obtenez moins zéro en Python
[Python] Lorsque vous souhaitez utiliser toutes les variables dans un autre fichier
Si vous souhaitez affecter une exportation csv à une variable en python
Comment faire R chartr () en Python
Résumons ce que vous voulez faire.
Que faire si vous ne pouvez pas utiliser la recherche de grille de sklearn en Python
Que faire si aucune documentation Python trouvée pour ... apparaît dans pydoc
Si vous souhaitez compter les mots en Python, il est pratique d'utiliser Counter.
Je veux faire un patch monkey seulement en partie en toute sécurité avec Python
Je veux créer une fenêtre avec Python
Implémentation minimale d'Union Find en Python
Je veux fusionner des dictionnaires imbriqués en Python
Connectez-vous à Yahoo Business avec Selenium Python
Essayez de calculer RPN avec Python (pour les débutants)
Que faire pour obtenir une feuille de calcul Google en Python
Je veux afficher la progression en Python!
Voulez-vous que je corrige cette copie?
Utilisez PIL en Python pour extraire uniquement les données souhaitées d'Exif
Que faire si vous obtenez «Python non configuré». Utilisation de PyDev dans Eclipse
Je veux écrire en Python! (1) Vérification du format de code
Un outil pour créer des images de masque pour ETC en Python
[Pour les débutants] Comment utiliser la commande say avec python!
Je souhaite intégrer une variable dans une chaîne Python
Je veux facilement implémenter le délai d'expiration en python
Comment faire un calcul de hachage avec Salt en Python
Entrée clé qui n'attend pas l'entrée clé en Python
Comment exécuter python dans l'espace virtuel (pour MacOS)
Je veux écrire en Python! (2) Écrivons un test
Même avec JavaScript, je veux voir Python `range ()`!
Je veux échantillonner au hasard un fichier avec Python
Liens pour faire ce que vous voulez avec Sublime Text
Que faire si vous obtenez une erreur lors de l'importation de matplotlib en Python (Mac)
J'étais accro au grattage avec Selenium (+ Python) en 2020
Je veux juste trouver l'intervalle de confiance à 95% de la différence de ratio de population en Python
% Et str.format () en Python. Lequel utilisez-vous?
Je veux travailler avec un robot en python.
Comment télécharger des fichiers depuis Selenium of Python dans Chrome
Je veux écrire en Python! (3) Utiliser des simulacres
Pour ceux qui veulent écrire Python avec vim
Pour faire l'équivalent de Ruby ObjectSpace._id2ref en Python
Je veux utiliser le jeu de données R avec python
Je veux manipuler des chaînes dans Kotlin comme Python!
Que faire si vous exécutez python sur IntelliJ et quittez avec une erreur
Notez ce que vous voulez faire à l'avenir avec Razpai
Que faire lorsque swagger-codegen est terminé avec python et Erreur d'importation: aucun module nommé n'apparaît
[Python3] Code qui peut être utilisé lorsque vous souhaitez redimensionner des images dossier par dossier
[Python] Lorsque vous souhaitez importer et utiliser votre propre package dans le répertoire supérieur