Функция Selenium click () (вроде бы) случайно не устанавливает флажок [Нет ошибок] [Python] - PullRequest
0 голосов
/ 03 февраля 2020

Я новичок в селене и заставляю бота автоматически делать пустяки. Вход в систему работает отлично, как и большинство других полей для кликов и перехода к следующему вопросу.

Случайным образом они не нажимают кнопку, а также не нажимают для следующего l oop. Это часто случается с последними вопросами (9 и более), но это может быть совпадением.

Весьма смущает то, что ошибки не отображается? Код заканчивается без ошибок

Кто-нибудь знает, почему это происходит?

Основной код

from selenium import webdriver
from time import *
from data import *
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class TriviaBot():
    def __init__(self):
        self.driver = webdriver.Chrome()
        self.driver.get("https://www.freekigames.com/educational-trivia")
    def login(self):
        # selects and clicks the "Login/Sign Up" button on the home-page
        self.login_btn = self.driver.find_element_by_xpath('//*[@id="loginContainer"]/a')
        self.login_btn.click()

        sleep(2) # allows username + password box to load in

        self.driver.switch_to.frame(bot.driver.find_element_by_xpath('//*[@id="jPopFrame_content"]')) # switches to correct frame for login box

        # selects username-box and types in my username and then does the same for password
        self.username_box = self.driver.find_element_by_xpath('//*[@id="userName"]') #username
        self.username_box.send_keys(username)

        self.username_box = self.driver.find_element_by_xpath('//*[@id="password"]') #password
        self.username_box.send_keys(password)

        # selects login box and then clicks
        self.login_box = self.driver.find_element_by_xpath('//*[@id="bp_login"]')
        self.login_box.click()

        sleep(2) # allows main page to load again
    def AmericanPresidents(self):
        self.i = 0
        # sends browser to first trivia
        self.driver.get("https://www.freekigames.com/american-presidents-trivia")

        while True: #there are ? # of questions, so I loop it 12 times
            self.i += 1
            if self.i == 13:
                break
            print("run: "+str(self.i))

            # sets the variable to the current question so that the correct answer can be located through answer lists
            self.current_question = ((self.driver.find_element_by_xpath('//*[@id="quizContainer"]/div[2]')).text)

            #setting variables for boxes and their text values. The text can be corrolated to the button allowing the bot to click the correct answer

            self.button_1 = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH,('/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[1]/span[@class="answerBox"]/a[@name="checkboxtag"]'))))
            self.text_1   = (self.driver.find_element_by_xpath('//*[@id="quizContainer"]/div[3]/div[1]/span[2]').text)


            self.button_2 = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH,('/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[2]/span[@class="answerBox"]/a[@name="checkboxtag"]'))))
            self.text_2   = (self.driver.find_element_by_xpath('//*[@id="quizContainer"]/div[3]/div[2]/span[2]').text)


            self.button_3 = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH,('/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[3]/span[@class="answerBox"]/a[@name="checkboxtag"]'))))
            self.text_3   = (self.driver.find_element_by_xpath('//*[@id="quizContainer"]/div[3]/div[3]/span[2]').text)


            self.button_4 = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH,('/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[4]/span[@class="answerBox"]/a[@name="checkboxtag"]'))))
            self.text_4   = (self.driver.find_element_by_xpath('//*[@id="quizContainer"]/div[3]/div[4]/span[2]').text)


            for i in range(0, len(american_presidents)):
                if american_presidents[i]["question"] == self.current_question:
                    self.dataLine = i
            if self.text_1 == american_presidents[self.dataLine]["answer"]:
                self.button_1.click()
            if self.text_2 == american_presidents[self.dataLine]["answer"]:
                self.button_2.click()
            if self.text_3 == american_presidents[self.dataLine]["answer"]:
                self.button_3.click()
            if self.text_4 == american_presidents[self.dataLine]["answer"]:
                self.button_4.click()

            sleep(0.5) # to stop the code from beating itself. Going to quick

            # selects and clicks the "Next Question!" button
            nextquestion_btn = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH,('//*[@id="nextQuestion"]'))))
            nextquestion_btn.click()
bot = TriviaBot()
bot.login()
bot.AmericanPresidents()

data.py

american_presidents = [
    {"question" : "Who was the 1st president of the United States?",
     "answer"   : "George Washington"},
    {"question" : "Who was the 2nd president of the United States?",
     "answer"   : "John Adams"},
    {"question" : "Who was the 3rd president of the United States?",
     "answer"   : "Thomas Jefferson"},
    {"question" : "Who was the 4th president of the United States?",
     "answer"   : "James Madison"},
    {"question" : "Who was the 5th president of the United States?",
     "answer"   : "James Monroe"},
    {"question" : "Who was the 6th president of the United States?",
     "answer"   : "John Quincy Adams"},
    {"question" : "Who was the 7th president of the United States?",
     "answer"   : "Andrew Jackson"},
    {"question" : "Who was the 8th president of the United States?",
     "answer"   : "Martin Van Buren"},
    {"question" : "Who was the 9th president of the United States?",
     "answer"   : "William Henry Harrison"},
    {"question" : "Who was the 10th president of the United States?",
     "answer"   : "John Tyler"},
    {"question" : "Who was the 11th president of the United States?",
     "answer"   : "James K. Polk"},
    {"question" : "Who was the 12th president of the United States?",
     "answer"   : "Zachary Taylor"},
    {"question" : "Who was the 13th president of the United States?",
     "answer"   : "Millard Fillmore"},
    {"question" : "Who was the 14th president of the United States?",
     "answer"   : "Franklin Pierce"},
    {"question" : "Who was the 15th president of the United States?",
     "answer"   : "James Buchanan"},
    {"question" : "Who was the 16th president of the United States?",
     "answer"   : "Abraham Lincoln"},
    {"question" : "Who was the 17th president of the United States?",
     "answer"   : "Andrew Johnson"},
    {"question" : "Who was the 18th president of the United States?",
     "answer"   : "Ulysses S. Grant"},
    {"question" : "Who was the 19th president of the United States?",
     "answer"   : "Rutherford B. Hayes"},
    {"question" : "Who was the 20th president of the United States?",
     "answer"   : "James A. Garfield"},
    {"question" : "Who was the 21st president of the United States?",
     "answer"   : "Chester A. Arthur"},
    {"question" : "Who was the 22nd president of the United States?",
     "answer"   : "Grover Cleveland"},
    {"question" : "Who was the 23rd president of the United States?",
     "answer"   : "Benjamin Harrison"},
    {"question" : "Who was the 24th president of the United States?",
     "answer"   : "Grover Cleveland"},
    {"question" : "Who was the 25th president of the United States?",
     "answer"   : "William McKinley"},
    {"question" : "Who was the 26th president of the United States?",
     "answer"   : "Theodore Roosevelt"},
    {"question" : "Who was the 27th president of the United States?",
     "answer"   : "William Howard Taft"},
    {"question" : "Who was the 28th president of the United States?",
     "answer"   : "Woodrow Wilson"},
    {"question" : "Who was the 29th president of the United States?",
     "answer"   : "Warren G. Harding"},
    {"question" : "Who was the 30th president of the United States?",
     "answer"   : "Clavin Coolidge"},
    {"question" : "Who was the 31st president of the United States?",
     "answer"   : "Herbert Hoover"},
    {"question" : "Who was the 32nd president of the United States?",
     "answer"   : "Frankin D. Roosevelt"},
    {"question" : "Who was the 33rd president of the United States?",
     "answer"   : "Harry S. Truman"},
    {"question" : "Who was the 34th president of the United States?",
     "answer"   : "Dwight D. Eisenhower"},
    {"question" : "Who was the 35th president of the United States?",
     "answer"   : "John F. Kennedy"},
    {"question" : "Who was the 36th president of the United States?",
     "answer"   : "Lyndon B. Johnson"},
    {"question" : "Who was the 37th president of the United States?",
     "answer"   : "Richard Nixon"},
    {"question" : "Who was the 38th president of the United States?",
     "answer"   : "Gerald Ford"},
    {"question" : "Who was the 39th president of the United States?",
     "answer"   : "Jimmy Carter"},
    {"question" : "Who was the 40th president of the United States?",
     "answer"   : "Ronald Reagan"},
    {"question" : "Who was the 41st president of the United States?",
     "answer"   : "George W. H. Bush"},
    {"question" : "Who was the 42nd president of the United States?",
     "answer"   : "Bill Clinton"},
    {"question" : "Who was the 43rd president of the United States?",
     "answer"   : "George W. Bush"},
    {"question" : "Who was the 44th president of the United States?",
     "answer"   : "Barack Obama"}

]

Ошибка

Traceback (most recent call last):
  File ".\trivia-bot.py", line 83, in <module>
    bot.AmericanPresidents()
  File ".\trivia-bot.py", line 80, in AmericanPresidents
    nextquestion_btn.click()
  File "C:\Program Files\Python36\lib\site-packages\selenium\webdriver\remote\webelement.py", line 80, in click
    self._execute(Command.CLICK_ELEMENT)
  File "C:\Program Files\Python36\lib\site-packages\selenium\webdriver\remote\webelement.py", line 633, in _execute
    return self._parent.execute(command, params)
  File "C:\Program Files\Python36\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "C:\Program Files\Python36\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
  (Session info: chrome=79.0.3945.130)

Ответы [ 4 ]

1 голос
/ 03 февраля 2020

Наиболее вероятная причина, по которой вы не видите ошибку, заключается в том, что используемый вами xpath на самом деле находит элементы, но, возможно, не те, которые вы предполагали. Страница загружается со стилем анимации для каждого вопроса, и вы можете выполнять поиск до того, как они будут выполнены. То, что вам следует делать, - это ждать, пока элемент будет найден, и использовать xpath, более конкретно указывающий c, что вам нужно. Вот ссылка на дополнительную информацию об ожиданиях: https://selenium-python.readthedocs.io/waits.html

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC   

self.button_1 = WebDriverWait(driver, 10).until(EC.presence_of_element_located(By.XPATH,'/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[1]/span[@class="answerBox"]/a[@name="checkboxtag"]))

Сделайте это для остальных ваших элементов. Я также использовал бы эти локаторы:

#setting variables for boxes and their text values. The text can be corrolated to the button allowing the bot to click the correct answer
self.button_1 = (self.driver.find_element_by_xpath('/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[1]/span[@class="answerBox"]/a[@name="checkboxtag"]))
self.text_1   = (self.driver.find_element_by_xpath(/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[1]/span[@class="answerText"]).text)

self.button_2 = (self.driver.find_element_by_xpath(/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[2]/span[@class="answerBox"]/a[@name="checkboxtag"]))
self.text_2   = (self.driver.find_element_by_xpath(/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[2]/span[@class="answerText"]).text)

self.button_3 = (self.driver.find_element_by_xpath(/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[3]/span[@class="answerBox"]/a[@name="checkboxtag"]))
self.text_3   = (self.driver.find_element_by_xpath(/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[3]/span[@class="answerText"]).text)

self.button_4 = (self.driver.find_element_by_xpath(/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[4]/span[@class="answerBox"]/a[@name="checkboxtag"]))
self.text_4   = (self.driver.find_element_by_xpath(/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[4]/span[@class="answerText"]).text)

Другой вариант для нахождения флажка, чтобы щелкнуть, состоит в том, чтобы использовать эти локаторы вместо:

self.button_1 = WebDriverWait(driver, 10).until(EC.presence_of_element_located(By.XPATH, '/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[1]/span[@class="answerBox"]/input[@name="answers"]'))
self.button_2 = WebDriverWait(driver, 10).until(EC.presence_of_element_located(By.XPATH, '/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[2]/span[@class="answerBox"]/input[@name="answers"]'))
self.button_3 = WebDriverWait(driver, 10).until(EC.presence_of_element_located(By.XPATH, '/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[3]/span[@class="answerBox"]/input[@name="answers"]'))
self.button_4 = WebDriverWait(driver, 10).until(EC.presence_of_element_located(By.XPATH, '/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[4]/span[@class="answerBox"]/input[@name="answers"]'))

Ваше сообщение об ошибке относится к кнопке следующего вопроса и это не быть интерактивным. Используйте это вместо:

 nextquestion_btn = WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.XPATH,('//*[@id="nextQuestion"]'))))
0 голосов
/ 04 февраля 2020

Я не уверен, как, но я просто перекодировал все, и это работает удивительно

Большое спасибо @Muzzamil и @RKelley за терпение и информацию.

Вот ( как-то) исправил код

from selenium import webdriver
from time import *
from data import *
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException


class TriviaBot():
    def __init__(self):
        self.driver = webdriver.Chrome()
        self.driver.get("https://www.freekigames.com/educational-trivia")
        self.i = 0
    def login(self):
        # selects and clicks the "Login/Sign Up" button on the home-page
        self.login_btn = self.driver.find_element_by_xpath('//*[@id="loginContainer"]/a')
        self.login_btn.click()

        sleep(2) # allows username + password box to load in

        self.driver.switch_to.frame(bot.driver.find_element_by_xpath('//*[@id="jPopFrame_content"]')) # switches to correct frame for login box

        # selects username-box and types in my username and then does the same for password
        self.username_box = self.driver.find_element_by_xpath('//*[@id="userName"]') #username
        self.username_box.send_keys(username)

        self.username_box = self.driver.find_element_by_xpath('//*[@id="password"]') #password
        self.username_box.send_keys(password)

        # selects login box and then clicks
        self.login_box = self.driver.find_element_by_xpath('//*[@id="bp_login"]')
        self.login_box.click()

        sleep(2) # allows main page to load again
    def AmericanPresidents(self):
        # sends browser to first trivia
        self.driver.get("https://www.freekigames.com/american-presidents-trivia")

        # sets the variable to the current question so that the correct answer can be located through answer lists
        self.current_question = ((self.driver.find_element_by_xpath('//*[@id="quizContainer"]/div[2]')).text)

        #setting variables for boxes and their text values. The text can be corrolated to the button allowing the bot to click the correct answer
        #/html//div[@id="quizContainer"]/div[@class="answersContainer"]/div[1]/span[@class="answerBox"]/a[@name="checkboxtag"]

        for i in range(0, len(american_presidents)):
            if american_presidents[i]["question"] == self.current_question:
                self.current_answer = american_presidents[i]["answer"]


        self.xpath_1  = '//*[@id="quizContainer"]/div[3]/div[1]/span[1]/a'
        self.text_1   = ((WebDriverWait(self.driver, 10)).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="quizContainer"]/div[3]/div[1]/span[2]')))).text


        self.xpath_2  = '//*[@id="quizContainer"]/div[3]/div[2]/span[1]/a'
        self.text_2   = ((WebDriverWait(self.driver, 10)).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="quizContainer"]/div[3]/div[2]/span[2]')))).text


        self.xpath_3  = '//*[@id="quizContainer"]/div[3]/div[3]/span[1]/a'
        self.text_3   = ((WebDriverWait(self.driver, 10)).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="quizContainer"]/div[3]/div[3]/span[2]')))).text


        self.xpath_4  = '//*[@id="quizContainer"]/div[3]/div[4]/span[1]/a'
        self.text_4   = ((WebDriverWait(self.driver, 10)).until(EC.element_to_be_clickable((By.XPATH, '//*[@id="quizContainer"]/div[3]/div[4]/span[2]')))).text


        if self.text_1 == self.current_answer:
            self.button = WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.XPATH, self.xpath_1)))
        if self.text_2 == self.current_answer:
            self.button = WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.XPATH, self.xpath_2)))
        if self.text_3 == self.current_answer:
            self.button = WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.XPATH, self.xpath_3)))
        if self.text_4 == self.current_answer:
            self.button = WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.XPATH, self.xpath_4)))

        self.button.click()

        # selects and clicks the "Next Question!" button
        nextquestion_btn = WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.XPATH,('//*[@id="nextQuestion"]'))))
        nextquestion_btn.click()

bot = TriviaBot()
bot.login()
for i in range(1, 13):
    print("Run: "+str(i))
    bot.AmericanPresidents()

print("will it work afterwards?")

Еще раз спасибо за все ваши старания и терпение. Я могу наконец закончить sh этот проклятый код: D

0 голосов
/ 04 февраля 2020

Поскольку вы работаете с щелчком мыши, чтобы перейти к новому вопросу, есть больше шансов, что следующий вопрос или элемент загружен неправильно.

Попробуйте click с webdriver wait, чтобы элемент был кликабельным, поэтому элемент в состоянии получить click.

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

element = WebDriverWait(driver, 40).until(
EC.element_to_be_clickable((By.XPATH, "//*[@id="bp_login"]")))
element.click()

ИЛИ (попробуйте щелкнуть скриптом Java, но без ожидания, так как это может быть неудачным при ожидании)

element= driver.find_element(By.XPATH, "//*[@id='bp_login']")
driver.execute_script("arguments[0].click();", element)
0 голосов
/ 03 февраля 2020

По моему опыту, клик может go заблуждаться, если элемент не готов к щелчку. Я бы попробовал использовать WebDriverWait, чтобы этого не произошло.

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

button = WebDriverWait(self.driver, 15).until(
  EC.element_to_be_clickable((By.XPATH, '//*[@id="quizContainer"]/div[3]/div[1]/span[1]/a'))
)

button.click()
...