Python/Selenium - Getting the element after an element - python

I need to close a popup window from the website itself by pressing the "X" window on the top right. Here is the shortened, relevant part of my code:
chromedriver = r'C:\Users\do\Desktop\chromedriver.exe'
browser = webdriver.Chrome(chromedriver)
url = 'Fake.com'
browser.get(url)
browser.find_element_by_id('imgAttachmentsImg').click()
# I need to close out the window after this
The issue is that there are no unique identifiers for the "X" button itself. However, the pop up itself does have a unique identifier. I just need to be able to flow it down to the X button.
Info from the page:
1. V<div class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-draggable ui-resizable" tabindex="-1" role="dialog" aria-describedby="attachmentsDialogOverview" aria-labelledby="ui-id-3" style="position: absolute; height: auto; width: auto; top: 239px; left: 102px; display: block;">
2. <div class="ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix">
3. <span id="ui-id-3" class="ui-dialog-title">Attachments</span>
4. V<button type="button" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only ui-dialog-titlebar-close" role="button" aria-disabled="false" title="close">
5. <span class="ui-button-icon-primary ui-icon ui-icon-closethick"</span>
6. <span class="ui-button-text">close</span></button>
I am new to using Python and Selenium. I switched over from VBA and still don't exactly understand all the syntax yet, so I do make mistakes! I did find a bandaid solution by just having sendkeys press Escape. But I am trying to actually understand how to actually solve this. I am not sure what errors I made with my solution:
browser.find_element_by_xpath("//span[#id, 'ui-id-3']/following-sibling::button").click()
Questions
Why did my solution not work?
How would I locate "ui-id-3"(on line 3) and get to the element on Line 4 to click it?
How would I locate "ui-id-3"(on line 3) and get to the element on Line 5 to click it? (just so I know how to move across multiple elements)
Relevant links I looked over:
Following-Sibling Python Selenium
Find next sibling element in Python Selenium?
Using XPath Selector 'following-sibling::text()' in Selenium (Python)
Python + Selenium WebDriver - Get div value if sibling contains string
What is the correct syntax for using a variable and following-sibling in Python Selenium?

The xpath has a problem. this should work:
browser.find_element_by_xpath("//span[#id='ui-id-3']/following-sibling::button").click()
To get to the span below it, you could use:
browser.find_element_by_xpath("//span[#id='ui-id-3']/following-sibling::button/span")
by the way, if you're more comfortable with CSS, the equivalent paths would be:
div#ui-id-3 > button
div#ui-id-3 > button span:nth-of-type(1)

Related

How to click a Vue/Vuetify card using selenium in python?

I am using selenium version 4.0.0, for reference.
I'm trying to click a Vuetify card element, which is acting as a button, but I running into an element not interactable: [object HTMLDivElement] has no size and location or just element not interactable errors. I have been able to solve similar problems with action chains in the past, but it doesn't seem to work with this.
This is the list element the button is contained within:
<li class="lu-li list-item" data-v-711d8d7a="" style="display: flex;">
<div class="addCard v-card v-card--link v-sheet theme--light" data-v-711d8d7a="" tabindex="0" onselectstart="return false;">
::before
<i class="v-icon notranslate btnAdd material-icons theme--light enableIcon" data-v-711d8d7a="" aria-hidden="true">
add
::after
</i>
</div>
</li>
The first things I tried was simply clicking on the element, and then clicking on the <i> element beneath it when that didn't work:
addQLButton = driver.find_element(By.CLASS_NAME, "addCard")
addQLButton.click()
addQLButton = driver.find_element(By.CLASS_NAME, "btnAdd")
addQLButton.click()
I have already tried using WebDriverWait on both the v-card <div> and <i> element to make sure they are available before being clicked, which it passes without any issues:
WebDriverWait(driver, timeout=10).until(lambda d: d.find_element(By.CLASS_NAME, "addCard"))
WebDriverWait(driver, timeout=10).until(lambda d: d.find_element(By.CLASS_NAME, "btnAdd"))
I have already tried using action chains to make sure the elements are visible (this has worked in the past with similar errors), but I still run into the same issue:
addQLButton = driver.find_element(By.CLASS_NAME, "addCard")
actions.move_to_element(addQLButton).perform()
driver.execute_script("arguments[0].click();", addQLButton)
addQLButton = driver.find_element(By.CLASS_NAME, "btnAdd")
actions.move_to_element(addQLButton).perform()
driver.execute_script("arguments[0].click();", addQLButton)
The elements are not in an iframe, and I am sure I have the correct window selected as I am still able to interact with its elements.
I am at a bit of a loss, any help would be much appreciated. I'm happy to answer any clarifying questions if I didn't explain the issue clearly enough.
I managed to get it working with some javascript:
js = "document.querySelector('.btnAdd').click();"
driver.execute_script(js)

Finding/locating a clickable text by xpath in div/span format

I used the following line to click the Availability Grid button, but it failed to locate the element.
Class Sarsa-button-content is used everywhere so, I added text together to make it unique. However, it couldn't find it. What am I missing?
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//a[#class='sarsa-button-content']/span[text()='Availability Grid']"))).click()
<div class="sticky-top-wrapper" style="top: 80px;">
<div class="site-filter-container" id="site-filter-container">
<a data-component="Button" class="sarsa-button view-by-availability-grid--button-tracker sarsa-button-primary sarsa-button-sm" href="/site/123456/availability">
<span class="sarsa-button-inner-wrapper">
<span class="sarsa-button-content">Availability Grid</span>
your xpath is wrong, try this:
//span[contains(#class, 'sarsa-button-content') and text() = 'Availability Grid']

Selenium "Select" Class returns "Unsupported locator strategy" error

I have been trying to enter a website using Python and it's Selenium Package. In this website I have to: (1) enter some login credentials (2) go to a specific page (need the credentials to travel there)
(3) select value from drop-down list
I have managed the first two steps, however, I can't manage to overcome the drop-down list problem. I always get the error:
Message: invalid argument: Unsupported locator strategy: null
I have tried to change my Locator method from "name" to "id" and to "value" but have been unsuccessful.
Any assistance would be much appreciated, I am puzzled as to why all the rest works and this specific point fails. I can't provide the original website as example due to proprietary issues.
Thank you!
EDIT: I have added the HTML code regarding the drop-down list, had to omit some information due to personal details but I think it should help anyways.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.ui import Select
#log-in info
userStr = "User"
passStr = 'Pass'
#enter log-in
browser = webdriver.Chrome()
browser.get(('https://www.example.com'))
Log_User = browser.find_element_by_id('user_field')
Log_User.send_keys(userStr)
Log_User = browser.find_element_by_id('pass_field')
Log_User.send_keys(passStr)
Enter_Button = browser.find_element_by_id('enter_button')
Enter_Button.click()
#go to desired window
browser.get(('https://www.example.com/newpage.aspx'))
#select dropdown (the issue is here)
select = Select(browser.find_element_by_name('drop-down-list'))
select.select_by_value("target")
<div class="ms-webpart-zone ms-fullWidth">
<div id="MSOZoneCell_WebPartWPQ2" class="s4-wpcell-plain ms-webpartzone-cell ms-webpart-cell-vertical ms-fullWidth ">
<div class="ms-webpart-chrome ms-webpart-chrome-vertical ms-webpart-chrome-fullWidth ">
<div webpartid="46ca13d8-6d03-474f-bc6c-d2c6cf8c95f2" haspers="false" id="WebPartWPQ2" width="100%" class="ms-WPBody noindex " allowdelete="false" style=""><div class="ms-rtestate-field"><h2 class="3s-web-title">***<br></h2></div><div class="ms-clear"></div></div>
</div><div class="ms-PartSpacingVertical"></div>
</div><div id="MSOZoneCell_WebPartctl00_ctl51_g_0c672ab8_73ff_4b46_a925_3f0c0213b64d" class="s4-wpcell-plain ms-webpartzone-cell ms-webpart-cell-vertical ms-fullWidth ">
<div class="ms-webpart-chrome ms-webpart-chrome-vertical ms-webpart-chrome-fullWidth ">
<div webpartid="0c672ab8-73ff-4b46-a925-3f0c0213b64d" haspers="false" id="WebPartctl00_ctl51_g_0c672ab8_73ff_4b46_a925_3f0c0213b64d" width="100%" class="ms-WPBody noindex " allowdelete="false" style=""><div style="display: table; margin-bottom: 10px;"><div style="display: table-row;"><div style="display: table-cell; vertical-align: middle; text-align: left;"><label style="margin-bottom: 0px;" for="ctl00_ctl51_g_0c672ab8_73ff_4b46_a925_3f0c0213b64d_ddlDealers">Concessionário:</label></div><div style="display: table-cell; vertical-align: middle; text-align: left; padding-left: 15px;">
<select name="ctl00$ctl51$g_0c672ab8_73ff_4b46_a925_3f0c0213b64d$ddlDealers" onchange="javascript:setTimeout('__doPostBack(\'ctl00$ctl51$g_0c672ab8_73ff_4b46_a925_3f0c0213b64d$ddlDealers\',\'\')', 0)" id="ctl00_ctl51_g_0c672ab8_73ff_4b46_a925_3f0c0213b64d_ddlDealers">
<option selected="selected" value="-1;-1">-- Concessionário --</option>
<option value="*****;****">***** (Special Sales) (****2)</option>
...
</select></div></div></div>
<span>Necessita de seleccionar um concessionário.</span><div class="ms-clear"></div></div>
</div>
</div>
</div>
is find_element_by_name really a thing? You can do:
browser.find_element_by_css_selector('[name="drop-down-list"]')
The error message seems to be complaining about a null argument passed into the constructor for Select. My guess would be browser.find_element_by_name('drop-down-list') is not returning anything, which could set the value to null, and that's what the error message might be detailing.
Based on the HTML you provided, it doesn't look like your locator for the select element is correct -- you are searching by_name, but the element does not have a distinct name attribute -- it is just a randomly generated string.
I tested your code in my browser and I received a NoSuchElementException when browser.find_element_by_name('drop-down-list') did not find an element, so I'm not sure where the null error is coming from. select_by_value just takes a string parameter, so I don't think the issue is on that line either.
You could try changing to an XPath and see if that works:
select = Select(browser.find_element_by_xpath("//select[contains(#id, 'ddlDealers')]"))
Since you mentioned there is only one select element on the page, you could also try:
# locate select element
select_element = browser.find_element_by_xpath("//select")
# call print to verify something has been located
print(select_element)
# declare the select object
select = Select(select_element)
Something like <selenium.webdriver.remote.webelement.WebElement (session="5c7855ef72bf6bca9babb1e0a7a22ac2", element="6e100df3-342d-47ad-99f3-f48300282b5b")> will print in the console if an element has successfully been located -- this will rule out whether or not the issue is with the selector.
If this does not work, there may be some sort of iframe element that is hiding the select from driver -- if the above code throws a NoSuchElementException, we may need to see some more HTML on the page to get the context which the select appears in.

Python Selenium Scrape with dropdown

I am using python and selenium to scrape a website. However I am having issues selecting an element from a dropdown list. When I run this script on windows in the python IDE I can get my script to work:
listElement = driver.find_element_by_id('header-transactionTypeOptions')
transElement = driver.find_element_by_id('container-primary-4-transactionTypeOptions')
listElement.click()
time.sleep(2)
transElement.click()
<input id="header-transactionTypeOptions" class="jpui input header focus-on-header wrap right text-float-left " type="button" aria-disabled="false" aria-expanded="false" aria-label=" SHOWING:: Activity since last statement" value="Activity since last statement">
However, when I run this on my ubuntu instance with pyvirtualdisplay it tells me it cannot locate the element. In my research for using selenium with a drop down - the suggested answers are using "Select". However there is no "Select ID" on the elements on this webpage.
I have include the elements below, as other options to reference in trying to find an answer:
<button id="iconButton-transactionTypeOptions" type="button" class="jpui input-icon icon text-overflow" aria-hidden="true" tabindex="-1"><span class="jpui expanddown icon input-icon hasError"></span></button>
<span class="primary" id="container-primary-1-transactionTypeOptions">Jul 21, 2016 statement </span>

Selenium Webdriver python: Element is not currently visible & same class name

I am using Selenium in python to click a button in a dialog. I try to click"OK", but it keeps getting errors
the buttons show "display:block" in CSS, cause "element is not visible" error
find_element_by_xpath, but the xpath of the element keeps changing
the class names are the same, how to choose the "OK" button?
Here are the code
<div<class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix">
<div<class="ui-dialog-buttonset">
<button type="button" class="large ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false">
<span class="ui-button-text">Cancel</span>
</button>
<button type="button" class="orange large ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false">
<span class="ui-button-text">OK</span>
</button>
</div>
</div>
Thank you:)
If the element is invisible in the DOM like css { display: None}, {opacity: 0}... etc, , selenium will not be able to SEE it even given that you try to wait or time.sleep, instead you should use execute_script to run a JavaScript to trigger the desired event, something like this:
driver.execute_script('document.querySelector("span.ui-button-text").click();')
You should wait for the element to be ready before trying to click on it. Use waitForVisible or similar to achieve that.
For example, something like this:
element = WebDriverWait(driver, 10).until(
lambda driver : driver.find_element_by_xpath(element_xpath)
)
If the class remains the same, then you should select that class with element_xpath. The last thing you need to determine is what other attribute designates the button as ready. Then you can wait for the specific argument like:
def find(driver):
e = driver.find_element_by_xpath(element_xpath)
if (e.get_attribute(some_attribute)==some_value):
return False
return e
element = WebDriverWait(driver, 10).until(find)
Two different things can happen here.
• The selector is not explicitly returning the intended element
• Element load issue.
If both cases are true use explicit wait with a correct selector. In terms of selector I like using text bases search in such scenario. Notice I am using xpatth contains to make sure it eliminates any leading or tailing white spaces.
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH , "//span[contains(text(),'OK')]")))
API doc here

Categories