Unable to click on element with link in selenium python - python

I am trying to interact with a sign out button but I just can't seem to click on it using link text or xpath.
I have tried following these answers with no luck:
Why Cant I Click an Element in Selenium?
Unable to click link using selenium webdriver in python
Here is my code:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from xatu.tests.base import login
from xatu.tests.bagon import BagonBaseTestCase
class BasicTestCase(BagonBaseTestCase):
#login
def test_logout(self):
self._wait_until_id_presents("quotes-form")
WebDriverWait(self, 10).until(
EC.presence_of_element_located((By.XPATH, "//a[#href='/login/clear']/i")))
self.browser.find_element_by_xpath("//a[#href='/login/clear']/i").click()
self.implicitly_wait(2)
self._title_check("Login")
The first line under test_logout calls a function that waits for a certain element to appear on the webpage so I can see that the page has been loaded. Then I try to click the sign out button.
This is the HTML(element is at class="btn" href="/login/clear"):
<div class="navbar navbar-fixed-top screen-only">
<div class="navbar-inner">
<div class="container-fluid">
<a class="btn btn-navbar" data-target=".nav-collapse" data-toggle="collapse">
<a class="brand" href="/">
<div class="nav-collapse collapse">
<ul class="nav">
<p class="pull-right" style="margin-top: 4px; margin-left: 4px;">
<a class="btn" href="/login/clear">
<i class="icon-off"/>
Sign out
</a>
</p>
<p class="navbar-text pull-right"> Logged-in as D. V. Lauper </p>
</div>
<!--/.nav-collapse -->
</div>
</div>
</div>
When I try finding by link_text, the element can't be found. Running this code gives me a stacktrace error saying:
ElementNotVisibleException: Message: Element is not currently visible and so may not be interacted with
Edit: I've tried Saifur's answer and updated my code to his answer but now I get: AttributeError: 'BasicTestCase' object has no attribute 'find_element'. I've tried changing "self" to "self.browser" as an argument in WebDriverWait() but I would then get my original error.

Use explicit wait and relativexpath
like //a[#href='/login/clear']/i
from xatu.tests.base import login
from xatu.tests.bagon import BagonBaseTestCase
class BasicTestCase(BagonBaseTestCase):
#login
def test_logout(self):
self._wait_until_id_presents("quotes-form")
WebDriverWait(self, 10).until(
EC.presence_of_element_located((By.XPATH, "//a[#href='/login/clear']/i")))
self.browser.find_element_by_xpath("//a[#href='/login/clear']/i").click()
self.browser.implicitly_wait(2)
self._title_check("Login")

You need an explicit wait. See docs. Example code:
element = WebDriverWait(driver, 30).until(EC.visibility_of_element_located((By.XPATH,'//a[#href="/login/clear"]')))
And then just click the element.
element.click()
Note I added my answer b/c -- in my tests at least -- you don't need to worry about the italics tag. That's for the text, not the button -- and you're not clicking the text. So find By.XPATH and select a unique attribute (i.e., the href in this case and very likley not the class attr), and then click your element.
EDIT:
please try this line:
element = WebDriverWait(self.browser, 30).until(EC.visibility_of_element_located((By.XPATH,'//a[#class="btn" and #href="/login/clear"]')))

Related

Selenium click button with <a> tag - intercepted exception

I am trying to click a button on a website in Python using Selenium. The html for the button I want looks like this:
<a onclick="exportGridExcel()"><span class="accordion-download"><i class="fa fa-file-excel-o" title="Download Excel" aria-hidden="true"></i></span></a>
A more expanded version of the html is:
<div class="lang-switch-wrapper lang-switch-inverse-wrapper">
<div class="lang-switch">
<ul>
<li class="dropdown">
<a href="#" class="dropdown-toggle lang-lable" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<span class=" hidden-xs">English</span>
<span class="hidden-lg hidden-md hidden-sm">EN</span>
<img src="/etc/designs/wbrrdesign/clientlibs-wbrredsign/img/angle-down-gray.svg" alt="dropdown"></a>
<ul class="dropdown-menu dropdown-item">
<li>Español</li>
</ul>
</li>
</ul>
</div>
</div>
Then some other stuff before going to the button group and button I want:
<div class="button-group">
<button onclick="onModifyQuery()" type="button" class="btn">Modify Query</button>
<a onclick="exportGridExcel()"><span class="accordion-download"><i class="fa fa-file-excel-o" title="Download Excel" aria-hidden="true"></i></span></a>
<a title="Undo to column removal" onclick="restoreColumn()" class="toggle-btn primary-light-blue-btn"><i class="fa fa-circle-o-notch" aria-hidden="true"></i></a>
</div>
Part of my confusion is inexperience with this html with multiple classes and "i class".
EDIT:
If I try something like:
WebDriverWait(driver,300).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a[onclick='exportGridExcel()']"))).click()
Then I get the error:
ElementClickInterceptedException: element click intercepted: Element <a onclick="exportGridExcel()">...</a> is not clickable at point (772, 11). Other element would receive the click: <div class="lang-switch-wrapper lang-switch-inverse-wrapper">...</div>
The problem is that your page is automatically scrolled up and the excel download button is probably hidden by the top banner that contains the language selector. When Selenium tries to click on the excel download button, it finds the language selector instead.
I would suggest you to scroll the page up till the whole data table is visible
You can use something like this. Press HOME key to go to top of the page
from selenium.webdriver.common.keys import Keys
...
...
element = WebDriverWait(driver,300).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a[onclick='exportGridExcel()']")))
element.send_keys(Keys.CONTROL + Keys.HOME)
element.click()
Ideally clicking on the element <a onclick="exportGridExcel()"> as per your code trials inducing WebDriverWait for the elementToBeClickable() should have worked.
However, there seems to be a decendant <span>. So you can use either of the following locator strategies:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a[onclick^='exportGridExcel'] > span.accordion-download"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[starts-with(#onclick, 'exportGridExcel')]/span[#class='accordion-download']"))).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
In another approach you can also use JavascriptExecutor as follows:
Using CSS_SELECTOR:
element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a[onclick^='exportGridExcel'] > span.accordion-download")))
driver.execute_script("arguments[0].click();", element)
Using XPATH:
element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[starts-with(#onclick, 'exportGridExcel')]/span[#class='accordion-download']")))
driver.execute_script("arguments[0].click();", element)

How to click available button which refuses the click?

I'm working on automation of one website. My problem is that the button which is visible in my selenium (simply prints out) stopped working after recent update. Eventho I can see it, I cannot click it. I've noticed that it has started to have dynamic id selector, but class stays stable. What that can be ? Is there any other way to click it ?
<div>
<div>
<div class="pull-left middle-col-4">
<!---->
</div>
<div class="pull-left middle-col-4">
<!---->
</div>
</div>
<button tabindex="-1" id="exit-button-ZpyYaHCdmZ5jnmaamGhjaJjFcsVrmJOUcZWVaZlsaGlolpOaZg" class="btn btn-inverse btn-large pull-right">Wyjście</button>
</div>
To Click on the button induce WebDriverWait and element_to_be_clickable() And following locator strategy.
By Css Selector:
WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,"button.btn.btn-inverse.btn-large.pull-right"))).click()
By Xpath:
WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//button[#class='btn btn-inverse btn-large pull-right' and starts-with(#id,'exit-button-')][text()='Wyjście']"))).click()
You need to import followings to execute above code.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
Please find below solution to click exit button if id is dynamic
1. Xpath and contains method
button=driver.find_element_by_xpath("//button[contains(text(), 'Wyjście')]")
button.click()
2. Class name
element = driver.find_element_by_class_name("btn btn-inverse btn-large pull-right")
element.click()

How to fix "Element not interactable" Selenium error in Python?

I was trying to click a popup button and my code shows the error:
"selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable".
I have searched but could not find the solution which works for me with the popup buttons.
Image for clicking show 10 rows and displaying the pop-up boxThe attached image is the desired result and 'Show 10 rows' is behind it and lightly seen.
I have this in my HTML code and need to click on the button.
<div class="table-responsive">
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" id="loadsur" href="#Section" aria-expanded="true">LoadSurvey</a></li>
</ul>
<div class="container-fluid">
<div class="row">
<div class="col-md-12" style="margin-left: -10px;">
<div class="table-responsive">
<div id="myDataTable25_wrapper" class="dataTables_wrapper no-footer"><div class="dt-buttons">
<button class="dt-button buttons-csv buttons-html5" tabindex="0" aria-controls="myDataTable25">
<span>Csv</span></button>
<button class="dt-button buttons-excel buttons-html5" tabindex="0" aria-controls="myDataTable25">
<span>Excel</span></button>
<button class="dt-button buttons-collection buttons-page-length" tabindex="0" aria-controls="myDataTable25" aria-haspopup="true">
<span>Show 10 rows</span></button>
</div>
</div>
</div>
</div>
</div>
In Python I tried this:
def single_meter(i=0):
browser=webdriver.Chrome('C:\Webdrivers\chromedriver.exe')
for row in range (5,10):
browser.get('http://#link'+consumer_ID+'?reportrange=21%2F07%2F2018-25%2F08%2F2019')
Show10 = find_element_by_xpath("//button[#class='dt-button buttons-collection buttons-page-length']//span[contains(text(),'Show 10 rows')]")
Show10.click()
I expect to click this button which causes a popup button to appear.
It might be in an iframe.
Try first to find the iframe and switch to it.
browser = webdriver.Chrome()
browser.get("http:/link")
frame_id = 'frame'
wait = WebDriverWait(browser, 10)
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, frame_id)))
Then try clicking on the button.
Show10 = wait.until(expected_conditions.element_to_be_clickable((By.XPATH, "//button[#class='dt-button buttons-collection buttons-page-length']//span[contains(text(),'Show 10 rows')]")))
Show10.click()
I got a solution to this problem. The error was with the link in the xpath. I later copied and pasted from the html and the code now looks this:
Show10 = find_element_by_xpath("//*[#id='myDataTable2_wrapper']/div[1]/button[7]/span")
Show10.click()
And it works fine. Thank all for your help.
Change the xpath with :
//button[#class='dt-button buttons-collection buttons-page-length']//span[contains(text(),'Show 10 rows')]
Try use WebDriverWait for make sure the element exist, and add expected_conditions until the element clickable.
Import this :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
Try this :
wait = WebDriverWait(singlemeter, 10)
Show10 = wait.until(expected_conditions.element_to_be_clickable((By.XPATH, "//button[#class='dt-button buttons-collection buttons-page-length']//span[contains(text(),'Show 10 rows')]")))
Show10.click()
Or use ActionChains, import this :
from selenium.webdriver import ActionChains
Try this :
ActionChains(singlemeter).move_to_element(Show10).click(Show10).perform()

Click on a checkbox element using python and selenium

I am trying to automate loading and configuring a web page.
On this page I am trying to check the state of the checkbox and then click on a it if its unchecked.
HTML code for the page:
<fieldset id="wireless-24" class="left" style="display: block;">
<div class="legend-edit text-orphan">
<legend>2.4 GHz network</legend><span>|</span><span id="edit-wireless-24"><a id="editWireless24Link" href="http://192.168.0.1/ui/1.0.99.162351/dynamic/home.html#">Edit</a></span>
</div>
<div class="row toggle-edit">
<label style="width: 126px;">Network:</label>
<label id="w-radio-enabled-text-24">Disabled</label> <!-- code sets the text to either Enabled or Disabled -->
<div class="cell" id="w-enabled-span-24">
<div class="check-item" style="">
<div><input type="checkbox" id="w-enabled-24" name="radio.band24.settings.isEnabled" class="ui-helper-hidden-accessible"><span class="ui-checkbox"></span></div>
<div><label for="w-enabled-24" class="ui-checkbox">Enabled</label></div>
</div>
</div>
</div>
Network is the field I am trying to click on. I am using selenium and python.
I tried the following:
browser.find_element_by_id("w-radio-enabled-text-24").send_keys("Enabled")
browser.find_element_by_text("Network").click()
Firstly, you are trying to send_keys to label tag, what is wrong. You can send_keys to input tag or equivalent. Secondly, you are trying to click on the label, what from my perspective also not effective. I believe you want something like this:
checkbox = driver.find_element_by_id('w-enabled-24') # locate checkbox
if not checkbox.is_selected(): # check if checkbox is already selected
checkbox.click() # if not, click on it
Also I would add WebDriverWait, to make sure, that element is visible and ready to be clicked like this:
checkbox = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "w-enabled-24")))
this will wait at least 10 seconds until checkbox will be clickable. The full code would be like this:
checkbox = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "w-enabled-24")))
if not checkbox.is_selected():
checkbox.click()
Note: you have to add some imports:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
More information about WebDriverWait you will find here.

Clicking on a button using selenium [Python]

I am opening a URL and trying to click on the Search button described here below:
<td class="th-sa-tb-bt">
<span class="th-bt-up">
<a href="javascript:void(0)" class="th-bt th-bt-text-em" onclick="thBtMgr.click(this);return htmlbSL(this,2,'J22_MNQ_LOP_V1WR_SEARCH_BTN:SEARCH','0')" onmousedown="thBtMgr.press(this,event);" onfocusout="thBtMgr.unpress(this);" onfocus="thSaveKbFocus(this);" oncontextmenu="return false;" ondragstart="return false;" id="J22_MNQ_LOP_V1WR_SEARCH_BTN" title="Search">
<span class="th-bt-span">
<b class="th-bt-b">Search</b>
</span>
</a>
</span>
<span class="th-bt-spacer">
<!-- -->
</span>
<span class="th-bt-up">
<a href="javascript:void(0)" class="th-bt th-bt-text" onclick="thBtMgr.click(this);return htmlbSL(this,2,'J22_MNQ_LOP_V1WR_CLEAR_BTN:\x23Exit\x23_CLEAR','0')" onmousedown="thBtMgr.press(this,event);" onfocusout="thBtMgr.unpress(this);" onfocus="thSaveKbFocus(this);" oncontextmenu="return false;" ondragstart="return false;" id="J22_MNQ_LOP_V1WR_CLEAR_BTN" title="Clear">
<span class="th-bt-span">
<b class="th-bt-b">Clear</b>
</span>
</a>
</span>
<span class="th-bt-spacer">
<!-- -->
</span>
<span class="th-bt-up">
<a href="javascript:void(0)" class="th-bt th-bt-text" onclick="thBtMgr.click(this);return htmlbSL(this,2,'J22_MNQ_LOP_V1WR_BtnReset:RESET','0')" onmousedown="thBtMgr.press(this,event);" onfocusout="thBtMgr.unpress(this);" onfocus="thSaveKbFocus(this);" oncontextmenu="return false;" ondragstart="return false;" id="J22_MNQ_LOP_V1WR_BtnReset" title="Reset">
<span class="th-bt-span">
<b class="th-bt-b">Reset</b>
</span>
</a>
</span>
<span class="th-bt-spacer">
<!-- -->
</span>
</td>
Here when I copy the xpath for the search button element J22_MNQ_LOP_V1WR_SEARCH_BTN it gives me timeout error.
Here is the code :
import time
import selenium
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
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("<URL>")
time.sleep(10)
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, '//*[#id="J22_MNQ_LOP_V1WR_SEARCH_BTN"]'))
)
element.click()
I tried with XPATH and ID also along with this increased time wait to check if the exception that I get that resolves or not, but unfortunately nothing works, can anybody help here?
Traceback :
Traceback (most recent call last):
File "C:\Users\vanishka\Desktop\test2\.py", line 18, in <module>
EC.element_to_be_clickable((By.XPATH, 'J22_MNQ_LOP_V1WR_SEARCH_BTN'))
File "C:\Program Files (x86)\Python36-32\lib\site-packages\selenium\webdriver\support\wait.py", line 80, in until
raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message:
Added iframe Html :
<div id="Uiframecontainer" style="display: block; visibility: visible;">
<iframe name="UiApplicationFrame" id="UiApplicationFrame" frameborder="0" title="Uiframeapp" scrolling="no" src="/zzp(ZT1RelV5TkRJd05EWmZYMTlmT0ROZk1qUmZBSkQ2NW81V0h0aUdvOHBZZWk5ZzFnPT0=)/bc/bsp/zzp/crm_ui_frame/main.htm?zzx-client=001&zzx-language=EN&zzx-domainRelax=min&zzzrole=zzfdecs" style="display: block; visibility: visible;"></iframe></div>
<frame src="/zzx/bc/bsp/zzx/crmcmp_hdr/bspwdapplication.do?zzx-client=001&zzx-language=EN&zzx-domainRelax=min&zzxrole=zzfedcs" name="HeaderFrame" id="HeaderFrame" title="" scrolling="no" noresize="noresize" frameborder="0" marginwidth="0" marginheight="0" onload="thtmlbSetOnloadFrameEvents(event, this)">
As per the HTML to click on the Search button you have to induce WebDriverWait and you can use the following line of code :
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//td[#class='th-sa-tb-bt']/span[#class='th-bt-up']/a[#class='th-bt th-bt-text-em']/span[#class='th-bt-span']/b[#class='th-bt-b']"))).click()
First: using a time.sleep followed by a WebdriverWait completely nullifies the value of the WebdriverWait. I might even describe it as low-grade evil.
As for your issue - I am not yet convinced the element is there to be found. Can you go to the console in your browser dev tools and type $x('YOUR_XPATH_HERE'), press enter and tell me if it returns the expected element? If not, and you see the element on the page, the issue is with your locator.
If you see the element but you can't find it with a known-good locator, look for an iframe or other element that could be grabbing your focus. This may require webdriver.switch_to()
Try:
element = driver.find_element_by_xpath("//*[contains(#class, 'th-') and contains(text(), 'Search')]")
element.click()
If this returns Unable to locate element, use this first:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//*[contains(#class, 'th-') and contains(text(), 'Search')]"))
)
Switch to the frame before interacting
Selenium can only interact with a single document at a time. If the element you desire is located in a frame, you will need to “switch to” that frame before searching or clicking:
iframe = driver.find_element_by_name("UiApplicationFrame")
driver.switch_to.frame(iframe)
try:
element = driver.find_element_by_link_text("Search")
element.click()
finally:
driver.switch_to.default_content
P.S. Search like a human
Notice that my answer searches for the element in a different way.
While searching by ID may work for now, it might not always. The implementation of the page could easily change, breaking your script.
To be more resilient against such change, search like a human would: by looking for an interactive element by its text.
Bonus: Simplify with Capybara
This can be further simplified by using capybara-py, which provides a helpful layer atop Selenium:
with page.frame("UiApplicationFrame"):
page.click_link("Search")
In addition to simplifying the work of finding and switching into and out of frames, Capybara provides helpers, such as click_link, for performing common interactions with semantic, accessible HTML elements. It also synchronizes everything, e.g., by retrying if the link is not yet visible or not yet clickable.
This had been the same issue with selenium which I too faced, but you can workaround it with something like this:
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, '//*[#id="J22_MNQ_LOP_V1WR_SEARCH_BTN"]'))
)
driver.find_element_by_xpath('//*[#id="J22_MNQ_LOP_V1WR_SEARCH_BTN"]').click()
Hope this helped.

Categories