Can't click element by xpath inside iFrame - Selenium - python

I'm aware that I have to switch to an iframe when I want to click and element inside it. Heres what the start of the iFrame looks like:
<iframe src="about:blank" name="tool_content" id="tool_content" class="tool_launch" allowfullscreen="allowfullscreen" webkitallowfullscreen="true" mozallowfullscreen="true" tabindex="0" title="Tool Content" style="height: 100%; width: 100%;" allow="geolocation *; microphone *; camera *; midi *; encrypted-media *; autoplay *" data-lti-launch="true"></iframe>
I switched to it using driver.switch_to.frame(driver.find_element_by_class_name("tool_launch"))
I then tried clicking a 'Join' button inside the Iframe by using it's exact xpath:
driver.find_element_by_xpath("/html/body/div[1]/div/div/div[2]/div/div/div[3]/div[1]/div[2]/div/div/div/div/div/div/div/div/div/div/table/tbody/tr/td[4]/div/div[1]/a").click()
But it keeps saying it's not present. Why? There are no further iframes inside that one, and this xpath is completely 100% inside the iframe. It can recognise other elements, so why not this one?
Here's the join button element line:
<a target="_blank" href="/lti/rich/j/96494344321?oauth_consumer_key=AAPUZMZcQCSN85nnG74vOQ&lti_scid=ee49a632bee823b3046456c29c5eb4064ee1e3790f433af82bebaf2752bde531" class="ant-btn ant-table-span" style=""> Join</a>
Heres what the iframe looks like - I want to click the join button:
It's inside a table.
I'm able to select things like the 'previous meetings' tab, but cannot use the Join or invitation buttons.
Here is the full HTML
I cannot paste it because this can only be viewed in inspect element (when viewing the source, you can't see all this), and I would only be able to copy one element at a time.
I have highlighted at the top where the start of the iframe is, and where the Join button that I want to click is.
The two images just continue on from one another.
Edit #1
I tried using the css selector - same result.

Try waiting and clicking on the element. Try not to use xpath.
elem=WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.ant-btn.ant-table-span")))
elem.click()
Import
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

Related

Selenium doesn't find element loaded from Ajax

I have been trying to get access to the 4 images on this page: https://altkirch-alsace.fr/serviable/demarches-en-ligne/prendre-un-rdv-cni/
However the grey region seems to be Ajax-loaded (according to its class name). I want to get the element <div id="prestations"> inside of it but can't access it, nor any other element within the grey area.
I have tried to follow several answers to similar questions, but no matter how long I wait I get an error that the element is not found ; the element is here when I click "Inspect element" but I don't see it when I click "View source". Does that mean I can't access it through selenium?
Here is my code:
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
driver.get("https://altkirch-alsace.fr/serviable/demarches-en-ligne/prendre-un-rdv-cni/")
element = WebDriverWait(driver, 10) \
.until(lambda x: x.find_element(By.ID, "prestations"))
print(element)
You're not using WebDriverWait(...).until properly. Your lambda is using find_element, which throws exception when it is called and the element is not found.
You should use it like this instead:
from selenium.webdriver.support import expected_conditions as EC
...
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "prestations"))
)
Got the same problem. There is no issue with waiting. There is a frame on that webpage:
<iframe src="https://www.rdv360.com/mairie-d-altkirch?ajx_md=1" width="100%"
height="600" style="border:0px;"></iframe>
The Document Object Model - DOM of the main website does not contain any informations about the webpage that is loaded into a frame.
Even waiting hours you will not find any elements inside this frame, as it has its own DOM.
You need to switch the WebDriver context to this frame. Than you may access the frame's DOM:
As on your website the iframe has no id, you may search for all frames like described on the selenium webpage (https://www.selenium.dev/documentation/webdriver/browser/frames/):
The code searches for all HTML-tags of type "iframe" and takes the first (maybe it should be [0] not [1])
iframe = driver.find_elements(By.TAG_NAME,'iframe')[1]
driver.switch_to.frame(iframe)
Now you may find your desired elements.
The solution that worked in my case on a webpage like this:
<html>
...
<iframe ... id="myframe1">
...
<\iframe>
<iframe ... id="myframe2">
...
<\iframe>
...
</html>
my_iframe = my_WebDriver.find_element(By.ID, 'myframe_1')
my_Webdriver.swith_to.frame(my_iframe)
also working:
my_WebDriver.switch_to.frame('myframe_1')
According Selenium docs you may use iframe's name, id or the element itself to switch to that frame.

Change style with selenium python

On this website I try to set some filters to collect data but I can't access to the table using a click event with selenium in my python script.
I noticed that I need to change the style from :
div id="filtersWrapper" class="displayNone " style="display: none;"
to
div id="filtersWrapper" class="displayNone " style="display: block;"
I think that I should use driver.execute_script(), but I have no clue how to do it
I would greatly appreciate some help with this. Thank you!
You can change an attribute on an element using javascript through selenium
element = driver.find_element_by_id('filtersWrapper')
driver.execute_script("arguments[0].setAttribute('attributeToChange', 'new value')", element)
or you can try clicking the element with javascript
driver.execute_script("arguments[0].click();", element)
I have checked the DOM Tree of the webpage. Somehow I was unable to locate any element as:
<div id="filtersWrapper" class="displayNone " style="display: none;">
However the following element exists:
<div id="filtersWrapper" class="displayNone ">
<div id="filtersArrowIndicator" class="arrowIndicator"></div>
.
<div id="economicCalendarSearchPopupResults" class="eventSearchPopupResults economicCalendarSearchPopupResults text_align_lang_base_1 dirSearchResults calendarFilterSearchResults displayNone">
</div>
</div>
Not sure if that was your desired element. A bit of more information about your usecase would have helped us to debug the issue in a better way. However, To set the display property of style attribute as block for the element you can use:
driver.execute_script("document.getElementById('filtersWrapper').style.display='block';");
You can use driver.execute_script() to accomplish this. This is how I change the style attribute in my own code:
div_to_change = driver.find_element_by_id("filtersWrapper")
driver.execute_script("arguments[0].style.display = 'block';", div_to_change)
I had a look at the website you are automating, and you might not need to use JSE at all to do this - there's a reason the div you are trying to click has style = "display: none" - it is not meant to be clicked in this context. Working around that with Javascript might not produce your intended results. This code snippet has been updated with your requirements to set a Time filter in the Economic Calendar section:
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.get("https://www.investing.com/economic-calendar/")
driver.find_element_by_id("economicCurrentTime").click()
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "filterStateAnchor"))).click()
checkbox_for_bull3 = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//*[#id='importance2']")))
driver.execute_script("arguments[0].scrollIntoView(true);", checkbox_for_bull3)
checkbox_for_bull3.click()
checkbox_for_time = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//fieldset[label[#for='timeFiltertimeOnly']]/input")))
checkbox_for_time.click()
I modified your code snippet to fix a few issues -- when navigating to the economic-calendar page, you were clicking the 'Filters' field twice which caused an issue trying to click checkbox_for_bull3. I also added a scrollIntoView() Javascript call.
I ran this on my local machine and the code executed end to end successfully.

How to click on the angular based checkbox as per the HTML provided through Selenium and Python?

I am trying to click on a checkbox using selenium python. I tried
buttons = driver.find_element_by_xpath("//*[contains(text(), 'Exact')]"); buttons.click()
I keep getting
"ElementNotVisibleException:"
<button type="button" data-ng-class="{iconCheck: event.locationExactness.isExact, inputBox:!event.locationExactness.isExact}" class="link icon locationButton inputBox" data-sfs-callout-visible="relativeExactnesses.length > 1" data-sfs-callout="sfs_-sfsLocationExactness-1-place-callout" data-sfs-callout-focus="sfs_-sfsLocationExactness-1-exact" data-ng-click="updateIsExact(relativeExactnesses.length > 1 ? true : !event.locationExactness.isExact)" data-autoname="NameAPlace_msypn_LocationExactButton"><!--
--><span class="locationLabel ng-binding">Exact</span><!--
--></button>
<<pseudo:before>></<pseudo:before>>
<!--
-->
<span class="locationLabel ng-binding">Exact</span>
<!--
-->
First of all you are locating one element, but are giving it plural name buttons. I would use singular name button.
Second thing is even in your code snippet there is two span which contain Exact. You have to change your locator so, that only one element(which you want to interact with) will be selected via selector.
For example, if you want the first Exact in your code snippet, you can use this xPath:
//button[#data-sfs-callout = 'sfs_-sfsLocationExactness-1-place-callout']/span
Note: as #RajKamal already mentioned, there can be multiple elements on the page with text Exact. You can check this in dev tools by pressing F12.
As per the HTML you have shared the element with text as Exact is a Angular element so to invoke click() on the desired element you have to induce WebDriverWait for the element to be clickable and you can use the following solution:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[#class='link icon locationButton inputBox' and #data-autoname='NameAPlace_msypn_LocationExactButton']//span[#class='locationLabel ng-binding'][contains(.,'Exact')]"))).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

Python Selenium: Getting dynamic content within iframe

I am trying to scrape the available apartment listings from the following webpage: https://3160599v2.onlineleasing.realpage.com/
I am using the Python implementation of Selenium, but so far I haven't found an effective solution to programmatically get the content. My most basic code is the following, which currently just returns the non-dynamic HTML source code:
from selenium import webdriver
driver = webdriver.Chrome('/path_to_driver')
driver.get('https://3160599v2.onlineleasing.realpage.com/')
html = driver.page_source
The returned html variable does not contain the apartment listings I need.
If I 'Inspect' the element using Chrome's built-in inspect tool, I can see that the content is within an un-classed iframe: <iframe frameborder="0" realpage-oll-widget="RealPage-OLL-Widget" style="width: 940px; border: none; overflow: hidden; height: 2251px;"></iframe>
Several children down within this iframe you can also see the div <div class="main-content"> which contains all the info I need.
Other solutions I have tried include implementing an explicit WebDriverWait:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.CLASS_NAME, 'main-content')))
I get a TimeoutException with this method as the element is never found.
I also tried using the driver.switch_to.frame() method, with no success.
The only steps that have actually allowed me to get the apartment listings out of the webpage have been (using Chrome):
Manually right-click on an element of the listings within the webpage
Click Inspect
Find the div 'main-content'
Manually right-click on this div and select Copy -> Copy Element
This is not an effective solution since I'm seeking to automate this process.
How can I get this dynamically generated content out of the webpage in a programatic way?
Try to use below code to switch to iframe:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait as wait
wait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it(driver.find_element_by_xpath('//iframe[#realpage-oll-widget="RealPage-OLL-Widget"]')))
Also note that method that allows to switch to static iframe is switch_to.frame(), but not switch-to.frame()
You can not directly see the content which is in the iframe. You need to change frame. You can do this by firstly selecting 'iframe element' and then switching to it with driver.switch_to.frame() function.
iframe = driver.get_element_by_id('iframe')
driver.switch_to.frame(iframe)
After that you can access the iframe's content.
Alternatively, you can take the source attribute of iframe then going to that page with selenium. In the end, iframe content is another html page.

Selenium Web-driver Click Button

[Python 2.7, Selenium Web-driver]
So there's this Website:
<div class="flex-module-header">
<h3><span class="trend-location js-trend-location">Greece Trends</span></h3>
<span class="middot">ยท</span> <a role="button" href="#" data-modal="change-trends" class="change-trends js-trend-toggle">Change</a>
And I want to click the button:
<a role="button" href="#" data-modal="change-trends" class="change-trends js-trend-toggle">Change</a>
And I've tried everything (trying to locate by xpath, class etc.), and I can't seem to be able to do what I'm looking for.
I basically want to click the button, that's all.
As you didn't provide error stack trace and tried code, Assuming you didn't use WebDriverWait yet to wait until element visible and clickable. So I'm giving the example with this as below :-
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
link = wait.until(EC.element_to_be_clickable((By.LINK_TEXT, "Change")))
link.click()
Note :- Before using this, make sure element is not present inside a frame or iframe. If element is present inside a frame or iframe you need to switch that frame before finding the button as driver.switch_to_frame("frame name or id").
Hope it helps...:)

Categories

Resources