python - Python selenium 如何等到元素消失/变得陈旧?
问题描述
我正在尝试以编程方式解决此地址出现的问题:https ://www.arealme.com/brain-memory-game/en/ ,简而言之,它将连续显示几个闪烁的数字,并要求您输入序号倒序。
现在这里是详细信息,当你进入网站时,会有一个开始按钮,它有一个从左侧填充它的蓝条,我发现如果你让你的机器人在蓝条填满之前点击那个按钮按钮,则按钮的功能不会被触发,脚本的其余部分也不会运行。
单击开始按钮后,页面将刷新,您将看到以下闪烁的文本:
这些数字很快就会到来。请注意...
之后,你会看到几个闪烁的数字,它们通过改变alpha来闪烁,它们从完全可见变为完全不可见,当一个数字消失时会出现另一个数字,即使它们具有相同的值,它们也是不同的数字。
然后会有这样的信息:
请单击您刚刚在反向顺序中看到的数字。
还有一个带有十个按钮的数字键盘。
按照它说的做,然后会出现一个按钮,告诉你是否正确,你需要点击它继续下一个问题。
一共有十道题。
现在介绍技术细节。
我设法找到了所涉及元素的类名、xpath 和 id。
开始按钮的 id 是'start'
,我发现time.sleep(3)
它足以填满。
类的层次结构如下:
<div class="questionWrapper">
<div class="question">
<div class="gnumber_title">
<div class="gend-tip">Please click on the number you just saw IN REVERSE ORDER.</div>
</div>
<div class="gnumber_btns" id="gbtn0" style=""><button data-n="9">9</button><button data-n="8">8</button><button data-n="7">7</button><button data-n="6">6</button><button data-n="5">5</button><button data-n="4">4</button><button data-n="3">3</button><button data-n="2">2</button><button data-n="1">1</button><button data-n="0">0</button></div>
</div>
<div class="answer" value="10">1</div>
</div>
问题包装在"questionWrapper"
类中,每个类中只有一个实例"gnumber_title"
,对象包含消息和数字。
类在任何时候都只包含一个元素,类所包含的内容会随着时间而变化,但它们都相对于所述类共享相同的 xpath:'./div'
在问题开始时,当提示是第一条消息时,所述位置内的对象是 class "gstart-tip blink_me"
。
然后它会消失,取而代之的是一个 class 的对象,'gflash-num'
可以使用.text
属性访问其内容。
它通过改变样式闪烁,样式会从"opacity: 1.000000;"
变为"opacity: 0.000000;"
(我不知道确切的值,但它是一个从 1 到 0 的六位小数的浮点数),然后它会变成"display: none;"
,然后它将被删除并另一个实例的"glash-num"
会出现。
在 的几个实例之后"gflash-num"
,出现第二条消息,它的类是"gend-tip"
,位于与数字和第一条消息相同的 xpath 中。
并且数字键盘将可见,其类为"gnumber_btns"
。
显示相同数量的按钮被点击后,"answer"
出现所属类的按钮,点击进入下一题。
这是我解决问题的尝试:
import time
from selenium import webdriver
Firefox = webdriver.Firefox()
Firefox.get('https://www.arealme.com/brain-memory-game/en/')
time.sleep(3)
Firefox.find_element_by_id('start').click()
questions = Firefox.find_elements_by_class_name("questionWrapper")
for q in questions:
numbers = []
title = q.find_element_by_class_name('gnumber_title')
while True:
if title.find_element_by_xpath('./div').get_attribute('class') != 'gstart-tip blink_me':
break
while True:
if title.find_element_by_xpath('./div').get_attribute('class') == "gend-tip":
break
numbers.append(title.find_element_by_class_name('gflash-num').text)
while True:
if not title.find_element_by_class_name('gflash-num').get_attribute('style').startswith('opacity'):
break
while True:
if not title.find_element_by_class_name('gflash-num').get_attribute('style').startswith('display'):
break
buttons = q.find_element_by_class_name("gnumber_btns")
for n in reversed(numbers):
buttons.find_element_by_xpath(f'.//*[text() = "{n}"]').click()
time.sleep(0.5)
q.find_element_by_class_name("answer").click()
和错误:
---------------------------------------------------------------------------
StaleElementReferenceException Traceback (most recent call last)
<ipython-input-1-9d34e88c4046> in <module>
20 numbers.append(title.find_element_by_class_name('gflash-num').text)
21 while True:
---> 22 if not title.find_element_by_class_name('gflash-num').get_attribute('style').startswith('opacity'):
23 break
24 while True:
c:\program files\python39\lib\site-packages\selenium\webdriver\remote\webelement.py in get_attribute(self, name)
137 attributeValue = ''
138 if self._w3c:
--> 139 attributeValue = self.parent.execute_script(
140 "return (%s).apply(null, arguments);" % getAttribute_js,
141 self, name)
c:\program files\python39\lib\site-packages\selenium\webdriver\remote\webdriver.py in execute_script(self, script, *args)
632 command = Command.EXECUTE_SCRIPT
633
--> 634 return self.execute(command, {
635 'script': script,
636 'args': converted_args})['value']
c:\program files\python39\lib\site-packages\selenium\webdriver\remote\webdriver.py in execute(self, driver_command, params)
319 response = self.command_executor.execute(driver_command, params)
320 if response:
--> 321 self.error_handler.check_response(response)
322 response['value'] = self._unwrap_value(
323 response.get('value', None))
c:\program files\python39\lib\site-packages\selenium\webdriver\remote\errorhandler.py in check_response(self, response)
240 alert_text = value['alert'].get('text')
241 raise exception_class(message, screen, stacktrace, alert_text)
--> 242 raise exception_class(message, screen, stacktrace)
243
244 def _value_or_default(self, obj, key, default):
StaleElementReferenceException: Message: The element reference of <div class="gflash-num"> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed
动态元素的任何迭代都可能引发异常,我必须等到位于该 xpath 处的元素不再"gstart-tip blink_me"
开始执行代码的下一个阶段,然后添加 的值"gflash-num"
并等到元素消失再添加下一个值,然后最后当它变为"gend-tip"
按相反顺序单击按钮时。
我试图通过不分配变量并即时获取属性来避免异常,但异常仍然被引发。
但是它引发异常的时间正是它应该从睡眠中醒来并添加数字的时间。
那么我怎么能等到一个元素变得陈旧/不可见/删除/不存在/无论如何,所有的谷歌搜索都告诉了如何做相反的事情:等到元素不再陈旧,但我想等到元素已经消失了,那么该怎么做呢?
我想我发现了一些对解决问题非常重要的东西,使用 ffmpeg 从过程的屏幕录制中提取帧,我能够确定闪烁的确切时间。
第一个提示正好显示 3 秒,每个数字正好闪烁 1 秒。
解决方案
等到任何 elelemt 变得不可见,我们有这个预期的条件:
invisibility_of_element
在我可以看到的代码中:
class invisibility_of_element(invisibility_of_element_located):
""" An Expectation for checking that an element is either invisible or not
present on the DOM.
element is either a locator (text) or an WebElement
"""
def __init(self, element):
self.target = element
如果你有一个正在运行的 webdriverwait 对象,那么你可以试试这个:
WebDriverWait(driver, 10).until(EC.invisibility_of_element((By.XPATH, "xpath here")))
这将等到 xpath 定义的元素不可见。
推荐阅读
- linux - 警告 sqrt:在 gnu awk 中使用否定参数调用
- javascript - 提醒弹出
- php - 尝试在 Laravel 中使用关系时出现未定义的属性错误
- javascript - 使用 ES6/React 解构简单的嵌套对象
- php - 从批处理命令运行 php 服务器
- vue.js - Nuxt.JS scss 不加载 svg 文件
- javascript - 如何训练 LSTM 对 tensorflow.js 中的垃圾邮件进行分类?
- python - 为什么 Python 会错误地调用子进程命令?
- javascript - 自填充依赖选择框
- html - 将 xml 结果保存到 SQL 表中的列