Clarification on relative xpath - selenium

I want an xpath which represents the element 2 w.r.t element 1, as shown in the picture below. Can I build it using following-sibling?
Any help appreciated.
<div id="leads_data" class="uk-width-large-8-12 uk-container-center">
<div class="md-card-list leads_cards_list">
<ul class="">
<li class="item-shown" style="margin: 40px -20px; min-height: 90px;">
<div class="md-card-list-item-menu" data-uk-dropdown="{mode:'click',pos:'bottom-right'}">
<span>12:35:22 PM</span>
<a class="md-btn md-btn-flat md-btn-wave waves-effect waves-button" onclick="showModal(446)" data-uk-modal="{ center:true }" href="#lead_info">Edit</a>
</div>
<div class="md-card-list-item-sender">
<span>
<i class="material-icons">face</i>
CDYCUQYGNKYNFNFCWOUO
</span>
</div>
<div class="md-card-list-item-sender">
<span>
<i class="material-icons">call</i>
+91-1119771441
</span>
</div>
<div class="md-card-list-item-subject">
<span>
<i class="material-icons">email</i>
rnkntsoorh#jd.com
</span>
</div>
<div class="md-card md-card-list-item-content-wrapper uk-margin-top" onclick="showModal(446)" style="display: block; opacity: 1;">
<div class="md-card-content leads_card_content">
<div class="uk-text-large uk-margin-remove">
<b>Remarks:</b>
Some remarks of TSYNTORSAC
</div>
</div>
</div>
<br/>
</li>
I want to start with div having the text "CDYCUQYGNKYNFNFCWOUO" and locate the div having the text "Some remarks of TSYNTORSAC".

You can use below xPath :-
//span[contains(.,'CDYCUQYGNKYNFNFCWOUO')]/parent::div/following::div[contains(.,'Some remarks of TSYNTORSAC')][last()]
or
//span[contains(.,'CDYCUQYGNKYNFNFCWOUO')]/parent::div/following::div[contains(.,'Some remarks of TSYNTORSAC') and contains(#class, 'uk-text-large uk-margin-remove')]
or
//span[contains(.,'CDYCUQYGNKYNFNFCWOUO')]/parent::div/following-sibling::div[contains(.,'Some remarks of TSYNTORSAC')]/descendant::div[contains(#class, 'uk-text-large uk-margin-remove')]
or
//span[contains(.,'CDYCUQYGNKYNFNFCWOUO')]/parent::div/following-sibling::div[contains(.,'Some remarks of TSYNTORSAC')]/div/div
Hope it will help you..:)

In addition to the ways described by Saurabh gaur you can also use following-sibling to locate the desired element.
.//span[text()='CDYCUQYGNKYNFNFCWOUO']/../following-sibling::div[position()=3]//div[contains(.,'Some remarks of TSYNTORSAC')]
or
.//span[text()='CDYCUQYGNKYNFNFCWOUO']/../following-sibling::div[position()=3]/div/div[contains(text(),'Some remarks of TSYNTORSAC']
Hope this helps

You could simply get the element containing the desired text instead of using following:
//li[div[normalize-space(.)='face CDYCUQYGNKYNFNFCWOUO']]/div[last()]

try this :-
//div[contains(#class,'md-card-list-item-sende') and contains(.,'CDYCUQYGNKYNFNFCWOUO')]/following::div[contains(#class,'md-card-list-item-content') and descendant::b[contains(.,'Remarks')]]

Related

How to clean up pulled data from BeautifulSoup, Pandas, Python

Hello everyone I have the information I want pulled using BeautiuflSoup but I can't seem to get it printed out correctly to send to pandas and excel.
html_f ='''
<li class="list-group-item">
<div>
<div class="tyler-toggle-controller open">
<p class="text-primary">
07/01/2022 Date
<span class="caret"> </span>
</p>
</div>
<div class="tyler-toggle-container row-buff" style="display: block; overflow: hidden;">
<p class="col-sm-12 col-md-12">
<span class="text-muted">Comment</span><br>
[1] Comments
</p>
</div>
</div>
</li>'''
My code used to pull the data I want:
soup = BeautifulSoup(html_f,'html.parser')
for child in soup.findAll('li',class_='list-group-item')[0]:
print (child.text)
Here is the info it pulls But it prints it out weird with tons of spacing
07/01/2022 Date
Comment
[1] Comments
Ideally, I only need the top portion of (date and File Date) printed out but at the very least I need help getting it into a list format like:
07/01/2022 Date
Comment
[1] Comments
To get your information printed as expected in your question, you could use stripped_strings and iterate over its elements:
for e in soup.find_all('li',class_='list-group-item'):
for t in list(e.stripped_strings):
print(t)
Note: In new code use find_all() instead of old syntax findAll().
Example
html='''
<li class="list-group-item">
<div>
<div class="tyler-toggle-controller open">
<p class="text-primary">
07/01/2022 Date
<span class="caret">
</span>
</p>
</div>
<div class="tyler-toggle-container row-buff" style="display: block; overflow: hidden;">
<p class="col-sm-12 col-md-12">
<span class="text-muted">
Comment
</span>
<br/>
[1] Comments
</p>
</div>
</div>
</li>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html)
for e in soup.find_all('li',class_='list-group-item'):
for t in list(e.stripped_strings):
print(t)
Output
07/01/2022 Date
Comment
[1] Comments
Not sure cause you are talking about pandas, you also could pick each information, clean it up and append to a list of dicts:
data = []
for e in soup.find_all('li',class_='list-group-item'):
data.append({
'date': e.p.text.strip().replace(' Date',''),
'comment': e.select_one('.tyler-toggle-container br').next_sibling.strip()
})
pd.DataFrame(data)
or
data = [{
'date':soup.select_one('li.list-group-item .text-primary').text.strip().replace(' Date',''),
'comment':soup.select_one('li.list-group-item .tyler-toggle-container br').next_sibling.strip()
}]
Output
date
comment
07/01/2022
[1] Comments
So far so good, it's my trying
doc='''
<li class="list-group-item">
<div>
<div class="tyler-toggle-controller open">
<p class="text-primary">
07/01/2022 Date
<span class="caret">
</span>
</p>
</div>
<div class="tyler-toggle-container row-buff" style="display: block; overflow: hidden;">
<p class="col-sm-12 col-md-12">
<span class="text-muted">
Comment
</span>
<br/>
[1] Comments
</p>
</div>
</div>
</li>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(doc, 'html.parser')
text=[' '.join(child.get_text(strip=True).split(' ')).replace(' DateComment[1]',',') for child in soup.find_all('li',class_='list-group-item')]
print(text)
Output:
['07/01/2022, Comments']
Try this ways,must work
text=' '.join([' '.join(child.get_text(strip=True).split(' ')).replace(' DateComment[1]',',') for child in soup.find_all('li',class_='list-group-item')]).strip()
#Or
text= [' '.join(child.get_text(strip=True).split(' ')).replace(' DateComment[1]',',') for child in soup.find_all('li',class_='list-group-item')]
final_text= text[1]+ ',' +text[2]
final_text= text[1]+text[2].split()#if you want to make list

how to select nth item from a CSS selector

[data-short-caption="itemName" i] .circle-base,
this selector is identifying two items in the DOM, I need to select the second item, is there any way like we have in xpath to select the second item ?
The HTML Structure is something like this :
<div class="selection" data-select-item="select-item">
<div data-short-caption='itemName'>
<div class=circle-base> </div>
</div>
<div data-short-caption='itemName'>
<div class=circle-base> </div>
</div>
</div>
As per the HTML:
<div class="selection" data-select-item="select-item">
<div data-short-caption='itemName'>
<div class=circle-base> </div>
</div>
<div data-short-caption='itemName'>
<div class=circle-base> </div>
</div>
</div>
To identify only the second item you can use either of the following css-selectors based Locator Strategy:
Using nth-child():
div.selection div:nth-child(2) > div.circle-base
Using nth-of-type():
div.selection div:nth-of-type(2) > div.circle-base
If I could correctly understand your query, there are several ways to achieve it via css pseudo-selectors. Please check the code if it helps.
/*Method 1 : using last-of-type pseudo-selector*/
[data-short-caption="itemName" i]:last-of-type .circle-base{
background-color: #efefef;
}
/*Method 2 : using last-child pseudo-selector*/
[data-short-caption="itemName" i]:last-child .circle-base{
background-color: #efefef;
}
/*Method 3 : using nth-of-type pseudo-selector*/
[data-short-caption="itemName" i]:nth-of-type(2) .circle-base{
background-color: #efefef;
}
/*Method 4 : using nth-child pseudo-selector*/
[data-short-caption="itemName" i]:nth-child(2) .circle-base{
background-color: #efefef;
}
<div class="selection" data-select-item="select-item">
<div data-short-caption='itemName'>
<div class=circle-base> first child </div>
</div>
<div data-short-caption='itemName'>
<div class=circle-base> second child </div>
</div>
</div>

How can I find the dynamic xpath for the word "Pace" in the attached?

I need the dynamic xpath for the the word "Pace" in the below code It is the the name of the third column in a table.
I have tried the following:
//table[contains(#class,'data-grid-table data-grid-fixed-row-table')]//span[contains(#class,'lightning-table-cell-measure-header-value')][contains(text(),'Pace')]
but this seems to be too long of a locator for my test. Is there a shorter dynamic xpath locator that I can use? Here is the snippet of the code that contains the word:
<th data-row-index="0" data-column-index="0" data-fixed-row="true" data-fixed-column="false" aria-selected="false" aria-hidden="false" id="data-grid-24-fixedrow0-col0" class="data-grid-table-cell data-grid-table-cell-start data-grid-header-cell" tabindex="0">
<div class="data-grid-table-cell-box" style="height: 17px;">
<div class="wave-table-cell-measure-header">
<span class="wave-table-cell-measure-header-text" data-tooltip="Pace" data-tooltip-on-truncation="true">
<span class="lightning-table-cell-measure-header-value" tabindex="-1">
<span class="header-icon-container">
<span class="slds-icon_container">
<svg aria-hidden="true" class="header-icon-sprite slds-icon">
<use xlink:href="/images/sprite.analytics.svg#formula"></use>
</svg>
<span class="slds-assistive-text">
Formula
</span>
</span>
</span>
Pace
</span>
</span>
</div>
</div>
<div class="data-grid-resize-slider" style="position: absolute; width: 0px; height: 0px;">
<input class="data-grid-resize-slider-input" aria-label="Pace Column Width: 115" type="range" tabindex="-1" min="35" max="1000" value="115">
</div>
</th>
The issue may be with the double [][] notation you are using for your //span element at the end. I've never seen that type of XPath syntax before, and I've always grouped queries into a single set of [].
You can use the following XPath:
//th/div/div//span[contains(text(), 'Pace']
This will get you the span element containing text 'Pace'.
If you just want to fix your existing XPath syntax, this might work too:
//table[contains(#class,'data-grid-table data-grid-fixed-row-table')]//span[contains(text(),'Pace') and contains(#class,'lightning-table-cell-measure-header-value')]
I've combined your last two queries into one using and operator.

Autocomplete with Selenium

I'm having some (actually, a lot) of trouble automating selection from autocomplete options with Selenium. Currently, I am able to automate the inputting of the text, though, I am not able to select anything from the appearing drop-down suggestions list that pops up. I tried searching here for some answers to my problem, but nothing has worked. Below is the element that appears with the suggestions that I am trying to select:
<div class="cs-autocomplete-popup">
<div class="inner">
<div class="cs-autocomplete-Matches csc-autocomplete-Matches">
<ul>
<li class="cs-autocomplete-matchItem csc-autocomplete-matchItem">
<span class="csc-autocomplete-matchItem-content cs-autocomplete-matchItem-content" id="matchItem::matchItemContent">john doe</span>
</li>
</ul>
</div>
<div class="csc-autocomplete-addToPanel cs-autocomplete-addToPanel">
<hr>
<div class="content csc-autocomplete-addTermTo cs-autocomplete-addTermTo">Add "John Doe" to:</div>
<ul>
<li class="cs-autocomplete-authorityItem csc-autocomplete-authorityItem" id="authorityItem:">Local Persons</li>
</ul>
</div>
</div>
<div class="cs-autocomplete-popup-miniView csc-autocomplete-popup-miniView" style="top: 2px; left: 149px; display: none;"><div class="cs-miniView">
john doe
<div>
<span class="csc-autocomplete-popup-miniView-field1Label cs-autocomplete-popup-miniView-field1Label">b.</span>
<span class="csc-autocomplete-popup-miniView-field1 cs-autocomplete-popup-miniView-field1" id="field1"></span>
</div>
<div>
<span class="csc-autocomplete-popup-miniView-field2Label cs-autocomplete-popup-miniView-field2Label">d.</span>
<span class="csc-autocomplete-popup-miniView-field2 cs-autocomplete-popup-miniView-field2" id="field2"></span>
</div>
<div>
<span class="csc-autocomplete-popup-miniView-field3 cs-autocomplete-popup-miniView-field3" id="field3"></span>
</div>
<div>
</div>
</div></div>
</div>
From this, I am trying to select "john doe". Does anyone know an efficient/complete way of doing this? I would very much appreciate the help.
driver.findElement(By.xpath("get the exact field address of autocomplete textbox");
Thread.sleep(5000);
//for xpath: need to take the common xpath from the list of the elements.
List<WebElement> link=driver.findElements(By.xpath("//span[contains(#class, 'cs-autocomplete-matchItem-content') and .='john doe']");
for(int i=0; i<=link.size(); i++)
{
if(link.get(i).getText().equalsIgnoreCase("john doe");
{
link.get(i).click();
}
}

Unable to get the values from <p> tag

I should get the values between the p tag.
Following is the code from which i need to get the values
<div id="ved-list-totals">
<div id="ved-sidebar-totals" class="clearfix margin-top-10" style="height: 100px;">
<div id="ved-sidebar-totals" class="clearfix margin-top-10" style="height: 100px; background-color: transparent;">
<div class="pull-right margin-left-20 margin-right-10 align-right">
<p class="no-margin">0</p>
<p class="no-margin" style="background-color: transparent;">5.97</p>
<p class="no-margin">0.00</p>
<p class="no-margin">4.95</p>
<p class="no-margin bold dark-text">10.92</p>
</div>
<div class="pull-right margin-left-20 align-right">
<p class="no-margin">Estimated Points</p>
<p class="no-margin">Subtotal</p>
<p class="no-margin">Tax</p>
<p class="no-margin">Service Fee</p>
<p class="no-margin bold dark-text">Estimated Total</p>
</div>
I have tried the following approaches:
String tot = driver.findElement(By.xpath("html/body/div[4]/table/tbody/tr/td[2]/div/div[1]/div[2]/div/div/div/div[2]/div/div/div[1]/p[2]")).getText();
String axd = driver.findElement(By.xpath("html/body/div[4]/table/tbody/tr/td[2]/div/div[1]/div[2]/div/div/div/div[2]/div/div/div[1]/p[3]")).getText();
String tot = driver.findElement(By.xpath("//div[#id='ecart-sidebar-totals']/div/p[4]")).getText();
String axd = driver.findElement(By.xpath("//div[#id='ecart-sidebar-totals']/div/p[3]")).getText();
I was getting the error as :
org.openqa.selenium.NoSuchElementException: Unable to locate element: {"method":"xpath","selector":"//div[#id='ecart-sidebar-totals']/div/p[4]"}
There are two elements with the same id (<div id="ved-sidebar-totals">) should this id be blamed for this error, or is there any thing which am missing.
Use the xpath //div[#id='ved-list-totals']//p[1]. This should return the first p tag value with getText() method.
Wild guess..
//div[#id='ecart-sidebar-totals']/div[#id='ved-list-totals']/p[1]
Try using Css selector
driver.findElement(By.cssSelector("div[class='pull-right margin-left-20 margin-right-10 align-right'] p:nth-child(4)"));