如何在 python 3.8 中等待文本字段可使用 selenium 进行编辑

How to wait for a text field to be editable with selenium in python 3.8

我正在制作一个 selenium 机器人作为一个有趣的项目,应该可以玩 typeracer for me, and I am having a bit of trouble getting it to wait for the countdown to be done before it tries to start typing. The best way that I have found to do this is to just wait for the text input field to be editable instead of waiting for the countdown popup to be gone, but as I said before, I can't get it to wait unless I use a time.sleep() function. This wouldn't work well because of the fact that we could have to wait for anywhere from 5ish-12ish seconds before the bot can start so it could wait too long or not long enough. I have tried the solutions from many other similar questions such as ,但到目前为止没有任何效果。

这是我目前的代码:

#!/usr/bin/env/python3

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class TRBot:
    def __init__(self, username, passwd):
        self.username = username
        self.driver = webdriver.Safari()
        self.driver.get("https://play.typeracer.com")  # Open automated safari to typeracer
        time.sleep(2)
   

        self.driver.find_element_by_xpath("//a[@title=\"Keyboard shortcut: Ctrl+Alt+I\"]").click()  # Click the "Enter a typing race" button
        time.sleep(2)


        inputField = WebDriverWait(self.driver, 10).until(EC.visibility_of((By.XPATH, "<div contenteditable=\"plaintext-only\"></div>")))

        # Find the first word of the passage to type
        text = self.driver.find_element_by_xpath("//*[@id=\"gwt - uid - 15\"]/table/tbody/tr[2]/td/table/tbody/tr[1]/td/table/tbody/tr[1]/td/div/div/span[1]").get_attribute("innerHTML")

        while text != "":
            inputField.send_keys(text)  # Type the word
            text = self.driver.find_element_by_xpath("//*[@id=\"gwt - uid - 15\"]/table/tbody/tr[2]/td/table/tbody/tr[1]/td/table/tbody/tr[1]/td/div/div/span[1]").get_attribute("innerHTML")  # Find the next word

        time.sleep(5)

        self.driver.quit()


TypeRacerBot = TRBot("TRBot", "R0b0t@")

这是错误输出:

Traceback (most recent call last):
  File "/Users/myuser/Documents/Programming/Python/TypeRacerBot.py", line 45, in <module>
    TypeRacerBot = TRBot("TRBot", "R0b0t@")
  File "/Users/myuser/Documents/Programming/Python/TypeRacerBot.py", line 29, in __init__
    inputField = WebDriverWait(self.driver, 10).until(EC.visibility_of((By.XPATH, "<div contenteditable=\"plaintext-only\">\*</div>")))
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/selenium/webdriver/support/wait.py", line 71, in until
    value = method(self._driver)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/selenium/webdriver/support/expected_conditions.py", line 144, in __call__
    return _element_if_visible(self.element)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/selenium/webdriver/support/expected_conditions.py", line 148, in _element_if_visible
    return element if element.is_displayed() == visibility else False
AttributeError: 'tuple' object has no attribute 'is_displayed'

现在,inputField = WebDriverWait(... 行之前的一切都按预期工作,所以这就是我目前专注于修复的问题,但如果您在代码中看到任何无法进一步工作的内容,我会打开那里也有建议。

提前致谢!

您需要替换行:

inputField = WebDriverWait(self.driver, 10).until(EC.visibility_of((By.XPATH, "<div contenteditable=\"plaintext-only\"></div>")))

与:

inputField = WebDriverWait(self.driver, 10).until(EC.visibility_of(self.driver.find_element_by_xpath("//div[@contenteditable='plaintext-only']")))

或:

inputField = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.XPATH, "//div[@contenteditable='plaintext-only']")))