Selenium selecting link within table - with all the same name - python-3.x

Cant click on the link due to the fact, all of the value I keep trying to select has the same name as well within the tables.
Tried xpath,by link, by text, by css none of it works. My current code:
driver.find_element_by_xpath('//[#id="homeapp"]/div/div/div[3]/div[1]/table/tbody/tr[3]/td[2]/div[1]/div[2]/span[1]/a').click()
Here is the relevant html code:
<tr class="bui-table__row"><td class="peg-table__cell--no-label bui-table__cell" data-heading="ID" scope="row"><a href="../../extranet_ng/manage/index.html?ses=8594ddf0718dec240a0c9e7991e108a8&name_id=11111" class="bui-link bui-link--secondary" target="_blank" data-track-ga="Groups: Home,Active Properties,Property ID">
1111(number i can click aswell)
</a></td> <td class="peg-table__cell--no-label bui-table__cell" data-heading="Name" scope="row"><div class="bui-avatar-block"><div class="peg-_-avatar-shrink bui-avatar"><img src="https://q-xx.bstatic.com/xdata/images/extra/square60/189090859.jpg?k=cc455d4d570f0e0c86a1b8329b16d53fdba96d78677cc87151d6181e45d38ec5&o=" alt="text i want to click" class="bui-avatar__image"></div> <div class="bui-avatar-block__text"><span class="bui-avatar-block__title"><a href="../../extranet_ng/manage/index.html?ses=8594ddf0718dec240a0c9e7991e108a8&name_id=11111" class="peg-property-link bui-link bui-link--secondary" target="_blank" data-track-ga="Groups: Home,Active Properties,Property Name">
Text i want to click
<!----> <!----></a></span> <span class="bui-avatar-block__subtitle"><!----> </span></div></div> <div class="bui-spacer--smaller"></div> <div class="peg-score-bar__inline bui-score-bar"><div class="bui-score-bar__item"><div class="bui-score-bar__header"><h2 class="bui-score-bar__title"></h2> <span class="bui-score-bar__score">93%</span></div> <div class="bui-score-bar__bar"><span data-value="9.3" class="bui-score-bar__value" style="width: 93%;"></span></div></div></div></td> <td class="peg-table__cell--no-label bui-table__cell" data-heading="Location"><div class="peg-address-wrapper"><span class="peg-flag-wrapper"><div class="peg-flag bui-flag"><img src="https://q.bstatic.com/backend_static/common/flags/16/nl/314ce6500532e846e25d6e3a7c824ef17c968446.png" class="bui-flag__flag" style="height: auto;"> <!----></div></span>
TEXT2
</div></td> <td class="peg-table__cell--no-label bui-table__cell" data-heading="Status"><span>Open/Bookable</span></td> <td class="bui-table__cell bui-table__cell--center" data-heading="Arrivals/departures & tomorrow"><span class="peg-counter--arrivals"><a href="../../extranet_ng/manage/search_reservations.html?ses=8594ddf0718dec240a0c9e7991e108a8&name_id=11111" data-track-ga="Groups: Home,Active Properties,Arrivals" target="_blank" class="peg-counter peg-counter--has"><span aria-label="80 unread" class="bui-bubble">
VALUE1
</span></a></span> <span class="peg-counter--departures"><a href="../../extranet_ng/manage/search_reservations.html?ses=8594ddf0718dec240a0c9e7991e108a8&name_id=11111&type=departure" data-track-ga="Groups: Home,Active Properties,Departures" target="_blank" class="peg-counter peg-counter--has"><span aria-label="80 unread" class="bui-bubble">
VALUE2
</span></a></span></td> <td class="bui-table__cell bui-table__cell--center" data-heading="Guest Messages"><a href="../../extranet_ng/manage/messaging_inbox.html?ses=8594ddf0718dec240a0c9e7991e108a8&name_id=11111" data-track-ga="Groups: Home,Active Properties,Guest Messages" target="_blank" class="peg-counter peg-counter--has"><span aria-label="102 unread" class="bui-bubble">
VALUE3
</span></a></td> <td class="bui-table__cell bui-table__cell--center" data-heading="extranet.com Messages"><a href="../../extranet_ng/manage/inbox.html?ses=8594ddf0718dec240a0c9e7991e108a8&name_id=11111" data-track-ga="Groups: Home,Active Properties,extrabnet.com Messages" target="_blank" class="peg-counter"><span aria-label="0 unread" class="bui-bubble">
0
</span></a></td></tr>

If you want to click the link which contains avatar in its class attribute use the following XPath expression:
//div[contains(#class,'avatar')]/descendant::a[contains(text(), 'text i want to click')]
where:
contains() is XPath Function allowing partial match on the attributes values and/or text
descendant - XPath Axis which matches children of the current node and their respective children
last part limits the search to hyperlinks which contain text you're looking for

The desired element is a ReactJS enabled element, so you have to induce WebDriverWait for the element to be clickable() and you can use either of the following solutions:
Using PARTIAL_LINK_TEXT:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.PARTIAL_LINK_TEXT, "text i want to click"))).click()
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.peg-property-link.bui-link.bui-link--secondary[href*='/extranet_ng/manage/index'][data-track-ga*='Active Properties']"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[#class='peg-property-link bui-link bui-link--secondary' and contains(#href, '/extranet_ng/manage/index')][starts-with(#data-track-ga, 'Groups')]"))).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

Related

Using Selenium and Python to Click on a button below searched element

I am trying to test downloading a file from a website using selenium on python.
The website has peculiar design where the file name appears as a text element above the button to download the file. There are no specific names or IDs for these buttons. And they are not known to us. So, I can't specify the ID or element name in the code directly.
Here is the HTML snippet:
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 noborderBottom semiBolder-label ">
<span data-bind="text: jurisdictionName, attr: { id: jurisdictionId() + '-guides' }, visible: showInList" id="67-guides">Greece</span>
</div>
<div class="clearfix visible-xs"></div>
<div class="col-xs-6 col-sm-6 col-md-5 col-lg-5 text-center">
<div class="greenPDFIcon cursorPointer align-center" data-bind="event: { click: onHighlightClick.bind($data) }, style: { 'visibility': highLightUrl() ? 'visible' : 'hidden' }" style="visibility: visible;"></div>
<span class="taxGuidesText lg-visible md-visible xs-visible" data-bind="style: { 'visibility': highLightUrl() ? 'visible' : 'hidden' }" style="visibility: visible;">Highlights</span>
<!--<span class="taxGuidesText lg-visible md-visible xs-visible" data-bind="visible:showInList">Highlights</span>-->
</div>
Now, I first need to search for the text "Greece" in the above example.
Get it's location on the webpage:
class="col-xs-12 col-sm-12 col-md-12 col-lg-12 noborderBottom semiBolder-label"
Locate the button right below this text - so in the above example that gives me:
class="col-xs-6 col-sm-6 col-md-5 col-lg-5"
And then click on the button:
class="greenPDFIcon cursorPointer align-center"
The thing is, I do not know this "Greece". That comes through input parameter.
I only know that if the input parameter text is found on the webpage, the button will be right below it. And I have to click it to open the pdf file.
How to do that using selenium on python?
So far I have reached:
s=Service(r"driver_path")
browser = webdriver.Edge(service=s)
browser.get('webpage_url')
country = input('Enter a country name: ')
Also, suggest if I should use anything else rather than selenium to do this, as I understand this is more of web-scrapping than automated testing. I also tried beautifulsoup, but the website is not accessible directly through api. Browser access is required.
To locate the element with the country name e.g. Greece and click on the respective element with text as Highlights you can use the following Locator Strategies:
Using XPATH and "Old Style" String Formatting (% Operator):
browser.get('webpage_url')
country = input('Enter a country name: ')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[contains(#class, 'semiBolder-label')]//span[contains(., '%s')]//following::div[2]//span[contains(., 'Highlights')]" % country))).click()
Using XPATH and "New Style" String Formatting (str.format):
browser.get('webpage_url')
country = input('Enter a country name: ')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[contains(#class, 'semiBolder-label')]//span[contains(., '{}')]//following::div[2]//span[contains(., 'Highlights')]".format(country)))).click()
Using XPATH and String Interpolation / f-Strings (Python 3.6+):
browser.get('webpage_url')
country = input('Enter a country name: ')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, f"//div[contains(#class, 'semiBolder-label')]//span[contains(., '{country}')]//following::div[2]//span[contains(., 'Highlights')]"))).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

How to extract the text content from multiple span elements using Selenium and Python

How to select text content from multiple DIV elements using selenium?
On the website I intend to collect information it contains div and span with the same class.
How can I collect this information separately?
I need the contents inside the panel-body div > span of each block
driver.find_element_by_xpath(".//div[#class='panel-body'][1]/span[1]").text
driver.find_element_by_xpath(".//div[#class='panel-body'][1]/span[2]").text
driver.find_element_by_xpath(".//div[#class='panel-body'][1]/span[3]").text
driver.find_element_by_xpath(".//div[#class='panel-body'][2]/span[1]").text
driver.find_element_by_xpath(".//div[#class='panel-body'][2]/span[2]").text
html
<div class="panel-heading">
<h3 class="panel-title">Identificação</h3>
</div>
<div class="panel-body">
<span class="spanValorVerde">TEXT</span><br>
<span style="font-size:small;color:gray">TEXT</span><br>
<br>
<span class="spanValorVerde">TEXT</span>
</div>
</div>
<div class="panel panel-success">
<div class="panel-heading">
<h3 class="panel-title">Situação Atual</h3>
</div>
<div class="panel-body">
<span class="spanValorVerde">TEXT</span> <br>
<span class="spanValorVerde">TEXT</span>
</div>
</div>
I am expecting that "select text" meant "get text".
first for loop:
count = driver.find_elements_by_xpath(".//div[#class='panel-body'][i]")
second for loop with count iteration:
driver.find_element_by_xpath(".//div[#class='panel-body'][i]/span[j]").text
If you search with findElements with ".//div[#class='panel-body'][i]" will give you the total element present, then add another loop for .//div[#class='panel-body'][i]/span[j] and then get text. Hope it helps!
To extract the texts e.g. TEXT, from each <span> using Selenium and python you have to induce WebDriverWait for visibility_of_all_elements_located() and you can use either of the following Locator Strategies:
Using CSS_SELECTOR and get_attribute("innerHTML"):
print([my_elem.get_attribute("innerHTML") for my_elem in WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "div.panel.panel-success div.panel-body span.spanValorVerde")))])
Using XPATH and text attribute:
print([my_elem.text for my_elem in WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//div[#class='panel panel-success']//div[#class='panel-body']//span[#class='spanValorVerde']")))])
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
Outro
Link to useful documentation:
get_attribute() method Gets the given attribute or property of the element.
text attribute returns The text of the element.
Difference between text and innerHTML using Selenium

Find different element inside rows using selenium python

I am trying to get the values of available license inside the table using selenium in python3. I am able to get the values using XPATH, and iterate through each rows. But XPATH is not ideal, since the table might change and include an additional column, thus will fail to get the correct value.
The values I want, is 98,50,etc...
<div class="slick-cell l6 r6 licensesUsedValueGrid">
<div class="slick-cell odd" style="padding: 0px;width:100%;height: 44px;">
<div style="padding: 15% 4px 0px 0%;float: right;">98</div>
</div>
</div>
<div class="slick-cell l6 r6 licensesUsedValueGrid">
<div class="slick-cell odd" style="padding: 0px;width:100%;height: 44px;">
<div style="padding: 15% 4px 0px 0%;float: right;">50</div>
</div>
</div>
This is using XPATH, and it worked:
for i in range(1, rows, 2):
pak_id = browser.find_element_by_xpath(f'//*[#id="scrollBarDiv"]/div/div[{i}]/div[3]/div/div/div[1]').text
used_license = browser.find_element_by_xpath(f'//*[#id="scrollBarDiv"]/div/div[{i}]/div[7]/div/div').text
available_license = browser.find_element_by_xpath(f'//*[#id="scrollBarDiv"]/div/div[{i}]/div[8]/div/div').text
I would like to use class name or some other means so that even if they add another column to the table, i will be able to capture the right value of 'license used' and 'license available'
Picture of how it looks like on chrome:
Probably just:
browser.find_elements_by_css_selector('.licensesUsedValueGrid')
To extract all the values of available licenses using Selenium and Python you have to induce WebDriverWait for the visibility_of_all_elements_located() and you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
print([my_elem.text for my_elem in WebDriverWait(driver, 5).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "div.licensesUsedValueGrid>div.slick-cell.odd>div")))])
Using XPATH:
print([my_elem.text for my_elem in WebDriverWait(driver, 5).until(EC.visibility_of_all_elements_located((By.XPATH, "//div[contains(#class, 'licensesUsedValueGrid')]/div[#class='slick-cell odd']/div")))])
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

NoSuchElementException: Unable to select dropdown item

I'm unable to select the dropdown.
The code for the dropdown is
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr class="navigatorTable">
<td nowrap="" align="left">
<span class="dropdownbutton showSingle bound">
<a><img class="vAlignSub" src="/images/add.gif"> Create Account <img src="../../images/actionitems_collapse.gif"></a>
</span>
</td>
</tr>
</tbody>
</table>
And in python I have the following code.
select = Select(driver.find_element_by_xpath("//span[#class='dropdownbutton show fork']")).click()
select.select_by_value('1')
But I'm getting
selenium.common.exceptions.NoSuchElementException: Message: no such element:
Unable to locate element: {"method":"xpath",
"selector":"//span[#class='dropdownbutton showSingle bound']"}
Please help me with the code. Thanks
You can't use the Select in this case as though the class name says it's a drop down but it's span not an select html node. So, you can't use Select approach here.
You have to make sure the script waits until the span element is loaded.
#Imports required
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as E
Now get the element and click on it (check the xpath)
ele = WebDriverWait(driver,30).until(EC.presence_of_element_located((By.XPATH,"//span[#class='dropdownbutton showSingle bound']//img")))
ele.click()

Unable to locate element error while trying to locate an input box element using Selenium through Python

I´m trying to find a text box with Python and Selenium.. I Tried by_css_selector, bY XPATH, by ID, by name but the message is always the same:
Unable to locate element: #x-auto-225-input
this is the piece of html. I Want to find the textbox to fill it.
<td class="x-table-layout-cell" role="presentation" style="padding: 2px;">
<div role="presentation" class=" x-form-field-wrap x-component" id="x-auto-225" style="width: 150px;"></div>
<input type="text" class=" x-form-field x-form-text " id="x-auto-225-input" name="PURCHASE_ORDER_CODE_NAME" tabindex="0" style="width: 150px;">
</td>
My last attempt was:
pc = browser.find_element_by_css_selector("#x-auto-225-input").click()
pc.send_keys("7555425-1")
Looking at the html, id mentioned can be dynamic, so you can't put the static id in your identifier.
However, as name attribute is present in the html, you can use that to identify your element, like:
browser.find_element_by_name("PURCHASE_ORDER_CODE_NAME").click()
Updated answer as per discussion with the OP
As an iframe is present on the UI, you need to first switch to the iframe and then click on the element.
To switch to iframe you can use:
browser.switch_to.frame(browser.find_element_by_tag_name('iframe'))
and then use:
pc = browser.find_element_by_name("PURCHASE_ORDER_CODE_NAME")
pc.click()
pc.send_keys("7555425-1")
if you want to switch back to the default content, you can use:
browser.switch_to.default_content()
The desired element is a dynamic element so to invoke click() on the element you have to induce WebDriverWait for the element to be clickable and you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input.x-form-field.x-form-text[id$='-input'][name='PURCHASE_ORDER_CODE_NAME']"))).click();
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[#class=' x-form-field x-form-text ' and contains(#id,'-input')][#name='PURCHASE_ORDER_CODE_NAME']"))).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
Maybe you can try another "selector" approach. Ex(Javascript):
selenium.By.xpath('//*[#data-icon="edit"]')
driver.findElement(by).click()

Resources