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.
Related
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)
I'm using selenium for web scraping, and I have the following HTML:
<a data-field="---" class="---" target="---" href="https://www.example.com/0000/">
<div class="display-flex align-items-center">
<span class="mr1 hoverable-link-text t-bold">
How can I access the href link and click on it?
I used the following and didn't get results, would be great to understand why:
browser.find_element(By.PARTIAL_LINK_TEXT, "https://www.example.com")
browser.find_element(By.XPATH,"//a[contains(text(),'https://www.example.com')]")
Thanks!
Edit:
The page I'm working on is the LinkedIn interests page (companies that I follow). You can find it on: https://www.linkedin.com/in/yourusername/details/interests/?detailScreenTabIndex=1
For each company I follow, there is an HTML:
<a data-field="active_tab_companies_interests" class="optional-action-target-wrapper
display-flex flex-column full-width" target="_self" href="https://www.linkedin.com/company/1016/">
<div class="display-flex align-items-center">
<span class="mr1 hoverable-link-text t-bold">
<span aria-hidden="true"><!---->GE Healthcare<!----></span><span class="visually-hidden"><!---->GE Healthcare<!----></span>
</span>
<!----><!----><!----> </div>
<!----> <span class="t-14 t-normal t-black--light">
<span aria-hidden="true"><!---->1,851,945 followers<!----></span><span class="visually-hidden"><!---->1,851,945 followers<!----></span>
</span>
<!----> </a>
I want to find href, in my example: "https://www.linkedin.com/company/1016/"
The code I wrote (with the help of the comments):
# log in
browser.get("https://www.linkedin.com")
username = browser.find_element(By.ID,"session_key")
username.send_keys("youremail")
password = browser.find_element(By.ID,"session_password")
password.send_keys("yourpassword")
login_button = browser.find_element(By.CLASS_NAME, "sign-in-form__submit-button")
login_button.click()
# companies I follow on Linkedin
browser.get("https://www.linkedin.com/in/username/details/interests/?detailScreenTabIndex=1")
# find all company links
wait = WebDriverWait(browser, 20)
company_page = browser.find_elements(By.XPATH,"//a[contains(#href,'https://www.linkedin.com/company/')]")
for x in range (len(company_page)):
print(company_page[x].text)
The output for "GE healthcare" (from the HTML snippet) is:
GE Healthcare
GE Healthcare
1,852,718 followers
1,852,718 followers
and not the href link that I'm looking for. I don't understand why it finds these texts and not the link.
Thanks!
https://www.example.com/0000/ is not a text attribute content. It is a value of href attribute. This is why both you locators are wrong.
Please try this:
browser.find_element(By.XPATH,"//a[contains(#href,'https://www.example.com')]")
Adding a .click() will probably click on that element, as following:
browser.find_element(By.XPATH,"//a[contains(#href,'https://www.example.com')]").click()
You may probably will need to add a delay to wait for the element to be clickable. In this case WebDriverWait expected conditions is the right way to do it, as following:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(browser, 20)
wait.until(EC.element_to_be_clickable((By.XPATH, "//a[contains(#href,'https://www.example.com')]"))).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()
There is drop menu in a frame, in code it starts with <div tag id=masterdiv, div class=submenu and onclick="SwitchMenu('sub1')">,
I have to click first on Personal Info., and then select Personal Details
I tried
driver.find_element_by_xpath("//a[contains(href,'PersonalInfo/EmpPersonalInfo.jsp')
and
contains(#class,'submenu')]")
and
driver.find_element_by_link_text("//a [#href=\"../EmployeeFiles/AcademicInfo/DailyStudentAttendanceEntry.jsp\"]")
None works.
<div id="masterdiv">
<div class="menutitle" onclick="SwitchMenu('sub1')">Personal Info.  <img src="../Images/arrow.gif"></div>
<span class="submenu" id="sub1" style="display: none;">
<img src="../Images/bullet4.gif"> <a target="DetailSection" title="Personal Information" href="PersonalInfo/EmpPersonalInfo.jsp"><font face="Arial" color="white" size="2">Personal Detail</font></a><br>
<img src="../Images/bullet4.gif"> <a target="DetailSection" title="Personal Information" href="PersonalInfo/imprestAcc.jsp"><font face="Arial" color="white" size="2">My Imprest Account</font></a><br>
<img src="../Images/bullet4.gif"> <a target="DetailSection" title="Self Attendance Detail" href="PersonalInfo\SelfAttendanceDetail.jsp"><font face="Arial" color="white" size="2">Self Attendance</font></a><br>
<img src="../Images/bullet4.gif"> <a target="DetailSection" title="Change eMailID/Contact Numbers" href="PersonalInfo/EmpModifyEmailIDTelephone.jsp"><font face="Arial" color="white" size="2">Edit Info.</font></a><br> }
Actually your provided locator looks incorrect that's why are unable to find element, you should try using WebDriverWait to wait until element present as below :-
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
#first switch to frame if present
driver.switch_to_frame("frame id or name")
wait = WebDriverWait(driver, 10)
# now find menu and click
menu = wait.until(EC.presence_of_element_located((By.XPATH, ".//*[contains(., 'Personal Info')]")))
menu.click()
#now find submemu and click
submemu = wait.until(EC.presence_of_element_located((By.XPATH, ".//*[contains(., 'Personal Detail')]")))
submemu.click()
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"]')))