How to collect information from non identic classes. (Selenium, Python) - python

I want to collect information (name) from website like ebay and append it to the list. But I have a problem.
My code:
for a in driver.find_elements_by_id("scroll"):
name = a.find_element(By.CLASS_NAME(".market-name.market-link")).getText()
mylist.append(name)
print(mylist)
Problem:
name =
a.find_element(By.CLASS_NAME(".market-name.market-link")).getText()
TypeError: 'str' object is not callable
Whats wrong?
Html code (I have deleted unnecessary things, like picters, etc):
<div class="featured-item col-sxs-12 col-xs-6 col-sm-6 col-md-4 col-lg-3 center-block app_730_2 item_17511241 has-wear scanned">
<div>
<a class="market-name market-link" href="=shop_view_item&item=17511241">
Happy
</a>
<div class="item-amount" onclick="showGraphFromId(17511241)">
$0.04
</div>
<button class="btn btn-orange" type="button" onclick="addToCart(17511241, 730, 4)">
Add to Cart
</button>
</div>
</div>

You use an incorrect By. ".market-name.market-link" is Css Selector, not Class name.
So you can solve this by change the By.CLASS_NAME to By.CSS_SELECTOR
By.CLASS_NAME is a first parameter of find_element and it is not a method, it is a value. The second parameter is an expression.
See code below.
try:
name = WebDriverWait(browser, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".market-name.market-link"))
).text
except:
print("Can't find the text.")

Related

How to loop over elements with selenium

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']")])

How to select button inside of multiple classes with selenium python?

I have a page with multiple elements, it's called cards, and on this page I want to click a button on some cards but not on all. The problem is the structure of individual cards because only class of card is different but class inside of cards and button are the same. I'm not sure how to find a right card.
Usually I use something like this, but in this case i want to select certain cards.
browser.find_element(By.CLASS_NAME, 'button-class').click()
But in this case I have something like this...
<div id="card-summer_1">
<div class="card_card">
<div class="card_footer">
<button class="button-class">
<button class="button-share">
</button>
</div>
</div>
</div>
<div id="card-summer_2">
<div class="card_card">
<div class="card_footer">
<button class="button-class">
<button class="button-share">
</button>
</div>
</div>
</div>
<div id="card-summer_3">
<div class="card_card">
<div class="card_footer">
<button class="button-class">
<button class="button-share">
</button>
</div>
</div>
</div>
How to click on button on id id="card-summer_1" and id="card-summer_3"?
Thanks in advance!
EDIT
There are two buttons, I want to click on a class button-class.
Find elements instead by CSS selector:
driver.find_element(By.CSS_SELECTOR, ".card-summer_1 .button-class")
By XPATH:
driver.find_element(By.XPATH, "//div[#id='card-summer_1']//button"]).click()
driver.find_element(By.XPATH, "//div[#id='card-summer_3']//button"]).click()
By CSS_SELECTOR:
driver.find_element(By.By.CSS_SELECTOR, ".card-summer_1 button").click()
driver.find_element(By.By.CSS_SELECTOR, ".card-summer_3 button").click()

Selenium how to select last link in a body?

I have a html page like below
<body>
<div>
<a class="btn btn-info" href="a.php">A</a>
<a class="btn btn-info" href="b.php">B</a>
<a class="btn btn-info" href="c.php">C</a>
<a class="btn btn-info" href="d.php">D</a>
</div>
<a class="btn btn-info" href="f.php">F</a>
</body>
I need to select last link F. I have tried like below
link = driver.find_element_by_xpath("//a[last()]")
It's selecting D
I also tried below way
email = driver.find_element_by_xpath("/body//a[last()]")
In this time unable to locate element. How can I get last link here in an easy way ?
To get the last element. Try following xpath.
link = driver.find_element_by_xpath("(//a)[last()]")
use the driver.findElements() method and put the return value in an array.
The last link will be the last element of the array.
I suggest you to (for various reasons):
do yourArray = driver.findElements(By.tag("a"))
for every element check if the href attribute is not null with element.getAttribute("href") != null and update a myIndex var if it's not
The element at the index "myIndex" of "yourArray" will be the element you're searching for.

How can I find an element looping through a list of divs using Selenium?

In an HTML file structured like this:
<div class="card">
<div class="id">
ID: 123456
</div>
<div class="title">
Title 1
</div>
<div class="description">
Description 1
</div>
</div>
<div class="card">
<div class="id">
ID: 89123
</div>
<div class="title">
Title 2
</div>
</div>
Let's say that I have a variable number of divs with the class "card", using Selenium I would like to loop through these divs and if there is div with the class description, I would like to print his text.
I tried to do something like code below, but using find_element_by_xpath. I will always get the first element that has the class "description". How can I fix this and properly-getting elements by looping through divs? Thanks a lot.
cards = webdriver.find_elements_by_xpath("//div[#class='main-div']")
for card in cards:
try:
description = card.find_element_by_xpath("//div[#class='description']")
print(description.text)
except:
print("No description")
You need to get all divs with class "card" and search the div "description" inside them:
cards = webdriver.find_elements_by_css_selector(".card")
for card in cards:
try:
description = card.find_element_by_css_selector(".description")
print(description.text)
except:
print("No description.")
PS: Or change your first XPath to //div[#class='card'] and second XPath to .//div[#class='description'] as proposed guys from another answers.
I hope it helps you!
Just use . for intermediate child tag.So it should be like that
card.find_element_by_xpath(".//div[#class='description']")
Code here:
cards = webdriver.find_elements_by_xpath("//div[#class='card']")
for card in cards:
try:
description = card.find_element_by_xpath(".//div[#class='description']")
print(description.text)
except:
print("No description")
You can do this with one locator and a single loop.
for description in driver.find_elements_by_css_selector("div.card > div.description"):
print(description.text)
NOTE: If you want a fix for your current code, you are just missing the self . axis in your second XPath. Change "//div[#class='description']" to ".//div[#class='description']" to indicate that you want to start searching at the current card element.
For more info on the self axis, see mdn which has a lot of great XPath and CSS selector related info.

How to click/submit onclick values in Python

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")]]

Categories