Unable to find element within a form using Selenium and Python3 - python-3.x

I am unable to input text into the Booking Number textbox in: https://www.hmm21.com/cms/business/hongkong/export/vgmWithoutLogin/index.jsp
This is the html of the textbox using inspect on chrome:
<input style="width:200px;text-transform:uppercase;ime-mode:disabled;" type="text" maxlength="12" name="bookingNumber" value="">
This is the code I am using for now:
element = WebDriverWait(self.driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[#name='bookingNumber']"))).send_keys('test')
I tried many other methods as well, like selecting using CSS Selector, absolute xpath, but I just cannot seem to be typing anything into the textbox.
I also tested the xpaths and CSS Selectors using ChroPath, a few other chrome extensions, xPath Finder on Firefox as well, and they all seemed to be working.
Would appreciate if anyone could help. Thanks.

To send a character sequence to the element associated with the text Booking Number 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 solution:
Using CSS_SELECTOR:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe#_frame1[src='/ebiz/ebooking/vgm/indexWithoutlogin.jsp']")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[name='bookingNumber']"))).send_keys('Rong Heng')
Using XPATH:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[#id='_frame1' and #src='/ebiz/ebooking/vgm/indexWithoutlogin.jsp']")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[#name='bookingNumber']"))).send_keys('Rong Heng')
Here you can find a relevant discussion on Ways to deal with #document under iframe

Try clicking the element before sending keys, You can also excute a JavaScript to modify it's value.
.click()
Also If the input is displayed through JavaScript wait for the element to be present and not clickable.
.presence_of_element_located()

You should switch the iframe first, use
WebDriverWait(self.driver, 10).until(EC.frame_to_be_available_and_switch_to_it(self.driver.find_element_by_id('_frame1')))
Because the Booking Number textbox input element is in a new iframe named '_frame1'.
Hope it will help you.

This element is inside iframe as ChroPath suggested. So first you will have to switch to iframe and perform the action. Sometime if sendKeys doesn't work on input box then try clear/click() method before sending keys in box.

Related

How to find elements in containers that open when buttons are pressed

I am using headless Firefox on Selenium and XPath Helper to identify insanely long paths to elements.
When the page initially loads, I can use XPath Helper to find the xpath of any element of interest, and selenium can find the element when given the xpath.
However, several buttons that I need to interact with on the page open menus when pressed that are either small or take up the whole "screen". No matter their size, these containers are overlaid on the original page, and although I can find their xpaths using XPath Helper, when I try to use those xpaths to find the elements using selenium, they can't be found.
I've checked, and there's no iframe funny business happening. I'm a bit stumped as to what could be happening. My guess is that the page's source code is being dynamically changed after I press the buttons that open the menu containers and when I call find_element_by_xpath on new elements in the containers, the original source is being searched, instead of the new source. Could that be it?
Any other ideas?
As a workaround, I can get around this issue by sending keystrokes to the body of the page, but I feel this solution is rather brittle and likely to fail. Would be a much more robust solution to actually specify all elements.
EDIT:
With selenium I can find the export button, but not the menu it opens.
Here is the code for the export button itself:
The element of interest for me is "Customize Export" which I have not been able to find using selenium. Here is the code for this element:
Notice the very top line of this last image (cdk-overlay-container)
Now, when I refresh the page and do NOT click the export button, the cdk-overlay-container section of the code is empty:
This suggests my that my hypothesis is correct -- that when the page loads initially, the "Customize Export" button is nowhere in the source code, but appears only after "Export" is clicked, and that selenium is using the original source code only --not the dynamically generated code that appears after clicking "Export" -- to find elements
Selenium could find the dynamic content after doing
driver.execute_script("return document.body.innerHTML")
The WebDriverWait is what you need to use to wait for a certain condition of elements. Here is an example of waiting for the elements to be clickable before the click with a timeout in 5 seconds:
wait = WebDriverWait(driver, 5)
button = wait.until(EC.element_to_be_clickable((By.XPATH, 'button xpath')))
button.click()
wait.until(EC.element_to_be_clickable((By.XPATH, 'menu xpath'))).click()
identify insanely long paths
is an anti pattern. You can try to not use XPath Helper and find xpath or selector yourself.
Update:
wait = WebDriverWait(driver, 10)
export_buttons = wait.until(EC. presence_of_all_elements_located((By.XPATH, '//button[contains(#class, "mat-menu-trigger") and contains(.="Export")]')))
print("Export button count: ", len(export_buttons))
export_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//button[contains(#class, "mat-menu-trigger") and contains(.="Export")]')))
export_button.click()
cus_export_buttons = wait.until(EC. presence_of_all_elements_located((By.XPATH, '//button[contains(#class, "mat-menu-item") and contains(.="Customize Export")]')))
print("Customize Export button count: ", len(cus_export_buttons))

Python Selenium: how to switch frames after navigation?

I'm trying to download a link within a table after navigating to a page using Python3 + selenium. After using selenium to click through links, and inspecting the elements on the latest-loaded page, I can see that my element is within a frame called "contents". When I try to access this frame, however, upon calling:
DRIVER.switch_to_frame("contents")
I get the following error:
selenium.common.exceptions.NoSuchFrameException: Message: contents
To gain more context I applied an experiment. Both the page that I loaded using DRIVER.get(URL) and the one to which I navigated had a frame called "menu".
I could call DRIVER.switch_to_frame("menu") on the first page, but not on the second.
DRIVER = webdriver.Chrome(CHROME_DRIVER)
DRIVER.get(SITE_URL)
DRIVER.switch_to_frame("contents") # This works
target_element = DRIVER.find_element_by_name(LINK)
target_element.click()
time.sleep(5)
DRIVER.switch_to_frame("menu")
target_element = DRIVER.find_element_by_name(LINK2)
target_element.click()
target_element = DRIVER.find_element_by_name(LINK3)
target_element.click()
DRIVER.switch_to_frame("contents") # Code breaks here.
target_element = DRIVER.find_element_by_xpath(REF)
target_element.click()
print("Program complete.")
I expect the code to find the xpath reference for the link in the "contents" frame. Instead, when attempt to switch to the "contents" frame, python run-time errors and cannot find "contents".
selenium.common.exceptions.NoSuchFrameException: Message: contents
this is because you are staying in child level of iframe which is 'menu' so inside that it can't able to find the iframe 'contents'.
First Switch back to the parent frame which is "contents", by using
DRIVER.switch_to.default_content()
and then try to go to the 'contents' iframe and perform actions, Now it should work.
Since contents appears to be a top level frame try going back to the top before selecting the frame:
DRIVER.switch_to.default_content()
DRIVER.switch_to.frame("contents")
As a thumb rule whenever switching frames you need to induce WebDriverWait for frame_to_be_available_and_switch_to_it() and you need 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 solution:
target_element.click()
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"frame_xpath")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "REF"))).click()
You can find a detailed discussion on frame switching in How can I select a html element no matter what frame it is in in selenium?
Here you can find a relevant discussion on Ways to deal with #document under iframe

Selenium : Unable to locate element

So I'm trying to identify this button to press it, but I get the exception:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element
The image below shows the button:
The weird thing, is that I already did identify the login button in the login page, but after I got to the following page, it's like identifying an element isn't possible anymore, could that be because the page doesn't allow for that?
#This one works
driver.find_element_by_class_name("urBtnStdNew").click()
#This one give the exception
driver.find_element_by_id("sapbi_snippet_TABSTRIP_CONTAINER_ITEM_1").click()
#This is the HTML of that element
<span class="urTbsTxtOff">DPD Trend</span></td>
Edit: Thank you guys, I didn't know about iframe's existence, so switching it solved my problem.
iframe = driver.find_element_by_xpath("//iframe[#name='iframe_Roundtrip_9223342']")
driver.switch_to.frame(iframe)
Use WebDriverWait and following xpath to click on the DPD Trend tab.
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
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//td[#class='urTbsLabelOff urBorderBox']/span[#class='urTbsTxtOff'][contains(.,'DPD Trend')]"))).click()
Hamza,
WebDriverWait will not work. As you have stated you have tried using Thread.sleep() and WebDriver still cannot locate the element.
The issue looks to me like it is down to an incorrect element locator being used.
If the button in your screenshot is the one in the red box, and the code in the red box in the element inspector relates to it, then it looks to me like the ID should be TABSTRIP_CONTAINER_ITEM_1_tabStrip_tabstrip-itm-5.
So based on your example above the following code should locate the DPD Trend button and click it:
driver.find_element_by_id("TABSTRIP_CONTAINER_ITEM_1_tabStrip_tabstrip-itm-5").click()
The correct XPath locator would be as simple as:
//span[text()='DPD Trend']
If you will still not be able to locate the element:
double check that it is not in an iframe, if it is - you will need to switch to it prior to finding
double check that it is not hidden in the shadow DOM, if it is - you will need to locate ShadowRoot via execute_script function and cast the result to a WebElement
a good practice is using WebDriverWait for locating the elements as it might be the case they're not immediately available in DOM, check out How to use Selenium to test web applications using AJAX technology article for more details.

Cannot find element within iframe using Selenium

I'm trying to locate elements within the iframe but got no luck.
I think because of my code cannot switch to the iframe and that's why I couldn't locate the elements within it.
Below is my code.
I have tried
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, '/html/body/iframe')))
driver.find_element_by_name('applicant.name').send_keys('email')
I also tried this
iframe = driver.find_element_by_xpath('/html/body/iframe')
driver.switch_to.frame(iframe)
driver.implicitly_wait(10)
driver.find_element_by_name('applicant.name').send_keys('email')
I tried look for xpath, id of the applicant.name but notthing work so far. Any help or suggestions would be appreciated.
Here the site:
https://www.indeed.com/cmp/Paratus-Partners-LLC/jobs/Full-Stack-Developer-7814e52be25090f3?from=iaBackPress&q=software%20developer&vjs=3
There are at least 2 iframes in the page you're trying to automate:
Therefore you need to
Amend your XPath Expression to uniquely identify first iframe like:
parentIframe = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH,"//iframe[contains(#id,'modal-iframe')]")))
Switch to first iframe
driver.switch_to.frame(parentIframe)
Locate second iframe and switch to it
childIframe = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH,"//iframe[contains(#src,'resumeapply')]")))
driver.switch_to.frame(childIframe)
Once done you should be able to send text into the input fields.
There are some elements with the xpath /html/body/iframe
I was looking for the applicant.name and it was only to create after click on the postulate button.
I think that you have to check the xpath for the iframe, maybe something like this can work
"//iframe[contains(#src,'resumeapply')]"

Python Selenium Webdriver: No Such Element or Element not Visible or InvalidSelectorException

I am trying to access an button in browser with the Name export via selenium web driver. I have tried with the xpath
driver.find_element_by_xpath("//div[#class='tb-btn']//[contains(text(), 'Export')]").click() for this i get the error InvalidSelectorException.
when i tried driver.find_element_by_xpath("*//[contains(text(), 'Export')]").click() for this i get the error Element Not Visible.
When i tried driver.find_element_by_xpath("*//[#id="master_btnExport"]").click() i get No such Element.
This is the image of the url when inspect the element
Not sure why i get these errors. Any inputs would be really helpful.
Regards,
Ren.
Try either of following two Xpath.It should work.
driver.find_element_by_xpath("//a[#id='master_btnExport']")
Or
driver.find_element_by_xpath("//a[#class='tb-btn-0link-left']")
If you want to give some time to load for element to be available try that.
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[#id='master_btnExport']")))
OR
WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//a[#id='master_btnExport']")))
Hope this helps
This error occurs when you either give a wrong path to an element or your script runs before actually letting that element load

Resources