AttributeError: 'list' object has no attribute 'click' using Selenium and Python

10,477

Solution 1

I would still suggest you to go with linkText over XPATH. Reason this xpath : /html/body/div[5]/section/div[8]/div[1]/a[1] is quite absolute and can be failed if there is one more div added or removed from HTML. Whereas chances of changing the link Text is very minimal.

So, Instead of this code :

elm = driver.find_elements_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]").click()

try this code :

annual_link = driver.find_element_by_link_text('Annual')
annual_link.click()

and yes @Druta is right, use find_element for one web element and find_elements for list of web element. and it is always good to have explicit wait.

Create instance of explicit wait like this :

wait = WebDriverWait(driver,20)

and use the wait reference like this :

wait.until(EC.elementToBeClickable(By.LINK_TEXT, 'Annual'))  

UPDATE:

from selenium import webdriver
link = 'https://www.investing.com/equities/apple-computer-inc-balance-sheet'

driver = webdriver.Firefox()
driver.maximize_window()
wait = WebDriverWait(driver,40)
driver.get(link)  

driver.execute_script("window.scrollTo(0, 200)") 

wait.until(EC.element_to_be_clickable((By.LINK_TEXT, 'Annual')))
annual_link = driver.find_element_by_link_text('Annual')
annual_link.click()
print(annual_link.text)  

make sure to import these :

from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC 

Solution 2

you need to use find_element_by_xpath not find_elements_by_xpath that return a list

driver.find_element_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]").click()

Also i think is better to use Waits for example.

from selenium.webdriver.common.by import By    
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.firefox.options import Options

options = Options()
options.add_argument("--window-size=1920,1080")
driver = webdriver.Firefox(firefox_options=options)

path = "/html/body/div[5]/section/div[8]/div[1]/a[1]"
try:
    element = WebDriverWait(driver, 5).until(
                           EC.element_to_be_clickable((By.XPATH, path)))
    element.click()
finally:
    driver.quit()

Solution 3

As per the documentation find_elements_by_xpath(xpath) returns a List with elements if any was found or else an empty list if not. Python's List have no click() method associated with it. Instead find_element_by_xpath(xpath) method have the click() method associated with it. So you have to use find_element_by_xpath(xpath) method inducing a waiter through WebDriverWait inconjunction with expected_conditions set as element_to_be_clickable(locator) as follows:

WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[@class='newBtn toggleButton LightGray' and @data-type='rf-type-button']"))).click()

Note : You have to add the following imports :

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Solution 4

Notice that find_elements_by_xpath is plural it returns a list of elements. Not just one. The list can contain none, exactly one, or more elements.

You can for example click the first match with:

driver.find_elements_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]")[0].click()

or iterate through the list and click all these elements, or you can use the find_element_by_xpath (which returns a single element, if it can be found):

driver.find_element_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]").click()
Share:
10,477

Related videos on Youtube

Felix
Author by

Felix

Keep working on a problem till you get frustrated. Then stop. And repeat process till you make progress

Updated on June 19, 2022

Comments

  • Felix
    Felix almost 2 years

    I'd like to click the button 'Annual' at a page that is by default set on 'Quarterly'. There are two links that are basically called the same, except that one has data-ptype="Annual" so I tryed to copy the xpath to click the button (also tried other options but none did work).

    However, I get the AttributeError: 'list' object has no attribute 'click'. I read a lot of similar posts, but wasn't able to fix my problem.. so I assume that javascript event must be called/clicked/performed somehow differnt.. idk Im stuck

    from selenium import webdriver
    link = 'https://www.investing.com/equities/apple-computer-inc-balance-sheet'
    
    driver = webdriver.Firefox()
    driver.get(link)
    elm = driver.find_elements_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]").click()
    

    The html is the following:

    <a class="newBtn toggleButton LightGray" href="javascript:void(0);" data-type="rf-type-button" data-ptype="Annual" data-pid="6408" data-rtype="BAL">..</a>
    
  • Felix
    Felix almost 6 years
    A thanks, but I still get an error cause a popup shows up.. Is there a way around it? Cause I get: ElementClickInterceptedException: 'Element <a class="newBtn toggleButton LightGray" href="javascript:void(0);"> is not clickable at point (175.29999542236328,530.3166961669922) because another element <div class="consentBarWrapper"> obscures it'
  • Druta Ruslan
    Druta Ruslan almost 6 years
    i update my answer, try to add options to open firefox on full window, but i run the code without options and it works
  • cruisepandey
    cruisepandey almost 6 years
    @Felix : I have updated my answer under update section. This code works fine on my machine. You will have to scroll down to interact with Annual button. Thanks !
  • JayB
    JayB almost 4 years
    Worked like a charm.Thanks!
  • sonali
    sonali over 3 years
    this is a comment, not an answer