Can't find element on page no matter what I try - python-3.x

I am striking out on locating an element on a search results page. I have tried locating by xpath, wait_for_element_to_be_clickable, find_element_by_link_text etc. and still can't get selenium to locate it.
If I have the driver reload the initial URL for the search page the same search results show up and not the initial search page. I've tried nuking cookies etc. This behavior exists on chrome and firefox.
Initial URL: https://elibrary.ferc.gov/eLibrary/search
just hitting the search button yields results. However I can't locate the link "General Search" at the top of the page with selenium to go back and enter new search criteria. The link is the same as the initial URL. My code to select the link and click:
try:
self.driver.find_element_by_xpath('//*[#id="srchResult"]/nav/div/ul/li[1]/a[1]').click
except:
_LOGGER.warning('Could Not Click on General Search - starting new driver')
self.driver = webdriver.Firefox(executable_path=r"/usr/local/bin/geckodriver", options=options)
Any help much appreciated.

XPath for that link is: //a[#aria-label='Return to General Search']

You can locate the element you are looking for with the following xpath:
//a[contains(#aria-label,'Return to General Search')]
or xss_selector: a[aria-label='Return to General Search']
Don't forget to put wait condition before clicking on it!

That link is
<a _ngcontent-c1="" aria-expanded="false" aria-label="Return to General Search" class="btn btn-link nav2" name="Refine" href="/eLibrary/search">General Search</a>
It has a name, which would be the preferred way to find it because it's least likely to change. The CSS selector below works.
a[name='Refine']

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))

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')]"

How to locate the element as per the HTML through FindElementByXPath in Selenium Basic

I'm writing a VBA code to login into a webpage and load some information i have in an excel worksheet.
I'm new in Selenium. I already got the login part right, but now i need to click in an element and i keep getting errors.
I need to click in the Company 2 button.
This is what i've got so far:
bot.FindElementByXPath("//input[#value=""Company 1""]").Click
Outputs NoSuchElementError
bot.FindElementByXPath("//input[#value=""Company 2""]").Click
Outputs ElementNotVisible
I don't know what i'm doing wrong, i think that the first input being hidden has something to do. Hope anyone can help me.
Might help you to know you can also use ByCss in most circumstances, in which case you can use:
bot.FindElementByCss("input[value='Company 1']").Click
That is nice and short.
The CSS selector is input[value='Company 1']. This says find element with input tag having attribute value with value of 'Company 1'.
XPath might be incorrect. Please try the following syntax:
FindElementByXPath("//input[#value='Company 1']")
First of all, use CSS selectors whenever possible. They are much easier to handle.
Now if you are using CSS selectors try to find the second button using something like
input[value="Company 2"]
For more info on this selector, look at https://www.w3schools.com/cssref/sel_attribute_value.asp
You can use any xpath, in first look I found your xpath is incorrect, try this:
//input[#type='button'][#value='Company 2']
//input[#type='button'&& #value='Company 2']
//input[#role='button'][#value='Company 2']
You can also use findelements() to store are all buttons and using if else you can extract the company 2 button
As per the HTML you have shared to invoke click() on the desired elements you can use the following solution:
To click on the element with text as Company 1:
bot.FindElementByXPath("//input[#class='btn_empresa ui-button ui-widget ui-state-default ui-corner-all' and #value='Company 1']").Click
To click on the element with text as Company 2:
bot.FindElementByXPath("//input[#class='btn_empresa ui-button ui-widget ui-state-default ui-corner-all' and #value='Company 2']").Click
Have you tried right-clicking the HTML in inspect and going to Copy>Copy XPath? That might give you something different. Maybe the buttons are created from Javascript and so the WebDriver can't actually see them?
Or try
Company_1 = bot.find_element_by_xpath("//input[#value='Company 1']")
Company_1.click()
Company_2 = bot.find_element_by_xpath("//input[#value='Company 2']")
Company_2.click()
And change the syntax with the ' ' quotes like someone else mentioned.

How do I interact with a dynamic id through python selenium?

I am trying to click on an icon in a web page. This is the element I am attempting to click:
<a class="Button ButtonIcon IconOnly DataSelector NormalState"
id="ze6402ef81ea54445aec5dab8790c781f" tabindex="0"><span class="Icon"></span>
<span class="Text"></span></a>
I have no problem interacting with the code below:
browser.find_element_by_css_selector('ze6402ef81ea54445aec5dab8790c781f').click()
The problem is that the id is dynamic with each session. I have attempted a workaround with the following code with no success:
browser.find_element_by_xpath("//a[span/#class='Text']").click()
and
browser.find_element_by_xpath("//a[span/#class='Icon']").click()
Afterwards, I noticed that the element needs to be in a hover state in order to be clicked. So next, I used ActionChains to try to simulate a hover state -- again, with no success:
actions=ActionChains(browser)
element=browser.find_element_by_css_selector("//a[span/#class='Icon']")
actions.move_to_element(element).click().perform()
Then, I tried to TAB to the element via send_keys and ActionChains -- but it ended up cycling rapidly through page, instead of one element at a time:
actions.send_keys(Keys.TAB)
I wanted to put in my due diligence before posting my issue. Any assistance is appreciated - Thank you.
As you mentioned, you don't have a problem with the following line of code:
browser.find_element_by_css_selector('ze6402ef81ea54445aec5dab8790c781f').click()
But the only issue here is that the id is dynamic, so we can use the class attribute to construct an unique cssSelector or an unique xpath as follows:
cssSelector :
driver.findElement(By.cssSelector("div.Button.ButtonIcon.IconOnly.DataSelector.NormalState"));
xpath :
driver.findElement(By.xpath("//div[#class='Button ButtonIcon IconOnly DataSelector NormalState']"));
Use these XPaths:
//span[#class='Text']
//span[#class='Icon']
Yours were formatted incorrectly.

How to click on link element with specific text using watir?

I'm not able to click on text link 'Add' using watir:
PAGE:
<div id="divAdd" style="float: right">
<a onclick="SwitchView('2')" style="color: #1B56A7; cursor: pointer;">Add</a>
</div>
Watir CODE:
browser.link(:text =>"Add").click
EXCEPTION:
Unable to locate element, using {:tag_name=>["a"], :text=>"Add"}
Please help me how to handle this?
If the page has a lot of ajax and javascript going on, you may just have to wait a little bit for the client side code to finish rendering the page after it has been loaded from the browser.
Try this
browser.link(:text =>"Add").when_present.click
If that does not work, then make sure the item is not in a frame or something..
btw, if there is more than one link on the page with the text 'Add' then you may have to specify a container outside the link that lets you identify which link you want. eg.
browser.div(id: => "divAdd").link.when_present.click
If
This would be my way of doing it.
while browser.div(:class, 'containerDIV').a(:text, 'Add').exists? do
browser.div(:class, 'containerDIV').a(:text, 'Add').click
end

Resources