Home > Back-end >  How do I access a button element correctly in Selenium?
How do I access a button element correctly in Selenium?

Time:01-25

Following my usecase in the OP, enter image description here

I have copied the CSS selector of the span element and tried this:

sendButton = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "body > div.app-root > div.composer-container > div > div > div > footer > div > div.button-group.button-group-solid-norm.button-group-medium > button > span")))
sendButton.click()

I get the following error:

selenium.common.exceptions.NoSuchWindowException: Message: Browsing context has been discarded

I am not sure, if I targeted the right element for what I want to achieve. I often struggle to find the right strategy to target an element. What is the best way if there is no id element oder a nice and short css selector? I checked the Selenium docs (https://selenium-python.readthedocs.io/locating-elements.html) but hesitated choosing one of the suggested methods.

Original code:

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

myPassword = 'XXXXXXXXXXXXXX!'

browser = webdriver.Firefox() # Opens Firefox webbrowser
browser.get('https://protonmail.com/') # Go to protonmail website
loginButton = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "a.btn-ghost:nth-child(1)")))
loginButton.click()
usernameElem = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#username")))
usernameElem.send_keys("[email protected]")
passwordElem = browser.find_element_by_css_selector("#password")
passwordElem.send_keys(myPassword)
anmeldenButton = browser.find_element_by_css_selector(".button")
anmeldenButton.click()
newMessage = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, "/html/body/div[1]/div[3]/div/div/div[1]/div[2]/button")))
newMessage.click()
addressElem = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[id^='to-composer']")))
addressElem.send_keys('[email protected]')
subjectElem = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[id^='subject-composer']")))
subjectElem.send_keys('anySubject')
WebDriverWait(browser, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe[title='Editor']")))
WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div#squire"))).send_keys('Test message')
sendButton = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "body > div.app-root > div.composer-container > div > div > div > footer > div > div.button-group.button-group-solid-norm.button-group-medium > button > span")))
sendButton.click()
browser.switch_to.default_content()

CodePudding user response:

Some initial comments...

  1. You don't need to keep using WebDriverWait(browser, 10). Instead declare a variable to store the WebDriverWait instance, wait = WebDriverWait(browser, 10), and then use the variable everywhere, e.g.

    loginButton = WebDriverWait(browser, 10).until()
    

    would become

    loginButton = wait.until()
    

    It removes unnecessary instantiations and makes the code easier to read.

  2. Unless you are going to reuse the variable, just one-line the WebDriverWait() and action, e.g.

    loginButton = wait.until()
    loginButton.click()
    

    becomes

    wait.until().click()
    

    It reduces the number of local variables you have, especially when you aren't using them and also makes the code easier to read.


The main answer...

I don't have a protonmail account but my guess is that your last few lines of code are the issue. It looks like after switching to an IFRAME, the IFRAME is no longer available... maybe due to the .send_keys()? Try moving the browser.switch_to.default_content() before the final .click() line or you may even have to switch back to default and then switch into a new IFRAME. That should at least get you pointed in the right direction. Updated code below.

wait.until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe[title='Editor']")))
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div#squire"))).send_keys('Test message')
browser.switch_to.default_content()
# may need to switch into the correct IFRAME again here
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "body > div.app-root > div.composer-container > div > div > div > footer > div > div.button-group.button-group-solid-norm.button-group-medium > button > span"))).click()

CodePudding user response:

As per the screenshot:

screenshot

to identify the element you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:

  • Using CSS_SELECTOR:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.button-group.button-group-solid-norm.button-group-medium > button span"))).click()
    

CodePudding user response:

I would try to select the button by xpath. I think its way more accurate. If your on chrome or fire fox

right click on the an element on the browser

right click and copy and copy by full xpath

//*[@id="hireme"]/div/ul/li[4]/div/a
  •  Tags:  
  • Related