web自動化測試第12步:selenium中下拉框的解決方法(Select)
在之前,遇到下拉框的時候我們可以用兩次點選來選擇我們需要的選項,不過對於下拉框,我們的webdriver中有封裝的Select包單獨對於下拉框有一套處理的方法,我們可以來學習一下,然後在測試的時候根據不同的情況來選擇需要哪兒種方法。
1.select包方法的使用示例以及定位方式
select下拉框的定位
2.select包內的方法詳解
1.獲取option元素
options:獲取包含select下拉框內所有option項element的列表
all_selected_options: 獲取當前選中項element的列表
first_selected_option:獲取所有下拉選項中的第一個選項的element(或者獲取當前選中的這一項)
2.選擇option
select_by_value(values):選擇option標籤中value屬性為:values的選項
select_by_index(index_number):選擇索引為index_number的選項(索引從0開始)
select_by_visible_text(text):選擇option選項內容為:text的選項
3.複選select的情況(select標籤中,multiple="multiple"時,即可多選的select選擇框)
deselect_all: 取消所有已選擇的選項
deselect_by_value(values):取消選擇option標籤中value屬性為:values的選項
deselect_by_index(index_number):取消選擇索引為index_number的選項(索引從0開始)
deselect_by_visible_text(text):取消選擇option選項內容為:text的選項
3.例項驗證(一)百度貼吧高階搜尋下拉框
本條例項主要是獲取選項元素和通過方法來選擇某項option,程式碼如下
from selenium import webdriver
from selenium.webdriver.support.ui import Select
from time import sleep
# 開啟Chrome瀏覽器
driver = webdriver.Chrome()
# 進入百度高階搜尋頁
driver.get("http://tieba.baidu.com/f/search/adv")
# 獲取select下拉框的元素
ele_select = driver.find_element_by_css_selector("select[name='sm']")
# 獲取下拉框中所有選項元素(element)
options = Select(ele_select).options
print("所有選項元素的列表:%s" % options)
for i in options:
print("元素對應的選項:%s"% i.text)
# 獲取下拉框當前顯示(選中)的元素(element)
options_selected = Select(ele_select).all_selected_options
print("-----------------------分隔符---------------------------")
print(options_selected)
for j in options_selected:
print("當前選中的選項(預設項):%s" % j.text)
# 選擇value值為2的選項
Select(ele_select).select_by_value("2")
sleep(1)
# 輸出預設項(當前選中項)
now = Select(ele_select).first_selected_option
print(now.text)
4.例項驗證(二)w3c多選multiple選擇框
由於w3c並沒有多選multiple這一項,所以我們把我們自己寫的表單資訊給寫入到頁面上,然後再進行多選select框的驗證
from selenium import webdriver
from selenium.webdriver.support.ui import Select
from time import sleep
# 開啟瀏覽器,進入演示頁面
driver = webdriver.Chrome()
driver.get("http://www.w3school.com.cn/tiy/t.asp?f=html_dropdownbox")
# 定位輸入框文字域
ele_textarea = driver.find_element_by_css_selector("#TestCode")
# 清空文字域
ele_textarea.clear()
# 輸入多選下拉框的演示原始碼 (multiple="multiple\")
texts = "<html> " \
"<body><form><select multiple=\"multiple\" name=\"cars\"><option value=\"volvo\">Volvo</option>" \
"<option value=\"saab\">Saab</option><option value=\"fiat\">Fiat</option>\" \
\"<option value=\"audi\">Audi</option></select></form></body></html>"
ele_textarea.send_keys(texts)
# 點選提交程式碼
submit_button = driver.find_element_by_css_selector("#butt > input[type='button']")
submit_button.click()
sleep(2)
# 定位frame和select元素
driver.switch_to.frame("i")
ele_select = driver.find_element_by_css_selector("body > form > select")
# 選擇全部的選項(多選)
Select(ele_select).select_by_index(0)
Select(ele_select).select_by_index(1)
Select(ele_select).select_by_index(2)
Select(ele_select).select_by_index(3)
# 取消選擇第一項選項(頁面上可以觀察到變化)
Select(ele_select).deselect_by_index(0)
# 輸出當前選擇的第一項
now = Select(ele_select).first_selected_option
print(now.text)
5.原始碼展示
class Select(object): def __init__(self, webelement): """ Constructor. A check is made that the given element is, indeed, a SELECT tag. If it is not, then an UnexpectedTagNameException is thrown. :Args: - webelement - element SELECT element to wrap Example: from selenium.webdriver.support.ui import Select \n Select(driver.find_element_by_tag_name("select")).select_by_index(2) """ if webelement.tag_name.lower() != "select": raise UnexpectedTagNameException( "Select only works on <select> elements, not on <%s>" % webelement.tag_name) self._el = webelement multi = self._el.get_attribute("multiple") self.is_multiple = multi and multi != "false" @property def options(self): """Returns a list of all options belonging to this select tag""" return self._el.find_elements(By.TAG_NAME, 'option') @property def all_selected_options(self): """Returns a list of all selected options belonging to this select tag""" ret = [] for opt in self.options: if opt.is_selected(): ret.append(opt) return ret @property def first_selected_option(self): """The first selected option in this select tag (or the currently selected option in a normal select)""" for opt in self.options: if opt.is_selected(): return opt raise NoSuchElementException("No options are selected") def select_by_value(self, value): """Select all options that have a value matching the argument. That is, when given "foo" this would select an option like: <option value="foo">Bar</option> :Args: - value - The value to match against throws NoSuchElementException If there is no option with specisied value in SELECT """ css = "option[value =%s]" % self._escapeString(value) opts = self._el.find_elements(By.CSS_SELECTOR, css) matched = False for opt in opts: self._setSelected(opt) if not self.is_multiple: return matched = True if not matched: raise NoSuchElementException("Cannot locate option with value: %s" % value) def select_by_index(self, index): """Select the option at the given index. This is done by examing the "index" attribute of an element, and not merely by counting. :Args: - index - The option at this index will be selected throws NoSuchElementException If there is no option with specisied index in SELECT """ match = str(index) for opt in self.options: if opt.get_attribute("index") == match: self._setSelected(opt) return raise NoSuchElementException("Could not locate element with index %d" % index) def select_by_visible_text(self, text): """Select all options that display text matching the argument. That is, when given "Bar" this would select an option like: <option value="foo">Bar</option> :Args: - text - The visible text to match against throws NoSuchElementException If there is no option with specisied text in SELECT """ xpath = ".//option[normalize-space(.) = %s]" % self._escapeString(text) opts = self._el.find_elements(By.XPATH, xpath) matched = False for opt in opts: self._setSelected(opt) if not self.is_multiple: return matched = True if len(opts) == 0 and " " in text: subStringWithoutSpace = self._get_longest_token(text) if subStringWithoutSpace == "": candidates = self.options else: xpath = ".//option[contains(.,%s)]" % self._escapeString(subStringWithoutSpace) candidates = self._el.find_elements(By.XPATH, xpath) for candidate in candidates: if text == candidate.text: self._setSelected(candidate) if not self.is_multiple: return matched = True if not matched: raise NoSuchElementException("Could not locate element with visible text: %s" % text) def deselect_all(self): """Clear all selected entries. This is only valid when the SELECT supports multiple selections. throws NotImplementedError If the SELECT does not support multiple selections """ if not self.is_multiple: raise NotImplementedError("You may only deselect all options of a multi-select") for opt in self.options: self._unsetSelected(opt) def deselect_by_value(self, value): """Deselect all options that have a value matching the argument. That is, when given "foo" this would deselect an option like: <option value="foo">Bar</option> :Args: - value - The value to match against throws NoSuchElementException If there is no option with specisied value in SELECT """ if not self.is_multiple: raise NotImplementedError("You may only deselect options of a multi-select") matched = False css = "option[value = %s]" % self._escapeString(value) opts = self._el.find_elements(By.CSS_SELECTOR, css) for opt in opts: self._unsetSelected(opt) matched = True if not matched: raise NoSuchElementException("Could not locate element with value: %s" % value) def deselect_by_index(self, index): """Deselect the option at the given index. This is done by examing the "index" attribute of an element, and not merely by counting. :Args: - index - The option at this index will be deselected throws NoSuchElementException If there is no option with specisied index in SELECT """ if not self.is_multiple: raise NotImplementedError("You may only deselect options of a multi-select") for opt in self.options: if opt.get_attribute("index") == str(index): self._unsetSelected(opt) return raise NoSuchElementException("Could not locate element with index %d" % index) def deselect_by_visible_text(self, text): """Deselect all options that display text matching the argument. That is, when given "Bar" this would deselect an option like: <option value="foo">Bar</option> :Args: - text - The visible text to match against """ if not self.is_multiple: raise NotImplementedError("You may only deselect options of a multi-select") matched = False xpath = ".//option[normalize-space(.) = %s]" % self._escapeString(text) opts = self._el.find_elements(By.XPATH, xpath) for opt in opts: self._unsetSelected(opt) matched = True if not matched: raise NoSuchElementException("Could not locate element with visible text: %s" % text) def _setSelected(self, option): if not option.is_selected(): option.click() def _unsetSelected(self, option): if option.is_selected(): option.click() def _escapeString(self, value): if '"' in value and "'" in value: substrings = value.split("\"") result = ["concat("] for substring in substrings: result.append("\"%s\"" % substring) result.append(", '\"', ") result = result[0:-1] if value.endswith('"'): result.append(", '\"'") return "".join(result) + ")" if '"' in value: return "'%s'" % value return "\"%s\"" % value def _get_longest_token(self, value): items = value.split(" ") longest = "" for item in items: if len(item) > len(longest): longest = item return longest