How to switch to a modal in Python using Selenium - python

I'm using Python and Selenium. My problem is that I can't switch on the modal that pops out and I can't click the buttons in it.
This is the elements of the modal:
This is my code:
minus the url of course
browser = webdriver.Chrome(executable_path="D:\\sasdsa\\automate\\chromedriver_win32\\chromedriver.exe")
user_name = browser.find_element_by_xpath("//input[#id='username']")
user_name.send_keys("test.employee")
##Password
pass_word = browser.find_element_by_xpath("//input[#id='password']")
pass_word.send_keys("123")
##log_in = browser.find_element_by_css_selector(".btn")
log_in = browser.find_element_by_xpath("//button[#class='btn btn-sm btn-primary btn-block']")
log_in.click()
##punch
#driver.find_element_by_id("//#id='product_view')
#To open the modal
punch_in = browser.find_element_by_xpath("//button[#class='btn btn-success btn-sm pull-right']")
punch_in.click()
#cant switch to the modal to access the button
browser.switch_to_frame("product_view")
punch_in2 = browser.find_element_by_xpath("//button[#id='save_me']")
punch_in2.click()

Delete the line below and it should work fine.
browser.switch_to_frame("product_view")
You don't need to do anything special here. A modal dialog like this is just HTML like any other HTML on the page. You access it just like you would anything else.
Having said that... if you click a button, etc. that launches the dialog, you will probably have to add a WebDriverWait to wait for the dialog to be visible before accessing elements inside it, etc.

Andersson and JeffC are right. I had a similar issue. I treated the modal window as something different, which didn't work by the way. At the end, I just treated it in the usual way. I simply added browser.implicitly_wait(60) after initiating the browser, and it worked.

What Jeff said worked for me. I had
<div class="ReactModalPortal">
I just added sleep for 3 seconds to see if it was working. It worked.
Then I used :
act = ActionChains(self.driver)
act.send_keys(Keys.TAB).perform()
act.send_keys(Keys.ENTER).perform()

Related

NoSuchElementException when using Selenium Python [duplicate]

This question already has an answer here:
Selenium "selenium.common.exceptions.NoSuchElementException" when using Chrome
(1 answer)
Closed 2 years ago.
I'm trying to scrape the promotion information of each product from a website by clicking on the product and go to its detailed page. When the spider clicks on the product, the web will ask it to log in, and I tried the following code:
def __init__(self):
self.driver = webdriver.Chrome(executable_path = '/usr/bin/chromedriver')
...
def start_scraping(self, response):
self.driver.get(response.url)
self.driver.find_element_by_id('fm-login-id').send_keys('iamgooglepenn')
self.driver.find_element_by_id('fm-login-password').send_keys('HelloWorld1_')
self.driver.find_element_by_class_name('fm-button fm-submit password-login').click()
...
However, there is NoSuchElementException when I run it.
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="fm-login-id"]"}
'spider_exceptions/NoSuchElementException': 14,
The HTML of the login page is as follows:
<div class='input-plain-wrap input-wrap-loginid'>
<input id='fm-login-id' class='fm-text' name='fm-login-id'...>
event
</div>
So, I'm pretty sure the id should be 'fm-login-id'. The reason I could think of that might cause this issue is that this login page is a popup.
Basically, it pops up in the middle of the main page. Looking at the HTML of the site, I can see that the login type seems to be a new HTML window
<!DOCTYPE html>
<html>event
....
<\html>
I'm not sure if this is the issue, and if so, how to fix it? Also, is there other reasons that might've caused the issue?
The popup will have an ID. You might have to add f'#{popup_id}' to the end of response.url. Like this URL: https://stackoverflow.com/questions/62906380/nosuchelementexception-when-using-selenium-python/62906409#62906409. It contains #62906409 because 62906409 is the ID of an element in the page.
The login page inside a frame, you need switch it first:
#switch it first
self.driver.switch_to.frame(driver.find_element_by_id('J_loginIframe'))
self.driver.find_element_by_id('fm-login-id').send_keys('iamgooglepenn')
self.driver.find_element_by_id('fm-login-password').send_keys('HelloWorld1_')
And for login button you can't use .find_element_by_class_name, this method just for single class name. This element having multiple class name, so use .find_element_by_css_selector like bellow:
#submit button
self.driver.find_element_by_css_selector('.fm-button.fm-submit.password-login').click()
The login content seems to be nested in an iFrame element (if you trace it all the way to the top, you should find an iFrame with id="sufei-dialog-content"), which means you need to switch to that iFrame for that nested html before selecting your desired element, otherwise it will not work.
First you will need to use driver.switch_to.frame("sufei-dialog-content"), and then select your element with driver.find_element_by_name() or whatever you had.
A similar issue can be found here: Selenium and iframe in html
Just a simple mistake:
<div class='input-plain-wrap input-wrap-loginid'>
<input id='fm-login-id class='fm-text' name='fm-login-id'...>
event
</div>
is actually supposed to be:
<div class='input-plain-wrap input-wrap-loginid'>
<input id='fm-login-id' class='fm-text' name='fm-login-id'...>
event
</div>
You forgot a single-quote.
Have you tried driver.find_element_by_name('fm-login-id')?
You should try finding the elements by their XPaths. You just have to inspect the element, right-click on it and copy its XPath. The XPath of the first <input ... is //*[#id="fm-login-id"].

Having a hard time clicking on a radio button that activates a drop down. Using Selenium and Python

SO normally I don't have a hard time with radio buttons but I was trying to configure the web browsers set home page to custom URL from the chrome settings. I knew I would have to activate the drop down box that lets me (picture provided). I located what I think is the source and had to navigate my way through some shadow DOM's. however after getting to the path I tried to click on it I get the error
selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element is not clickable at point (311, 1418)
I'm confused and I've been fighting this off for a while. Any one have any idea? I did notice some of the settings change when I personally click on the different options. here are the pictures
Heres my code:
from selenium import webdriver
from selenium.webdriver.support.ui import Select
def expand_shadow_element(element):
shadow_root = cdriver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
#chrom driver
cdriver = webdriver.Chrome(executable_path='C:\\Users\\name\Downloads\\chromedriver.exe')
#open up page to chrome settings.
cdriver.get('chrome://settings/')
root1 = cdriver.find_element_by_tag_name('settings-ui')
shadow_root1 = expand_shadow_element(root1)
root2 = shadow_root1.find_element_by_id('main')
shadow_root2 = expand_shadow_element(root2)
root3 = shadow_root2.find_element_by_tag_name('settings-basic-page')
shadow_root3 = expand_shadow_element(root3)
root4 = shadow_root3.find_element_by_tag_name('settings-on-startup-page')
shadow_root4 = expand_shadow_element(root4)
root5 = shadow_root4.find_element_by_name('4')
shadow_root5 = expand_shadow_element(root5)
root6 = shadow_root5.find_element_by_id('button')
root6.click()
anyone have any idea why I cant click on the source? i even right clicked on the radio button and thats the source I was pointed to.
To work around the element click intercepted error, you can try a Javascript click and see if that works for you.
The DOM tree is a bit hard to follow, but I think I catch the drift here -- a radio setting is under controlled-radio-button element, and the little circle itself is <div class='disc'>, as highlighted in your code sample.
I didn't see a shadow root under <div id="button"> that you store in root6 -- I see the element, but not a shadow root, so I am assuming the radio button itself actually lives under root5.
With that being said, here's some code to click on a radio button (given its description) using Javascript:
# grab the radio element... tricky with shadow roots
radio_button = root5.find_element_by_xpath("//div[#id='button']/div[#class='disc']")
# attempt to click it using JS -- ignores ClickIntercepted error
driver.execute_script("arguments[0].click();", radio_button)
Because you have already located the correct radio group and stored the shadow elements in root5 variable, you can try to use find_element_by_xpath on root5 to grab the <div class="disc"> element that appears right under it. The Javascript click should hopefully work around the ClickIntercepted error.

Python selenium: Unable to locate the element (//input[#type='file']')

I am trying to upload a file using python automation.
While I try to execute the code below python selenium throws an error.
Even I tried waiting for 10 seconds to avoid synchronisation issues.
driver.execute_script('window.open("https://ocr.space/" , "new window")')
Imagepath = r"C:\User\Desktop\banner.png"
field=driver.find_element_by_xpath('//input[#type="file"]')
field.send_keys(Imagepath)
NoSuchElementException: Message: no such element: Unable to locate
element: {"method":"xpath","selector":"//input[#type="file"]"}
Website url:
https://ocr.space/
HTML snippet:
<div class="span8">
<input type="file" id="imageFile" class="form-control choose valid">
</div>
Changing the code to launch the url with get seems to solve the issue.
from selenium import webdriver
driver = webdriver.Chrome("./chromedriver")
driver.get("https://ocr.space/")
image = r"C:\Users\Thanthu Nair\Desktop\soc360.png"
field=driver.find_element_by_xpath('//input[#type="file"]')
field.send_keys(image)
Also make sure the path provided C:\User\Desktop\banner.png is correct, otherwise you'll get another exception. It is just my assumption that this path might be wrong because usually Desktop folder is inside folder with user's name which is inside the User folder. In this case you've Desktop folder is inside User folder according to the path you've give.
To solve your problem, simply replace new window with _self in the below line of your code :
driver.execute_script('window.open("https://ocr.space/" , "_self")')
Your code is working fine but the reason for an error is, after running your code it launches browser with two tabs nothing but windows and the page will be launched in the second window so you need to switch to that window before uploading an image.
You can use window handles for switching to that window. Below is the code in Java, you can try doing same using Python :
// Using JavaScriptExecutor to launch the browser
JavascriptExecutor jse = (JavascriptExecutor) driver;
jse.executeScript("window.open(\"https://ocr.space/\" , \"new window\")");
// Fetching window handles and switching to the last window
Set<String> handles = driver.getWindowHandles();
for(String handle : handles) {
driver.switchTo().window(handle);
}
// Printing window title
System.out.println(driver.getTitle());
// Uploading an image
WebElement field = driver.findElement(By.xpath("//input[#type='file']"));
String imagePath = "some image";
field.sendKeys(imagePath);
If you use window.open() to launch an URL then it will do two things, first it will launch browser with default window then it will open URL in new tab even if you don't provide new window argument in your JavaScript function. You need to switch to a particular window to perform any operations on it if you choose this way.
To avoid an above problem, simply you can use driver.get(URL) or driver.navigate().to(URL) which launches the browser and navigates to a particular URL in the same launched browser window.
If you want to use JavaScriptExecutor only without doing switching, you can pass _self as a second argument to the JavaScript function like below instead of new window which avoids switching and launches an URL in the same window :
JavascriptExecutor jse = (JavascriptExecutor) driver;
jse.executeScript("window.open(\"https://ocr.space/\" , \"_self\")");
System.out.println(driver.getTitle());
WebElement field = driver.findElement(By.xpath("//input[#type='file']"));
String imagePath = "some image";
field.sendKeys(imagePath);
I hope it helps...
Generally, when the file upload related <input> tag contains the attribute type as file you can invoke send_keys() to populate the relevant text field with a character sequence. However, in your usecase the <input> tag though having type="file" but the class attributes are form-control choose which is as follows:
<input type="file" id="imageFile" class="form-control choose">
So, you may not able to able to send a character sequence invoking send_keys().
In these cases you need to use Auto IT based solutions. You can find a couple of relevant discussion in:
How to upload a file in Selenium with no text box

Selenium Hover/Click event on ajax filled menu options

Having serious issues here. Someone please help.
I am trying to login to a website. - This Works!
Redirect to the page I want after Login - This Works!
Now once in, I have to hover over the settings icon so the dropdown shows, and then click on the "Settings" options that has NO ID or CLASS or HREF.
Now there is a couple of reasons I cant do this. Number 1 is if I try to click on the link after the hover, it tells me that it's hidden and I cant interact with it. Also the menu options in the form are populated and appended once you hover, through ajax I think. They are not on the initial page load.
wait = WebDriverWait(driver, 10)
box = wait.until(EC.visibility_of_element_located((By.ID, "yucs-help_button")))
menuButton = driver.find_element_by_id("yucs-help_button")
ActionChains(driver).move_to_element(menuButton).perform()
After the above code is deployed I print the driver.page_source and can see (below) that the new menu options are there, if you don't hover, the below code will not be on the page.
Now the <a> i'm trying to click is the <span>Settings</span> option, and for the life of me, it will not work. Either can't find it, not clickable, can't interact with it, etc, etc, etc. xpath, css_selector, partial_name, nothing finds this thing. Also whats weird is once you click on it, from a browser, it appends an ID to <span> So weird. Any ideas?
<a data-ylk="rspns:nav;t3:tl-lst;t5:custitm;slk:custitm;elm:itm;elmt:custitm;itc:0;cpos:2" class="C(#000)! Td(u):h " data-mad="options" data-customevt="true" href="#" data-rapid_p="18"><span>Settings</span></a>
To perform mouse over event on element you should try to use .execute_script() using following java script :-
wait = WebDriverWait(driver, 10)
box = wait.until(EC.visibility_of_element_located((By.ID, "yucs-help_button")))
menuButton = driver.find_element_by_id("yucs-help_button")
driver.execute_script("var clickEvent = document.createEvent('MouseEvents');clickEvent.initEvent('mouseover', true, true); arguments[0].dispatchEvent(clickEvent);", menuButton)
Now after successfully mouse over you should try to click on Settings link as below :-
driver.find_element_by_xpath("//span[contains(text(), 'Settings')]/parent::a[#data-mad = 'options']").click()
Hope it will help you..:)

How to select pop up message "Allow" which is Span element of HTML page. Solution is expected by using find_element_by_css_selector

I am very new to Web UI automation, my queries might be very basic.
My UI automation requirement,I have to click on 'Allow' Pop up message. Could you please help me that How I can do this will work, I have given following try, However, unfortunately, these try did not work.
Following things could not worked. :
driver.find_element_by_css_selector('p.instructions.ALLOW').click();
##
#driver.find_element_by_css_selector('p.instructions').click()
document = 'ALLOW'
#driver.find_element_by_xpath("//*[normalize-space()='"+document+"']").click();
#driver.findElement_by_xpath("//span[contains(., \"" + document + "\")]").click();
#driver.find_element_by_xpath("//p[contains(text(),'ALLOW')]/span").click(); ##2
#driver.find_element_by_xpath("//span[contains(text(),'ALLOW')]").click(); ##2
#driver.find_element_by_xpath("//span[contains(text(),'ALLOW')]").click()
#driver.find_element_by_xpath("//span[contains(text(),'Allow')]").click()
#//a[contains(text(), 'Created By Me')]/span
#section.hidden.MouseAllowCameraView
#content = driver.find_element_by_css_selector('section.MouseAllowCameraView').click()
=========HTML Code ===========
<section class="MouseAllowCameraView hidden"><div class="background"></div>
<div class="page">
<div class="content">
<p class="instructions"><bdo dir="ltr">Activate your webcam by clicking <span>**ALLOW**</span><br>at the top of your browser window.</bdo></p>
</div>
<div class="webcam-arrow"></div>
</div>
</section>
===================End HTML Code
After checking the site, your question became more clear to me and its answer too.
Your Site has to be open only in Google Chrome, Once we click on Start Button it pops-up a browser pop-up which request a user to click on 'Allow' to proceed further,
Now here is the actual problem.
Selenium so far is not capable of automating the controls of the Browsers(Favorite bar, Address bar,Menu options) and the window which we get on clicking on 'Start'button is a part of the controls of our chrome browser.
To handle this situation you can use Some third part tools like Sikuli,AutoIT or ROBOT.
I'll suggest to go with Sikuli, with the help of this you will be able to click on Allow button.
Here is the complete Sikuli Link1 and Link2 tutorial.
Please let me know if any questions.

Categories