How to click on 2FA 'Duo Push Button' using Selenium in python - python

I am trying to click on a 2FA 'Send me a push' button, however none of my previous attempts have succeeded
def launch_login():
#open login web page
chrome_options = Options()
chrome_options.add_experimental_option("detach", True)
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get("http://my.csus.edu")
#enter login
driver.find_element(By.XPATH, "//input[#id='username']").send_keys("xxxxxxxx")
driver.find_element(By.XPATH, "//input[#id='password']").send_keys("xxxxxxxx")
login = driver.find_element(By.XPATH, "//button[contains(text(),'Login')]")
login.click()
#click duo push button
driver.find_element(By.XPATH, "//button[starts-with(#class, 'positive auth-button') and contains(., 'Send Me a Push')]").click()
return driver
driver = launch_csus()
This is error I am receiving
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//button[starts-with(#class, 'positive auth-button') and contains(., 'Send Me a Push')]"}
(Session info: chrome=101.0.4951.41)
I am still pretty new to selenium and am learning as I go. Is the button a special type of button that behaves in a certain way? Is there a specific way to access the button?
Send me a push inspect:

The button with the text as Send Me a Push is within an <iframe>
Solution
So to click on Send Me a Push you have to:
Induce WebDriverWait for the desired frame to be available and switch to it.
Induce WebDriverWait for the desired element to be clickable.
You can use either of the following locator strategies:
driver.get("http://my.csus.edu")
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[#id='username']"))).send_keys("xxxxxxx")
driver.find_element(By.XPATH, "//input[#id='password']").send_keys("xxxxxxxx")
driver.find_element(By.XPATH, "//button[contains(text(),'Login')]").click()
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[#id='duo_iframe']")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[normalize-space()='Send Me a Push']"))).click()
Note: You have to add the following imports:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Browser Snapshot:

Related

How to send text within an input field with contenteditable="true" within an iframe using Selenium and Python

I am writing a webscraping script that automatically logs into my Email account and sends a message.
I have written the code to the point where the browser has to input the message. I don't know how to access the input field correctly. I have seen that it is an iframe element. Do I have to use the switch_to_frame() method and how can I do that? How can I switch to the iframe if there is no name attribute? Do I need the switch_to_frame() method or can I just use the find_element_by_css_selector() method?
This is the source code of the iframe:
Here is my 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 = 'xxxxxxxxxxxxxxxx'
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("first.last#protonmail.com")
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('first.last#mail.com')
subjectElem = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[id^='subject-composer']")))
subjectElem.send_keys('anySubject')
messageElem = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#squire > div > div:nth-child(1)")))
messageElem.send_keys('message')
To access the <input> field within the iframe so you have to:
Induce WebDriverWait for the desired frame to be available and switch to it.
Induce WebDriverWait for the desired element to be clickable.
You can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[title='Editor']")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div#squire"))).send_keys('message')
Using XPATH:
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[#title='Editor']")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[#id='squire']"))).send_keys('message')
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
PS: As the <div> tag is having the attribute contenteditable="true" you can still send text to the element.
Reference
You can find a couple of relevant discussions in:
Switch to an iframe through Selenium and python
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element while trying to click Next button with selenium
selenium in python : NoSuchElementException: Message: no such element: Unable to locate element
You have to switch to iframe with driver.switch_to.frame method.
Like any other web element iframe element can be located by ID, CLASS, XPATH, CSS_SELECTOR etc.
Looks like here you can use this method:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[title='Editor']")))
Or
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[data-testid='squire-iframe']")))
When finished working within the iframe you will have to switch back to the default content with
driver.switch_to.default_content()
you first need to switch to iframe
wait = WebDriverWait(driver, 30)
wait.until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe[title='Editor']")))
and now here write the code to send the message body. something like this:
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"))).click()
email = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div#squire div:nth-child(2)")))
email.send_keys('write the email here')
also once you are done with iframe interaction, you should switch to default content:
driver.switch_to.default_content()

Python selenium How to click an element in iframe?

My first test with selenium is to click a button on a website. The first button that I need to click is this "yes you can use cookies"-buttons in the popup of a website. But it seems that selenium doesn't find that button even though I added a wait line. I tried other buttons in the popup as well, but none of them can be found by my element_to_be_clickable. The element is in an iframe, so I guess I have to change to it, but it seems that I'm doing something wrong.
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
driver_path = "D:/Python/learning_webclicker/firefox_driver/geckodriver.exe"
firefox_path = "C:/Program Files/Mozilla Firefox/firefox.exe"
option = webdriver.FirefoxOptions()
option.binary_location = firefox_path
driver = webdriver.Firefox(executable_path=driver_path, options=option)
url = "https://web.de/"
driver.get(url)
WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it(driver.find_element_by_xpath("/html/body/div[2]/iframe")))
#I tried to find the "save-all-conditionally"-element with lots of different methods:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "save-all-conditionally"))).click()
#WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, """//*[#id="save-all-conditionally"]"""))).click()
#WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, "save-all-conditionally")))
# ...
This raises the error
selenium.common.exceptions.TimeoutException: Message:
And if I try to click the button directly after changing to iframe (or without checking for iframe), then I get
driver.implicitly_wait(10)
element=driver.find_element_by_xpath("""//*[#id="save-all-conditionally"]""")
element.click()
>>> selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: [id="save-all-conditionally"]
I guess, that I'm not really in the iframe (although frame_to_be_available_and_switch_to_it doesn't return an error), but I'm not sure how/what/why.
The element you are looking after is inside nested iframe. You need to switch both the
iframes.
Use following css selector to identify the iframe.
WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[name='landingpage']")))
WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[src*='plus.web.de']")))
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "save-all-conditionally"))).click()
Or Use below xpath to identify the iframe.
WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[#name='landingpage']")))
WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[contains(#src,'plus.web.de')]")))
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "save-all-conditionally"))).click()

selenium.common.exceptions.TimeoutException: Message error sending text to username field within iframe using Selenium Python

When i try to locate one element with selellium it fails
driver = webdriver.Chrome(executable_path = r'./chromedriver.exe')
driver.get("http://eltiempo.com/login")
try:
element = WebDriverWait(driver, 30).until(
EC.presence_of_element_located((By.XPATH, "//*[#id='username']"))
)
finally:
driver.quit()
To send a character sequence to the username field as the element is within an <iframe> so you have to:
Induce WebDriverWait for the desired frame to be available and switch to it.
Induce WebDriverWait for the desired element to be clickable.
You can use either of the following Locator Strategies:
Using CSS_SELECTOR:
driver.get("https://www.eltiempo.com/login")
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe.iframe-login")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[name='username']"))).send_keys("Nick Rondon#stackoverflow.com")
Using XPATH:
driver.get('https://www.eltiempo.com/login')
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[#class='iframe-login']")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[#name='username']"))).send_keys("Nick Rondon#stackoverflow.com")
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Browser Snapshot:
Reference
You can find a couple of relevant discussions in:
Ways to deal with #document under iframe
Switch to an iframe through Selenium and python
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element while trying to click Next button with selenium
selenium in python : NoSuchElementException: Message: no such element: Unable to locate element

how to click button in headless and button have div tag inside it using selenium python?

using this code for without headless approch..
website link: https://www.na-kd.com/en/sweaters?sortBy=popularity&count=108
try:
element = self.driver.find_element_by_xpath('//*[#id="container"]/div/div/div[3]/div/div[4]/div/div[1]/div[2]/div[1]/button')
self.driver.execute_script("arguments[0].click();", element)
except Exception as e:
print('Error in clicking BTN : '+str(e))
Because this btn have div-tag inside it so it is not working with headless and virtual-display.
I also Try wait:
try:
element=WebDriverWait(self.driver, 20).until(
EC.element_to_be_clickable((By.XPATH, '//*[#id="container"]/div/div/div[3]/div/div[4]/div/div[1]/div[2]/div[1]/button')))
self.driver.execute_script("arguments[0].click();", element)
except Exception as e:
print('Error in clicking BTN : '+str(e))
chromedriver --version
ChromeDriver 78.0.3904.70
Google Chrome 78.0.3904.108
Using the headless mode when you fire any event add window-size() Because headless browser can't recognise where to click without window size.
To click on Load more products button Induce WebDriverWait() and wait for element_to_be_clickable() and use below xpath
To verify this whether button is clicked or not just scroll down the page and get the value from div tag.
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
# Headless option with window-size()
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('window-size=1920x1080');
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get("https://www.na-kd.com/en/sweaters?sortBy=popularity&count=108&ssr=on&loadfailure=1")
# Load more products button
element=WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//button[.//div[text()='Load more products']]")))
driver.execute_script("arguments[0].click();", element)
# To verify that whether button is clicked or not
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2) #wait for page to load
print(WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[#class='qa6 qmz qn0']"))).text)

How to interact with the reCAPTCHA audio element using Selenium and Python

I want to, click on the button to resolve the captcha through the audio, but selenium does not detect the specified "id".
browser.get("https://www.google.com/recaptcha/api2/demo")
mainWin = browser.current_window_handle
iframe = browser.find_elements_by_tag_name("iframe")[0]
browser.switch_to_frame(iframe)
CheckBox = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.ID ,"recaptcha-anchor"))).click()
sleep(4)
audio = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.ID ,"recaptcha-audio-button"))).click()
To click() on the button to resolve the captcha through the audio as the desired elements are within an <iframe> so you have to:
Induce WebDriverWait for the desired frame to be available and switch to it.
Induce WebDriverWait for the desired element to be clickable.
You can use the following Locator Strategies:
Code Block:
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
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options, executable_path=r'C:\WebDrivers\chromedriver.exe')
driver.get("https://www.google.com/recaptcha/api2/demo")
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[src^='https://www.google.com/recaptcha/api2/anchor']")))
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "span#recaptcha-anchor"))).click()
driver.switch_to.default_content()
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[title='recaptcha challenge']")))
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button#recaptcha-audio-button"))).click()
Browser Snapshot:
Reference
Ways to deal with #document under iframe
Outro
You can find a couple of relevant discussions in:
How to click on the reCaptcha using Selenium and Java
CSS selector for reCaptcha checkbok using Selenium and vba excel
Find the reCAPTCHA element and click on it — Python + Selenium
Very useful, just put your attention, that text: 'recaptcha challenge' in selector below depends from regional settings/language:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[title='recaptcha challenge']")))

Categories