I have a question about the Selenium Python code I'm writing.
The website has a bunch of time slots, and I'm trying to simulate a mouse click, specifically targeting the 8:30-11:30 timeslot.
Here is a snippet the html:
<div class="item-link" onclick="$('#SelectedStartTime').val('2015/10/16 08:30:00');$('#frmTimes').submit();">
<div class="item">
<div class="title">8:30 AM-11:30 AM
<span class="available">(Spaces: <strong class="num">20</strong>)</span>
</div>
</div>
</div>
<div class="item-link" onclick="$('#SelectedStartTime').val('2015/10/16 09:00:00');$('#frmTimes').submit();">
<div class="item">
<div class="title">9:00 AM-12:00 PM
<span class="available">(Spaces: <strong class="num">20</strong>)</span>
</div>
</div>
</div>
</body>
</html>
I've tried targeting the "8:30 AM-11:30 AM" text,
Time0830 = driver.find_elements_by_class_name("title")
for each in Time0830:
if "8:30 AM-11:30 AM" in each.text:
each.click()
break
for each in Time0830:
if each.text == "8:30 AM-11:30 AM"
each.click()
break
Both do not do anything.
I've also tried targeting the onclick based on this question.
Time0830 = driver.find_element_by_xpath('.//div[contains(#onclick,"8:30 AM-11:30 AM")]')
print (Time0830)
Time0830.click()
This resulted in Error: NoSuchElementException
Time0830 = driver.find_element_by_css_selector("div[onclick*='8:30 AM-11:30 AM']")
print(Time0830)
Time0830.click()
This also resulted in Error: NoSuchElementException.
What do I need to do to get this to work?
EDIT!!
Thanks for the help on xpath help. I think the problem was also that I could not get it to click.
I've been using .click(), but it's not working any more.
My code is now:
time.sleep(1.5)
Time0830 = driver.find_element_by_xpath('//div[#class = "item-link" and .//div[#class = "title" and contains(text(),"8:30 PM-11:30 PM")]]').click()
But the page does not move, still. I have time.sleep to account for loading time.
I've tried it without the click() and it seems to find an element. Am I finding the wrong element, or using the wrong function?
How about you would match a div with item-link class that has a descendant div element having 8:30 AM-11:30 AM text:
//div[#class = "item-link" and .//div[#class = "title" and contains(., "8:30 AM-11:30 AM")]]
Related
I want to use selenium to loop over a few divs on a webpage and find the content of the divs
The basic setup of the webpage looks like this:
<html>
<div data-testid="property-card">
<div data-testid="title">content 1</div>
</div>
<div data-testid="property-card">
<div data-testid="title">content 2</div>
</div>
<div data-testid="property-card">
<div data-testid="title">content 3</div>
</div>
</html>
and here is my code:
def report_results(self):
hotel_boxes = self.find_elements(By.XPATH, '//div[#data-testid="property-card"]')
for hotel in hotel_boxes:
hotel_name = hotel.find_element(By.XPATH, '//div[#data-testid="title"]').get_attribute('innerHTML')
print(hotel_name)
However, the problem is that this only prints "content 1" for three times. What am I doing wrong here?
You are almost there, the only 1 thing you are missing is a dot . at the front of XPath expression.
It should be
hotel_name = hotel.find_element(By.XPATH, './/div[#data-testid="title"]').get_attribute('innerHTML')
When using '//div[#data-testid="title"]' XPath expression it will search for the matching locator from the top of the page until it finds the first match.
While when we have that dot . it means to start searching inside the current node i.e. inside the parent element hotel
So, your entire code can be:
def report_results(self):
hotel_boxes = self.find_elements(By.XPATH, '//div[#data-testid="property-card"]')
for hotel in hotel_boxes:
hotel_name = hotel.find_element(By.XPATH, './/div[#data-testid="title"]').get_attribute('innerHTML')
print(hotel_name)
As per the given HTML:
<html>
<div data-testid="property-card">
<div data-testid="title">content 1</div>
</div>
<div data-testid="property-card">
<div data-testid="title">content 2</div>
</div>
<div data-testid="property-card">
<div data-testid="title">content 3</div>
</div>
</html>
To print the innerText of the descendant <div> tags you can use list comprehension and you can use either of the following locator strategies:
Using CSS_SELECTOR and text attribute:
print([my_elem.text for my_elem in driver.find_elements(By.CSS_SELECTOR, "div[data-testid='property-card'] > [data-testid='title']")])
Using XPATH and .get_attribute('innerHTML'):
print([my_elem..get_attribute('innerHTML') for my_elem in driver.find_elements(By.XPATH, "//div[#data-testid='property-card']/div[#data-testid='title']")])
I have a HTML code like :
<div class="A">
<div class="B"></div>
<div class="B">
<div class="C"></div>
<div class="C">
<p class="D"> Element 1 </p>
<div class="C"></div>
</div>
</div>
<div class="A">
<div class="B"></div>
<div class="B">
<div class="C"></div>
<div class="C">
<p class="D"> Element 2 </p>
<div class="C"></div>
</div>
</div>
(this is an example, there is more class "A")
I want to extract the text "Element 2" with Python Selenium.
I tried a lot of things but always the same result : No such element: Unable to locate element...
I tried :
elem = driver.find_element_by_xpath("//div[#class='A:last-child']/p[#class='D']").text
same result...
Try this:
"(//div[#class='A']//p)[2]"
This should get the second instance of Class = "A" and then the p element beneath that
Try this xpath:
"(//div[#class='A']//p)[last()]"
The main problem with your xpath, I think, is that the single slash before the p element means to only look for direct children of the div. You want the double slash to find any descendant.
In this structure Xpath
(//div[#class="A"]//p[#class="D"])[2]
if this is a second hierarchy or
(//div[#class="A"]//p[#class="D"])[last()]
if it is a last should work
XPATH newbie... I am trying to find text, then find the following button in a code block like below.
The ember numbers change so can't use those. Need to find text within a span, then the next (following) button after that text is found. Then click on that button. In this case it's a contact button.
I've tried:
//*[text()[contains(.,'Jason')]]/div/div/button
Also tried:
//*[text()[contains(.,'Jason')]]/following-sibling::button
A code block example I am trying to search.
<div data-test="e-list-item" data-e-id="Fdh348uF" class="material-list-tile e-list-item">
<div class="e-name">
<a href="/embed/Gdfsdjfhd25d88/gallery/Fdh348uF" id="ember2539" class="ember-view"> <span data-test="e-name">Jason Alamoa</span>
</a><!----> </div>
<!----> <div id="ember2539" class="c-info ember-view"> <div class="c-icons">
<!---->
<!---->
<!---->
<!---->
</div>
</div>
<div class="e-actions">
<div class="e-action-buttons">
<!----> <div class="e-action">
<button class="ssButton ssButtonPrimary v-button v " type="button" data-ember-action="" data-ember-action-2540="2540">
<i class="ssIcon-ok-sign ssIcon-large"></i>
Contact
</button>
<!---->
</div>
</div>
</div>
</div>
Based on HTML snippet provided following XPath could be used:
//div[./a/span[contains(.,'Jason')]]/following::div[#class="e-actions"]//button
Explanation:
//div[./a/span[contains(.,'Jason')]] => selects "div" with child "a" containing child "span" containing text "Jason"
/following::div[#class="e-actions"] => selects following "div" after the first one having attribute "class" with value "e-actions"
//button => selects "button" inside of the previous "div"
If you want to find span with specific text and following button, the easiest way
//span[contains(text(), 'Jason')]/following::button
I'm trying to parse the follow HTML code in python using beautiful soup. I would like to be able to search for text inside a tag, for example "Color" and return the text next tag "Slate, mykonos" and do so for the next tags so that for a give text category I can return it's corresponding information.
However, I'm finding it very difficult to find the right code to do this.
<h2>Details</h2>
<div class="section-inner">
<div class="_UCu">
<h3 class="_mEu">General</h3>
<div class="_JDu">
<span class="_IDu">Color</span>
<span class="_KDu">Slate, mykonos</span>
</div>
</div>
<div class="_UCu">
<h3 class="_mEu">Carrying Case</h3>
<div class="_JDu">
<span class="_IDu">Type</span>
<span class="_KDu">Protective cover</span>
</div>
<div class="_JDu">
<span class="_IDu">Recommended Use</span>
<span class="_KDu">For cell phone</span>
</div>
<div class="_JDu">
<span class="_IDu">Protection</span>
<span class="_KDu">Impact protection</span>
</div>
<div class="_JDu">
<span class="_IDu">Cover Type</span>
<span class="_KDu">Back cover</span>
</div>
<div class="_JDu">
<span class="_IDu">Features</span>
<span class="_KDu">Camera lens cutout, hard shell, rubberized, port cut-outs, raised edges</span>
</div>
</div>
I use the following code to retrieve my div tag
soup.find_all("div", "_JDu")
Once I have retrieved the tag I can navigate inside it but I can't find the right code that will enable me to find the text inside one tag and return the text in the tag after it.
Any help would be really really appreciated as I'm new to python and I have hit a dead end.
You can define a function to return the value for the key you enter:
def get_txt(soup, key):
key_tag = soup.find('span', text=key).parent
return key_tag.find_all('span')[1].text
color = get_txt(soup, 'Color')
print('Color: ' + color)
features = get_txt(soup, 'Features')
print('Features: ' + features)
Output:
Color: Slate, mykonos
Features: Camera lens cutout, hard shell, rubberized, port cut-outs, raised edges
I hope this is what you are looking for.
Explanation:
soup.find('span', text=key) returns the <span> tag whose text=key.
.parent returns the parent tag of the current <span> tag.
Example:
When key='Color', soup.find('span', text=key).parent will return
<div class="_JDu">
<span class="_IDu">Color</span>
<span class="_KDu">Slate, mykonos</span>
</div>
Now we've stored this in key_tag. Only thing left is getting the text of second <span>, which is what the line key_tag.find_all('span')[1].text does.
Give it a go. It can also give you the corresponding values. Make sure to wrap the html elements within content=""" """ variable between Triple Quotes to see how it works.
from bs4 import BeautifulSoup
soup = BeautifulSoup(content,"lxml")
for elem in soup.select("._JDu"):
item = elem.select_one("span")
if "Features" in item.text: #try to see if it misses the corresponding values
val = item.find_next("span").text
print(val)
I need to get div text with class _50x4 using 5pxsel:
<div...>
<i class="5pxsel">
<div>
<div>
<div class="_50x4">
Work in
<a>London</a>
<div class="_50x4">
Work in
<a> Germany </a>
I need to get text using class 5pxsel, not _50x4, and get only first result - 'Work in London'.
trt with following x-path
//*[#class="5pxsel"]/following-sibling::div/div/div[#class='_50x4']