82

I would like to select an <option> child of a <select> using the Python WebDriver.

I have a reference to the option WebElement I wish to select and have tried select() and click() methods but neither works.

What is the correct way to select an <option>?

4
  • Oh dearie me, of course it works. It was my fault for calling click() on the default <option>, which made it look like nothing had changed.
    – John Keyes
    Commented Jul 7, 2011 at 10:30
  • My test doesn’t work with option.click(), but it does work with option.select(). In the latest webelement.py source, select has been removed, and click must be used in it’s place. It will be interesting to see if my test works with the latest release.
    – John Keyes
    Commented Jul 7, 2011 at 10:58
  • 4
    Accepted solution is VERY SLOW. I recommend @Daniel Abel solution. It would be nice if OP accepted it, it keeps gaining upvotes. Commented Feb 5, 2015 at 21:38
  • possible duplicate of How do I work with dropdowns in Selenium Webdriver? Commented May 6, 2015 at 16:30

6 Answers 6

53

The easiest way that I have found was to do something along the lines of:

el = driver.find_element_by_id('id_of_select')
for option in el.find_elements_by_tag_name('option'):
    if option.text == 'The Options I Am Looking For':
        option.click() # select() in earlier versions of webdriver
        break

This may have some runtime issues if there are a large number of options, but for us it suffices.

Also this code will work with multi-select

def multiselect_set_selections(driver, element_id, labels):
    el = driver.find_element_by_id(element_id)
    for option in el.find_elements_by_tag_name('option'):
        if option.text in labels:
            option.click()

Then you can transform the following field

# ERROR: Caught exception [ERROR: Unsupported command [addSelection | id=deformField7 | label=ALL]]

Into this call

multiselect_set_selections(driver, 'deformField7', ['ALL'])

Multiple selection errors like the following:

 # ERROR: Caught exception [ERROR: Unsupported command [addSelection | id=deformField5 | label=Apr]]
 # ERROR: Caught exception [ERROR: Unsupported command [addSelection | id=deformField5 | label=Jun]]

Will be fixed with a single call:

multiselect_set_selections(driver, 'deformField5', ['Apr', 'Jun'])
6
  • @JasonWard How are you iterating over the Web Element object in for loop. I tried the same and got a exception that the object is not iterable. Any suggestion. Thanks
    – abhi
    Commented Apr 18, 2013 at 9:53
  • 1
    @abhi Make sure you are using find_elements_by_tag_name and not find_element_by_tag_name (The s in elements matters).
    – Jason Ward
    Commented Jul 24, 2013 at 1:43
  • 1
    Good solution, but not as good as Daniel Abel's proposed solution. Better off using the built in Select function
    – Chris Bier
    Commented Mar 27, 2014 at 16:04
  • @ChrisB you are correct that his solution is better, however I am fairly certain that when this was response was written the Select function did not exist :)
    – Jason Ward
    Commented Mar 28, 2014 at 20:11
  • Why did you edit my answer instead of adding your own?
    – Jason Ward
    Commented Apr 28, 2015 at 22:03
78

I think using selenium.webdriver.support.ui.Select is the cleanest way:

from selenium import webdriver
from selenium.webdriver.support.ui import Select

b = webdriver.Firefox()

# navigate to the page
select = Select(b.find_element_by_id(....))
print select.options
print [o.text for o in select.options] # these are string-s
select.select_by_visible_text(....)

Using this approach is also the fastest way. I wrote fast_multiselect as analogous function to multiselect_set_selections. On a test with 4 calls to multiselect_set_selections on lists of about 20 items each, the average running time is 16.992 seconds, where fast_multiselect is only 10.441 seconds. Also the latter is much less complicated.

 from selenium.webdriver.support.ui import Select

 def fast_multiselect(driver, element_id, labels):
     select = Select(driver.find_element_by_id(element_id))
     for label in labels:
         select.select_by_visible_text(label)
4
  • 3
    Nice. Selenium auto-generated documentation just sucks.
    – Stan
    Commented Sep 27, 2012 at 13:07
  • 1
    This is the idiomatic approach. Too bad it isn't the accepted answer. Commented Apr 28, 2015 at 19:13
  • This should be the accepted answer
    – Nam G VU
    Commented Jun 20, 2017 at 7:57
  • My big question is How is it so slow? Why? I don't understand... 10 seconds is way too long.
    – Jess
    Commented Jan 19, 2021 at 20:51
9

Similar to Will's answer, but finds the <select> by its element name, and clicks based on the <option> text.

from selenium import webdriver
b = webdriver.Firefox()
b.find_element_by_xpath("//select[@name='element_name']/option[text()='option_text']").click()
2
  • 2
    This worked for me using "//select[@name='element_name']/option[@value='2']" to select an option by it's value (in case you are concerned about option text changing). It's well worth learning about xpath, IMO. selenium-python.readthedocs.org/… Commented Dec 26, 2015 at 20:25
  • Yes, as @AdamStarrh, this only worked with @value Commented Apr 30, 2021 at 21:21
5

I had a similar problem and was able to resolve it by finding the elements by xpath:

from selenium import webdriver
b = webdriver.Firefox()
#...some commands here
b.find_element_by_xpath("//select/option[@value='The Options I am Looking for']").click()
1

easier way to manipulate the dropdowns

from selenium import webdriver
from selenium.webdriver.support.ui import Select

driver.get("link")
select = Select(driver.find_element_by_id('<given id name>'))
select.select_by_index(3)
0

Using the latest rewritten version (1.0.1) of facebook/php-webdriver:

$optionCssSelector = WebDriverBy::cssSelector("#order_images_row_wrapper .order-wrapper .merge-image-select option[value='2']");
$this->driver->findElements($optionCssSelector)[0]->click();
1
  • 3
    That's some mighty strange looking Python you've got there.
    – XtrmJosh
    Commented Mar 1, 2016 at 13:26

Not the answer you're looking for? Browse other questions tagged or ask your own question.