Eh bien, je n'aimais pas le flottement de la souris dans le système d'entreprise (gestion des présences).
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.
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
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.
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.
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:
À 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