selenium count elements of xpath - python

i have a webpage with a table containing many Download links
i want to let selenium click on the last one :
table:
item1 Download
item2 Download
item3 Download
selenium must click on Download next item3
i used xpath to find all elments then get size of returned array or dict in this way
x = bot._driver.find_element_by_xpath("//a[contains(text(),'Download')]").size()
but i get always this error
TypeError: 'dict' object is not callable
i tried to use get_xpath_count methode but the methode doen't exist in selenium in python!
i thought about another solution but i don't know how to do it and it is as following
x = bot._driver.find_element_by_xpath("(//a[contains(text(),'Download')])[size()-1]")
or
x = bot._driver.find_element_by_xpath("(//a[contains(text(),'Download')])[last()]")
or something else

Use find_elements_by_xpath to get number of relevant elements
count = len(driver.find_elements_by_xpath(xpath))
Then click on the last element:
elem = driver.find_element_by_xpath(xpath[count])
elem.click()
Notice: the find_elements_by_xpath is plural in first code snippet

Although get_xpath_count("Xpath_Expression") does not exist in Python, you can use
len(bot._driver.find_element_by_xpath("//a[contains(text(),'Download')]"))
to achieve the number of elements, and then iterate through then, using
something.xpath(//a[position()=n])
where
n < len(bot._driver.find_element_by_xpath("//a[contains(text(),'Download')]"))

the best way to do this is to use JavaScript and find elements by class name
self.bot._driver.execute_script("var e = document.getElementsByClassName('download'); e[e.length-1].click()")
source:
http://de.slideshare.net/adamchristian/javascript-testing-via-selenium

Related

Can't find element selenium even though it certainly exists

I have some trouble finding a element here Link
I want to scrape the names of the matches using:
WebDriverWait(driver,10).until(EC.presence_of_element_located((By.XPATH, '/html/body/div[7]/div[1]/div/div/div[4]/div/div/main/div[2]/div/div/div/div//div/div/div/article/main/a/span')))
(I don't like using the XPath, but otherwise I'd also get the bets that weren't just full time result bets)
But when I run this it returns an empty list.
I have tried figuring out wether the match names are within an iframe or something but I can't figure it out. Does someone know how I can scrape these elements?
N.B. I have checked multiple times whether the XPath is actually in the HTML and it is.
so the code you are using is to wait the page to load until the xpath is found. I wrote the code below and it works. It just prints dates too, you need to adjust. However I just run it so I am confident it works. Ensure you load all the dependencies in the top. It works with class and not xpath.
driver.get("https://sports.williamhill.com/betting/en-gb/football/competitions/OB_TY295/English-Premier-League/matches/OB_MGMB/Match-Betting")
WebDriverWait(driver, 10).until(
lambda x: x.find_element_by_class_name('sp-o-market__title').is_displayed())
out = driver.find_elements_by_class_name('sp-o-market__title')
for item in out:
item = item.get_attribute('innerHTML')
item = item.split('<span>')[1]
item = item.split("</span>")[0]
print(item)
Produces:
Arsenal v Norwich
Brentford v Brighton

How to find an Element by index in selenium Webdriver for python

This is HTML code of that page
From there I want to access the 2nd element by using class name "maxbutton-1" as it has 3 same buttons and I can't use xpath or any constant selector so want to use the indexing with class and can't find anything to do that in python particular.
Also tried the method used in java to do same thing but it didn't worked.
Link of that same page
just trying to automate the movie downloading process for any movie.
Thank you.
To click on first, second or third button, try to change number of element:
el1 = driver.find_element_by_xpath("(//a[#class='maxbutton-1 maxbutton maxbutton-download-links'])[1]")
el2 = driver.find_element_by_xpath("(//a[#class='maxbutton-1 maxbutton maxbutton-download-links'])[2]")
el3 = driver.find_element_by_xpath("(//a[#class='maxbutton-1 maxbutton maxbutton-download-links'])[3]")
then you can extract element href/link attribute like that:
link = el.get_attribute('href')
or click it like that:
el.click()

Python selenium 'list' object has no attribute 'text' error

I'm trying to copy text from comment on a website<span class="auto-link">yes</span> and my python code is
element=browser.find_elements_by_xpath('//span[#class="auto-link"][1]')
print(element.text)
but I keep on getting the 'list' object has no attribute 'text' error, I don't know what I'm doing wrong.
I'm using selenium in python. Try this code I hope this will work for you.
element=browser.find_elements_by_xpath('//span[#class="auto-link"][1]')
for value in element:
print(value.text)
I've never used Selenium, but based on the error and your response, the answer is pretty clear.
When you search for a class, there may be multiple matching elements, so it returns a list of all found matches. Even if you only have a single element with that class, it will still return a list for consistency.
Just grab the first element from the found elements:
elements = browser.find_elements_by_xpath('//span[#class="auto-link"][1]')
# ^ Renamed to reflect type better
print(elements[0].text)
# ^ Grab the first element
# instead of driver.find_elements_by_xpath() use driver.find_element_by_xpath() to get the individual element of the table
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import time
# Google Chrome
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get("https://testautomationpractice.blogspot.com/")
# Get Number of Rows
rows = len(driver.find_elements_by_xpath("//*[#id='HTML1']/div[1]/table/tbody/tr"))
# Get Number of Columns
columns = len(driver.find_elements_by_xpath("//*[#id='HTML1']/div[1]/table/tbody/tr[1]/th"))
print("Number of Rows:", rows)
print("Number of Columns:", columns)
# In web table index starts with 1 instead of 0
for row in range(2, rows+1):
for col in range(1,columns+1):
value = driver.find_element_by_xpath("//*[#id='HTML1']/div[1]/table/tbody/tr["+str(row)+"]/td["+str(col)+"]").text
print(value, end=' ')
print()
time.sleep(5)
# Close the Browser
driver.close()
This will work when you are looking for more than one element and takes the first element that matches the xpath:
element=browser.find_elements_by_xpath('//span[#class="auto-link"][1]').get_attribute("innerHTML")
print(element)
This is when you are looking only for one:
element=browser.find_element_by_xpath('//span[#class="auto-link"]').get_attribute("innerHTML")
print(element)
The output:
>>>yes
First Write the xpath of span in which you are currently working and then add the index number in the last of xpath but within it like given below.
from selenium import webdriver`
driver = webdriver.Firefox()
driver.get("http://www.example.org")
element=browser.find_elements_by_xpath('//span[#class="auto-link"[1]').click()
print(element)
[1] is the index number of my value which i want to access.
dont use find_elements_by_xpath, but find_element_by_xpath
There are 10 elements by this selector, it prints all of them
roles = driver.find_elements_by_xpath("(//label[#class='container-checkmark disabled'])")
for x in range(len(roles)):
print(roles[x].text)

Python: Remove repeated code for repeated action in Selenium

I am working in Python with Selenium and have to do this:
elem = driver.find_element_by_css_selector('#results .page_block_sub_header_count')
elem = driver.find_element_by_css_selector('#results .page_block_sub_header_count')
elem = driver.find_element_by_css_selector('#results .page_block_sub_header_count')
elem = driver.find_element_by_css_selector('#results .page_block_sub_header_count')
I am doing this because there are 4 elements on the page that have this CSS Selector "#results .page_block_sub_header_count". And I want to get the result of the 4th one.
Is there a good way I could put this into code? I do not want 4 similar lines. And I believe this is not considered a good code practice.
Just use the find_elements_by_css_selector() (note the "s") to locate multiple elements matching a locator - CSS selector in your case:
results = driver.find_elements_by_css_selector('#results .page_block_sub_header_count')
results would be a list of WebElement instances, you can iterate over it and get, say, a text:
for item in results:
print(item.text)
Without the HTML it is tough to provide you the best fit solution. How ever as I can see from your tried out code, you have used :
driver.find_element_by_css_selector('#results .page_block_sub_header_count')
This essentially means, the node with id as results has atleast 4 childnodes with class as page_block_sub_header_count. So to construct the best fit css_selector we are missing the information regarding the tagName which contains the class page_block_sub_header_count which will be available in the HTML DOM.
Still if you want to get the result of the 4th one you can use the following line of code :
elem = driver.find_element_by_css_selector('#results .page_block_sub_header_count:nth-of-type(4)')
Also you can use the following code (just a case):
elements = driver.find_elements_by_css_selector("#results .page_block_sub_header_count")
for index in range(len(elements)):
elements[index].text
PS: #alecxe's code is better for usage.

Using selenium to get access class info on website

I am using the following code using Python 3.6 and selenium:
element = driver.find_element_by_class_name("first_result_price")
print(element)
on the website it is like this
`website: span class="first_result_price">712
however if I print element I get a completely different number?
Any suggestions?
many thanks!!
"element" is a type of object called WebElement that Selenium adds. If you want to find the text inside that element, you have to say
element.text
Which should return what you're looking for, '712', albeit in string form.

Categories