0

I am just making a selenium bot as a fun project that is supposed to play 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 this one, but so far nothing has worked completely. I have already received help with a previous error that was arising from this code here but since this is a different error I have created a new question to deal with it.

Here is my code at the moment:

#!/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, 20).until(EC.visibility_of(self.driver.find_element_by_xpath("//div[@contenteditable='plaintext-only']")))

        # 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@")

and here is the error output:

Traceback (most recent call last):
  File "/Users/kalebrosborough/Documents/Programming/Python/TypeRacerBot.py", line 45, in <module>
    TypeRacerBot = TRBot("TRBot", "R0b0t@")
  File "/Users/kalebrosborough/Documents/Programming/Python/TypeRacerBot.py", line 29, in __init__
    inputField = WebDriverWait(self.driver, 20).until(EC.visibility_of(self.driver.find_element_by_xpath("//div[@contenteditable='plaintext-only']")))
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 394, in find_element_by_xpath
    return self.find_element(by=By.XPATH, value=xpath)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 976, in find_element
    return self.execute(Command.FIND_ELEMENT, {
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: 

Right now, everything works as expected up to the inputField = WebDriverWait(... line so that's what I'm currently focused on fixing, but if you see anything that won't work further along in the code I am open to suggestions there too.

Thanks in advance!

Shock9616
  • 116
  • 9

1 Answers1

0

I can see you are using expected conditions already here

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

If you need to wait for field to be editable please use the expected condition as below

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

So all you need to do is replace your expected condition with "EC.element_to_be_clickable", this should do the trick for you.

CodePuppet
  • 116
  • 3
  • I have just tried this and I still receive the same error. Is there anything else that might be causing this issue? – Shock9616 Jul 17 '20 at 16:47
  • Can you please post, which line exactly is throwing error now – CodePuppet Jul 18 '20 at 02:09
  • The first line in the traceback references my call to the TRBot() class (`TypeRacerBot = TRBot("TRBot", "R0b0t@")`) which isn't really that helpful. the second one is the same line that you were just helping me with (`inputField = WebDriverWait(self.driver, 20).until(EC.element_to_be_clickable(self.driver.find_element_by_xpath("//div[@contenteditable='plaintext-only']")))`) everything else in the traceback is just referencing stuff in the selenium WebDriver module. – Shock9616 Jul 18 '20 at 19:02