How to find element in selenium - html

I want to find the element "Holiday4" in span class="fc-title". How to do it? Do i need to use css selector or do I need to use xpath?
<tr>
<td class="fc-day-number fc-sun fc-future hp-cal-selected" data-date="2016-02-14">14</td>
<td class="fc-day-number fc-mon fc-future" data-date="2016-02-15">15</td>
<td class="fc-day-number fc-tue fc-future" data-date="2016-02-16">16</td>
<td class="fc-day-number fc-wed fc-future" data-date="2016-02-17">17</td>
<td class="fc-day-number fc-thu fc-future" data-date="2016-02-18">18</td>
<td class="fc-day-number fc-fri fc-future" data-date="2016-02-19">19</td>
<td class="fc-day-number fc-sat fc-future" data-date="2016-02-20">20</td>
</tr>
<tr>
<td class="fc-event-container">
<a class="fc-day-grid-event fc-h-event fc-event fc-start fc-end holiday" style="color:65280" title="Holiday">
<div class="fc-content">
<span class="fc-title">Holiday4</span>
</div>
</a>

Use cssSelector
.fc-content [div:contains('Holiday 4')]
Also check this out
Need to find element in selenium by css
https://saucelabs.com/selenium/css-selectors

If to use Python:
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('http://your_url.com')
element = driver.find_element_by_xpath('//span[#class="fc-title"][contain(text(),"Holiday 4")]')

Use Below Xpath,
//span[#class='fc-title'][.='Holiday4']

To get the Text of "Holiday4" you can find it by the following.
Using Css Selector:
string str = driver.FindElement(By.CssSelector("[class='fc-title']")).Text;
Using XPath:
string str = driver.FindElement(By.Xpath("tr/td/a/div/span")).Text;

Related

Beautiful soup finding the first sibling of a known object with a known attribute

I have the following code to select a certain cell in a table element:
tag = soup.find_all('td', attrs={'class': 'I'})
as shown in the attached image 1, I would like to somehow be able to find its first sibling within the same class "even_row". Ideally, the selection would output only the contents of data-seconds, in this case "58". Not every "even_row" class has a element with class I, and some have more than one, so I need to get the value data-seconds only for the "even_row" classes that have the element with class "I"
Any help would be appreciated as I've been banging my head on the wall looking through documentation to no avail.
html look like :
<tr class='even_row'>
<td class='row_labels' data-seconds="58">
<div class='celldiv slots1'></div>
</td>
<td class='new'>...</td>
<td class='I'>...</td>
<td class='new'>...</td>
<td class='new'>...</td>
One way to get around that issue is to pass True
from bs4 import BeautifulSoup
html = """
<tr class='even_row'>
<td class='row_labels' data-seconds="58">
<div class='celldiv slots1'></div>
</td>
<td class='new'>...</td>
<td class='I'>...</td>
<td class='new'>...</td>
<td class='new'>...</td>
</tr>
<tr class='even_row'>
<td class='row_labels' >
<div class='celldiv slots1'></div>
</td>
<td class='new'>...</td>
<td class='I'>...</td>
<td class='new'>...</td>
<td class='new'>...</td>
</tr>
"""
soup = BeautifulSoup(html,'html.parser')
even_rows = soup.find_all('tr', attrs={'class': 'even_row'})
for row in even_rows:
tag = row.find("td", {"data-seconds" : True})
if tag is not None:
print(tag.get('data-seconds'))
Output :
58
another way to do it is using regular expressions
import re
tds = [tag.get('data-seconds') for tag in soup.findAll("td", {"data-seconds" : re.compile(r".*")})]
print(tds)
Output :
['58']
Cannot test properly without the html but sounds like with bs4 4.7.1+ you can use :has to satisfy your requirements for .even_row:has(.I) i.e. parent with class even_row, having child with class I, and then add in [data-seconds] to cater for all child data-seconds attribute values
print([i['data-seconds'] for i in soup.select('.even_row:has(.I) [data-seconds]')])

XPath for a span based on its text?

I am unable to locate first span with XPath I tried:
//*[#id='student-grid']/div[2]/div[1]/table/tbody/tr[1]/td/span/span[contains(text(), 'Edit School')]
to select span with text - Edit Student button
<tbody role="rowgroup">
<tr class="" data-uid="2f3646c6-213a-4e91-99f9-0fbaa5f7755d" role="row" aria-selected="false">
<td class="select-row" role="gridcell">
<td class="font-md" role="gridcell">marker, Lion</td>
<td role="gridcell">TESTLINK_1_ArchScenario</td>
<td role="gridcell">1st</td>
<td role="gridcell">Not Started</td>
<td role="gridcell"/>
<td role="gridcell"/>
<td role="gridcell">QA Automation TestLink Folders</td>
<td class="k-cell-action" role="gridcell"/>
<td class="k-cell-action detail-view-link font-md" role="gridcell">
<span class="button-grid-action kendo-lexia-tooltip icon-pencil" role="button" title="Edit Student">
<span>Edit Student</span>
</span>
</td>
<td class="k-cell-action archive-link font-md" role="gridcell">
<span class="button-grid-action kendo-lexia-tooltip icon-archive" role="button" title="Archive Student">
<span>Archive Student</span>
</span>
</td>
</tr>
</tbody>
If you want to select span with text - Edit Studen try any of this:
//span[#title='Edit Student']/span
//span[text()='Edit Student']
If you want to select Edit Studen with role="button" try any of this:
//span[#title='Edit Student'][#role='button']
//span[#role='button'][./span[text()='Edit Student']]
//span[#role='button'][./span[.='Edit Student']]
simply use can use any of this xpaths
//span[contains(text(),'Edit Student')]
//*[contains(text(),'Edit Student')]
//span [#class='button-grid-action kendo-lexia-tooltip icon-pencil']/span
//span [#title='Edit Student']/span
//span [contains(#title,'Edit Student')]/span
//span [contains(#class,'button-grid-action kendo-lexia-tooltip icon-pencil')]/span
To select the outer span, this XPath,
//span[#role='button' and normalize-space()='Edit School']
will select span elements with a button #role and a normalized string value of Edit School.
To select the inner span, this XPath,
//span[text()='Edit School']
will select span elements with an immediate text node child whose value is Edit School.
You can, of course, further qualify the heritage in either case as needed.
See also
Testing text() nodes vs string values in XPath
This should get the span text
//span[.='Edit Student']

Unable to select multiple values using xpath

Here is my HTML code:
<table id="laptop_detail" class="table">
<tr>
<td style="padding-left:18px" class="ha">Touchscreen</td>
<td class="val"><span class="no_icon">No</span></td>
</tr>
<tr>
<td style="padding-left:18px" class="ha">Water Dispenser</td>
<td class="val"><span class="no_icon">No</span></td>
</tr>
<tr>
<td style="padding-left:18px" class="ha">Colour / Material</td>
<td class="val">Grey</td>
</tr>
</table>
Here is my xpath:
$x('//*[#id="laptop_detail"]//tr/td[contains(. ,"Touchscreen")]/following-sibling::td[1]/span/text() and //*[#id="laptop_detail"]//tr/td[contains(. ,"Water Dispenser")]/following-sibling::td[1]/span/text() and //*[#id="laptop_detail"]//tr/td[contains(. ,"Colour")]/following-sibling::td[1]/text()')
But my xpath returns "true" instead of my requirement "No, No, Grey". I know there is something wrong with my xpath but i am unable to understand it.
EDIT: Okay i had a little success, I was able to get "No, No" using this xpath:
$x('//*[#id="laptop_detail"]//tr/td[contains(. ,"Touchscreen") or contains(. ,"Water")]/following-sibling::td[1]/span/text()')
but unable to get "Grey" as that value is not inside span tag.
Here is a fix to your solution (I've added | operator):
//*[#id="laptop_detail"]/tr/td[contains(. ,"Touchscreen") or contains(. ,"Water")]/following-sibling::td[1]/span/text() | //*[#id="laptop_detail"]/tr/td[contains(. ,"Colour / Material")]/following-sibling::td[1]/text()
You can use little bit more easy syntax (run faster) if it is acceptable for your logic.
/table[#id="laptop_detail"]/tr/td[#class='val']/span/text() | /table[#id="laptop_detail"]/tr/td[#class='val']/text()

Xpath select element based on 2 child element conditions

Here is the html code:
<table>
<tr class="WhiteRow">
<td align="center">
<input id="SelectedDelivery1" type="checkbox" onclick="HandleClick(this.name,this.checked,"")" value="Y" name="SelectedDelivery1">
</td>
<td valign="top">
<span></span>
<span class="bold">Instrument Search</span>
<br>
abc (TRANSFER)
</td>
<td align="center">5 minutes</td>
<td class="noborder" align="right">
<td class="noborder" align="right">
<td class="noborder" align="right">
<td class="noborder" align="right">
</tr>
<tr>
<td align="center">
<input id="SelectedDelivery2" type="checkbox" onclick="HandleClick(this.name,this.checked,"")" value="Y" name="SelectedDelivery1">
</td>
<td valign="top">
<span></span>
<span class="bold">Instrument Search</span>
<br>
abc (CAVEAT)
</td>
...
</tr>
</table>
I would like to target the <tr> containing <span class="bold">Instrument Search</span> and abc (TRANSFER). That tr may not be the first element in the table.
So far I tried
//td/span[text()="Instrument Search"]/ancestor::tr
which only satisfy one of the condition, and there are a few tr that satisfy the selector.
Could you please advise me how to target both of them
Use the following XPath expression:
//tr[contains(., 'abc (TRANSFER)') and contains(td/span[#class = 'bold'], 'Instrument Search')]
If possible, you should always use expressions that are unidirectional, because a "backwards" axis like ancestor:: could be a costly move. That's the advantage over the solution you have found already.
If the span[#class = 'bold'] cannot contain anything else than "Instrument Search", you should modifiy the expression above to:
//tr[contains(., 'abc (TRANSFER)') and td/span[#class = 'bold'] = 'Instrument Search']
The location of "abc (TRANSFER)" is still not very precise, if it is required in a certain place (e.g. always inside a td element) you'd have to further restrict the above.
EDIT Respondin to your comment:
abc (TRANSFER) is inside td tag, it's just a text field
Then use
//tr[contains(td, 'abc (TRANSFER)') and td/span[#class = 'bold'] = 'Instrument Search']
I found myself an answer after crawling through the syntax.
Please let me know if there is any other better ways
//td/span[text()="Instrument Search"]/ancestor::td/text()[contains(., "TRANSFER")]/ancestor::tr

Repeating an HTML snippet that contains elements with id attribute defined

I need to repeat an html snippet several times on a page but the problem is that the contained html elements have id defined that should be unique on page. So what is the proper way I could repeat this snippet without removing the id attribute from the elements ?
Could I use iframe as container for this snippet & let the duplicate ids exist on page?
You can use JavaScript to clone the snippet and at the same time change the IDs.
Example if your snippet is:
<div id="snippet">
<table id="list">
<tr id="0">
<td id="firstName0">John</td>
<td id="lastName0">Smith</td>
</tr>
<tr id="1">
<td id="firstName2">John</td>
<td id="lastName2">Doe</td>
</tr>
</table>
</div>
Using
$("#snippet").clone(false).find("*[id]").andSelf().each(function() { $(this).attr("id", $(this).attr("id") + "_1"); });
Will Produce
<div id="snippet_1">
<table id="list_1">
<tr id="0_1">
<td id="firstName0_1">John</td>
<td id="lastName0_1">Smith</td>
</tr>
<tr id="1_1">
<td id="firstName2_1">John</td>
<td id="lastName2_1">Doe</td>
</tr>
</table>
</div>
Which will solve the duplicate ID problem.