84

How can I filter elements that have the same class?

<html>
  <body>
    <p class="content">Link1.</p>
  </body>
</html>
<html>
  <body>
    <p class="content">Link2.</p>
  </body>
</html>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sree
  • 849
  • 1
  • 6
  • 3

7 Answers7

92

You can try to get the list of all elements with class = "content" by using find_elements_by_class_name:

a = driver.find_elements_by_class_name("content")

Then you can click on the link that you are looking for.

LittlePanda
  • 2,496
  • 1
  • 21
  • 33
  • 4
    Does it return all elements of the class or the first found? – keerthan kumar May 14 '18 at 01:50
  • 15
    Why are you even initializing `a` as an empty list if you immediately reassign it? – user124384 Sep 08 '18 at 23:07
  • 3
    @keerthankumar this return list of all the elements. To get the 1st one use `find_element_by_class_name` – zvi Aug 08 '19 at 07:10
  • 1
    You don't need the semicolon at the end of python line of code. – raw-bin hood Jul 09 '20 at 00:02
  • 1
    Now how to click on the class name after selecting it? `.click()` attribute doesn't work! – Dagad Feb 13 '22 at 17:37
  • 6
    `find_element_by_*` and `find_elements_by_*` are removed in Selenium 4.3.0. Use `find_element` instead. Look at all change logs [here](https://github.com/SeleniumHQ/selenium/blob/a4995e2c096239b42c373f26498a6c9bb4f2b3e7/py/CHANGES). – Parampreet Rai Jul 08 '22 at 17:08
  • 1
    @Parampreet Rai: Though `find_element()` [throws an exception if the element doesn't exist](https://stackoverflow.com/questions/9567069/checking-if-an-element-exists-with-python-selenium#comment117614846_36166132). – Peter Mortensen Nov 11 '22 at 07:44
  • 1
    @PeterMortensen you can still use `find_elements(By.CLASS_NAME, 'foo')` to get a list of elements – Brian Leishman Nov 11 '22 at 13:08
50

By.CLASS_NAME was not yet mentioned:

from selenium.webdriver.common.by import By

driver.find_element(By.CLASS_NAME, "content")

This is the list of attributes which can be used as locators in By:

CLASS_NAME
CSS_SELECTOR
ID
LINK_TEXT
NAME
PARTIAL_LINK_TEXT
TAG_NAME
XPATH

ZygD
  • 22,092
  • 39
  • 79
  • 102
31

As per the HTML:

<html>
    <body>
    <p class="content">Link1.</p>
    </body>
<html>
<html>
    <body>
    <p class="content">Link2.</p>
    </body>
<html>

Two(2) <p> elements are having the same class content.

So to filter the elements having the same class i.e. content and create a list you can use either of the following Locator Strategies:

  • Using class_name:

    elements = driver.find_elements_by_class_name("content")
    
  • Using css_selector:

     elements = driver.find_elements_by_css_selector(".content")
    
  • Using xpath:

    elements = driver.find_elements_by_xpath("//*[@class='content']")
    

Ideally, to click on the element you need to induce WebDriverWait for the visibility_of_all_elements_located() and you can use either of the following Locator Strategies:

  • Using CLASS_NAME:

    elements = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, "content")))
    
  • Using CSS_SELECTOR:

    elements = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, ".content")))
    
  • Using XPATH:

    elements = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//*[@class='content']")))
    
  • 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
    

References

You can find a couple of relevant discussions in:

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • 1
    Neither class name nor css selector worked, no idea why, but xpath did, thanks a lot for that – Timeler Jan 14 '21 at 10:01
  • From [a comment](https://stackoverflow.com/questions/30002313/selenium-finding-elements-by-class-name-in-python#comment128785684_30025430): *"`find_element_by_*` and `find_elements_by_*` are removed in Selenium 4.3.0. Use `find_element` instead."* – Peter Mortensen Nov 10 '22 at 16:00
13

Use nth-child, for example: http://www.w3schools.com/cssref/sel_nth-child.asp

driver.find_element(By.CSS_SELECTOR, 'p.content:nth-child(1)')

or http://www.w3schools.com/cssref/sel_firstchild.asp

driver.find_element(By.CSS_SELECTOR, 'p.content:first-child')
Stan E
  • 3,396
  • 20
  • 31
12

The most simple way is to use find_element_by_class_name('class_name')

wanderlust
  • 1,826
  • 1
  • 21
  • 25
3

The first answer has been deprecated, and the other answers only return one result. This is the correct answer:

driver.find_elements(By.CLASS_NAME, "content")
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JackDonMcLovin
  • 137
  • 2
  • 11
  • Yes, they missed the plural, "elements". However, *find_elements* itself [is deprecated](https://stackoverflow.com/questions/30002313/selenium-finding-elements-by-class-name-in-python#comment128785684_30025430). – Peter Mortensen Nov 10 '22 at 15:53
  • What do you mean by "the first answer"? Highest scored? Chronological first? References to relative positions of answers are not reliable as they depend on the view (votes/oldest/active) and changing of the accepted answer and change over time (for votes, active, and accepted state). – Peter Mortensen Nov 10 '22 at 15:55
  • To be fair, it wasn't missed in [one of the answers](https://stackoverflow.com/questions/30002313/finding-elements-by-class-name-with-selenium-in-python/63329510#63329510). – Peter Mortensen Nov 10 '22 at 16:12
0

The question was related to "elements" plural, most are for element. To wait for the element and then iterate over each:

selectableEls = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, "content")))
for el in selectableEls:
    print(el)
FabricioG
  • 3,107
  • 6
  • 35
  • 74