【发布时间】:2021-08-27 06:58:03
【问题描述】:
我正在尝试以编程方式解决此地址出现的问题: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'
在问题开始时,当提示是第一条消息时,所述位置内的对象属于"gstart-tip blink_me"类。
然后它会消失,取而代之的是一个'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 秒。
【问题讨论】:
-
@GhostOps 你似乎暗示了我正在尝试做的事情的对立面。
标签: python python-3.x selenium