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>?

famousgarkin
  • 313
  • 2
  • 17
John Keyes
  • 943
  • 1
  • 7
  • 6

6 Answers6

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)
Daniel Abel
  • 931
  • 6
  • 3
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'])
Jason Ward
  • 1,155
  • 9
  • 7
  • @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 Apr 18 '13 at 09: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 Jul 24 '13 at 01:43
  • 1
    Good solution, but not as good as Daniel Abel's proposed solution. Better off using the built in Select function – Chris Bier Mar 27 '14 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 Mar 28 '14 at 20:11
  • Why did you edit my answer instead of adding your own? – Jason Ward Apr 28 '15 at 22:03
  • Complain if I try to get the option tag value 55 or visibletext in ID location at this URL?. The weird things are select.options returns only Select One options when you loop through options, instead of return 3 options. Any suggestions? – Anu Feb 15 '20 at 21:43
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()
famousgarkin
  • 313
  • 2
  • 17
Doug
  • 191
  • 1
  • 1
  • 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. http://selenium-python.readthedocs.org/locating-elements.html#locating-by-xpath – Adam Starrh Dec 26 '15 at 20:25
  • Yes, as @AdamStarrh, this only worked with @value – Henrique de Sousa Apr 30 '21 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()
Will Townes
  • 151
  • 1
  • 2
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)
Kate Paulk
  • 31,513
  • 8
  • 54
  • 108
SCode
  • 11
  • 2
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();