What is the correct way to select an <option> using Selenium's Python WebDriver</option>

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

    Oh dearie me, **of course it works**. It was my fault for calling `click()` on the default `

    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.

    Accepted solution is VERY SLOW. I recommend @Daniel Abel solution. It would be nice if OP accepted it, it keeps gaining upvotes.

  • Jason Ward

    Jason Ward Correct answer

    9 years ago

    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'])
    

    I just saw that you had answered your own question, oops :)

    No worries Jason. I tried to answer it myself earlier but six hours have to elapse before I could. I'll give you the kudos anyway :)

    @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 Make sure you are using `find_elements_by_tag_name` and not `find_element_by_tag_name` (The `s` in `elements` matters).

    Good solution, but not as good as Daniel Abel's proposed solution. Better off using the built in `Select` function

    @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 :)

    Why did you edit my answer instead of adding your own?

    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?

  • 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)
    

    This works and is a good solution.

    Nice. Selenium auto-generated documentation just sucks.

    This is the idiomatic approach. Too bad it isn't the accepted answer.

    This should be the accepted answer

  • 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()
    

    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

  • 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()
    
  • 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();
    

    That's some mighty strange looking Python you've got there.

  • 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)
    

License under CC-BY-SA with attribution


Content dated before 6/26/2020 9:53 AM