Selenium find element by class breaking code

Question:

My program checks a login page for available combinations. Upon first opening up the page, there is a "check availability" button, which has an ID which Selenium is able to find/use to click.

If the username is taken, a new button pops up which says "check another combination", however the DOM inspector only gives the following information about the second button:

<a class="btn btn-outline-primary btn-block mt-4" href="" role="button" data-ng-click="combination.reset()">
                                    Check another combination
                                </a>

I have tried finding this button by CLASS, CLASSNAME, copying and pasting the XPATH from the inspector and all these have lead to not only the button clicking not working, but the entering and submitting of the intial combination also ceasing to work.

Hoping someone can suggest how to identify this button from the given information. For reference, here is one of the lines I tried:

check_another_combo_button = driver.find_element(By.CLASS, "btn btn-outline-primary btn-block mt-4")

Here is my full code:

from selenium import webdriver
from selenium.webdriver.common.by import By
from webdriver_manager.firefox import GeckoDriverManager
import time

driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())
driver.maximize_window()
site = "https://www......"
driver.get(site)

combination_input_field = driver.find_element(By.ID, "userCombination")
check_availability_button = driver.find_element(By.ID, "btn_fQPAC_submit")

combination_input_field.send_keys(77777) #77777 is one of the unavailable combos
check_availability_button.click()
time.sleep(2)
check_another_combo_button = driver.find_element(By.CLASS_NAME, "btn btn-outline-primary btn-block mt-4")
check_another_combo_button.click()
Asked By: Morgan Roberts

||

Answers:

when you have common classes or dynamically generated classes for elements you wish to interact, the next approach is to be fixed by text.
Try with xpath, that matches the text:

//a[normalize-space(.)='Check another combination']

normalize-space(.) – will trim the whitespace and match the text inside the element.

Yu can include @role="button" as additional matcher inside the a tag.

Answered By: Infern0

I suspect you want to check for inputs say inputs in a loop. Here is the solution using both chrome and firefox.

Solution using chrome driver :

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

chrome_path = r"C:UsershpoddarDesktopToolschromedriver_win32chromedriver.exe"

s = Service(chrome_path)
url = 'https://www......'
driver = webdriver.Chrome(service=s)
driver.get(url)

inputs = ['77777', '88888', '99999', '11111']
for plate in inputs:
    combination_input_field = driver.find_element(By.ID, "qPlateCombination")
    check_availability_button = driver.find_element(By.ID, "btn_fQPAC_submit")
    combination_input_field.send_keys(plate)
    check_availability_button.click()

    element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".btn.btn-outline-primary.btn-block.mt-4")))
    check_another_combo_button = driver.find_element(By.CSS_SELECTOR, ".btn.btn-outline-primary.btn-block.mt-4")
    check_another_combo_button.click()

Solution using Geckodriver :

To use Geckodriver, all you need to add is

from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.chrome.service import Service

and change driver initialization line to

s = Service(executable_path=GeckoDriverManager().install())
webdriver.Firefox(service=s)
driver.maximize_window()
Answered By: Himanshu Poddar