Selenium how to select last link in a body? - python

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.

Related

Getting attribute from button

The problem here is i have a "show more" with infinite scroll, i need to detect when the button opacity becomes 0, or in other words when the button becomes not visible so i can use pagination until the button becomes invisible, which means there's no more info to scrape, i'm talking about over 200 pages to scrape, and no other way to know how many pages are there and use range to iterate the pages, so i need to get the trigger of the opacity attribute. Since the button is always there i can't just use is not None to find the last page.
The button is like this when there are more pages:
<a class="btn btn-primary btn-lg MaisArtigos">SHOW MORE</a>
it turns to this on the last page
<a class="btn btn-primary btn-lg MaisArtigos" style="opacity: 0;">SHOW MORE</a>
I need to trigger when the style attribute is present
I'm using BeautifulSoup and requests library
you can use the Element.getAttribute()
const div1 = document.getElementById('div1');
const exampleAttr= div1.getAttribute('style');
console.log("the attribute is: " + exampleAttr)
<div id="div1" style="opacity:0;">Hi Champ!</div>
well you may want to add an event listener with "scroll" to trigger the get attribute, also if the element has no "style" attribute it will return a NULL, exampleAttr = NULL;
Getting the attribute you can use the css selector:
soup.select_one('a.MaisArtigos[style="opacity: 0;"]')
Checking if the style is set you can use bool() that will give you True if exists and False while not existing:
bool(soup.select_one('a.MaisArtigos[style="opacity: 0;"]'))
Example
To demonstrate, this will only select the styled <a>.
from bs4 import BeautifulSoup
html='''
<a class="btn btn-primary btn-lg MaisArtigos" style="opacity: 0;">SHOW MORE</a>
<a class="btn btn-primary btn-lg MaisArtigos" style="opacity: 100;">SHOW MORE</a>
<a class="btn btn-primary btn-lg MaisArtigos" >SHOW MORE</a>
'''
soup=BeautifulSoup(html,'lxml')
soup.select('a.MaisArtigos[style="opacity: 0;"]')

Find an element with Python Selenium

Somebody can help me to find a way to click on an img with Python Selenium?
I need to find the div class="A" which has a div class="B" and then, click on his img in class="D"
<div class="A">
...
</div>
...
<div class="A">
<div class="B"> <!-- HERE IS WHAT I NEED TO CHECK-->
<span class="E"> <!-- HERE IS WHAT I NEED TO CHECK-->
<span class="F"> <!-- HERE IS WHAT I NEED TO CHECK-->
</div> <!-- HERE IS WHAT I NEED TO CHECK-->
<div class="C"> </div>
<div class="D">
<img class="Y" src="..."> <!-- HERE IS WHAT I NEED TO CLICK IF class="B" DOES EXIST (EVERY class="A" has an IMG in div class="D")-->
</div>
</div>
...
<div class="A">
...
</div>
I know I have to use XPath or CSS selector, but here it's not a rel/abs XPath... Please help me.
To check if the element exists you can use driver.find_elements.
It returns a list of web elements matching the passed locator.
In case the element exists it returns non-empty list treated as Boolean true in Python, otherwise it returns an empty list recognized as false in Python.
UPD:
According to the latest requirements your code can be something like this:
a_list = driver.find_elements_by_xpath("//div[#class='A']")
for a_el in a_list:
if a_el.find_elements_by_xpath(".//div[#class ='B']"):
a_el.find_element_by_xpath(".//img[#class ='Y']").click()
You can try this:
if driver.find_elements_by_xpath("//div[#class = 'A']/div[#class ='B']"): # Finding the element in case it exists.
image_to_click = driver.find_element_by_xpath("//div[#class = 'D']//img[#class ='Y']")
image_to_click.click() # Clicking on the image.
Thanks for your help !
The final code is :
skin_list = driver.find_elements_by_class_name("B")
if len(skin_list) != 0:
skin_list[0].find_element_by_xpath("..//div[#class='D']").click()
But now, my new problem is the "skin_list = driver.find_elements_by_class_name" take a long time to search...

Select dropdown in Selenium Python

I can't select values in a list. I tried using find_element_by_class_name() to open the menu but when I need to select a <li> returns that element doesn't have a function click().
Here the code:
click_menu = driver.find_element_by_class_name("periodSelector")
click_menu[1].click()
Here is the HTML that I am trying to parse:
<div data-period-selector="" data-period="periodFilter">
<div class="periodSelectorContainer">
<div class="btn-group periodSelector">
<button class="flat-btn dropdown-toggle periodToggle ng-binding" data-toggle="dropdown"> 20/02/2021 - 22/03/2021 <span class="dropdown-arrow"></span> </button>
<ul class="dropdown-menu">
<li>
<a href="javascript:void(0);" class="new-financ" ng-click="selectToday()"><i></i>
<span class="pull-left">Hoje</span>
<span class="pull-right"></span>
</a>
</li>
<li>
<a href="javascript:void(0);" class="new-financ" ng-click="selectThisWeek()"><i>
</li>
There are multiple class names you have to use a css selector.
click_menu = driver.find_element_by_css_selector("button.flat-btn.dropdown-toggle.periodToggle.ng-binding")
click_menu.click()
Clicks 1st li tag.
driver.find_element_by_xpath("ul[#class='dropdown-menu']/li[1]").click()
periodSelector is a class on a DIV
<div class="btn-group periodSelector">
I'm assuming that you need to click on the BUTTON
<button class="flat-btn dropdown-toggle periodToggle ng-binding" data-toggle="dropdown">
Most of those classes seem generic (probably not unique) but I'm guessing that periodToggle might be unique given the date range. Try
driver.find_element_by_css_selector("button.periodToggle").click()
NOTE:
You have an error in your code. You are using .find_element_by_class_name() (singular) but have array notation on the next line, click_menu[1]. In this case, you can just use click_menu.click(). You'd only need the array notation if you were using .find_elements_by_*() (note the plural, elements).

using nth-type or nth-child to select n element

Q: What XPath or CSS selector I can use to select 2nd <div class="checkbox">?
I have tried to use:
XPath - //div[#class="checkbox"][2]
CSS - div.checkbox:nth-child(2)
However none of them worked on chrome developer tool.
I can use $x('//div[#class="checkbox"]') to see all three checkboxes
I can use $x('//div[#class="checkbox"]')[0] to specify the 1st div.checkbox
I can use $x('//div[#class="checkbox"]')[1] to specify the 2nd div.checkbox
Here's an example of my HTML Structure
<div class="fs">
<div class="f">
<div class="checkbox">
<input type="radio" value="A">
<label for="A">A</label>
</div>
</div>
<div class="f">
<div class="checkbox">
<input type="radio" value="B">
<label for="B">B</label>
</div>
</div>
<div class="f">
<div class="checkbox">
<input type="radio" value="C">
<label for="C">C</label>
</div>
</div>
</div>
Rather than trying to find the second element by index, another possibility would be to get it by the value on the INPUT or the text in the LABEL that is contained in that DIV. A couple XPaths would be
//div[#class='checkbox'][./input[#value='B']]
//div[#class='checkbox'][./label[.='B']]
You need 2nd element from the results. Which can be done by using below
(//div[#class="checkbox"])[2]
I think CSS doesn't allow such a thing to select from a result
Since JeffC and Tarun Lalwani already suggested XPath way of doing it, I'd like to suggest a different approach.
In CSS, one can use :nth-child selector to choose 2nd <div class="f"> and grab the nested div from there. (> can be omitted)
div.f:nth-child(2) > div.checkbox
Similarly, the following works in XPath:
//div[#class='f'][2]/div[#class='checkbox']
One can choose an element based on the attribute value with CSS selector using Attribute selectors, but one cannot select the parent, unfortunately.

How to collect information from non identic classes. (Selenium, 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.")

Categories