Selenium 高阶应用之WebDriverWait 和 expected_conditions

转载地址: http://www.cnblogs.com/yicaifeitian/p/4749149.html

 Seleniium 是相当不错的一个第三方测试框架,可惜目前国内已经无法访问其官网(FQ可以)。

      不知道大家是否有认真查看过selenium 的api,我是有认真学习过的。selenium 的api中包含有WebDriverWait  和 expected_conditions这两个高级应用。

  下面先看WebDriverWait :

复制代码
 1 import time
 2 from selenium.common.exceptions import NoSuchElementException
 3 from selenium.common.exceptions import TimeoutException
 4 
 5 POLL_FREQUENCY = 0.5  # How long to sleep inbetween calls to the method
 6 IGNORED_EXCEPTIONS = (NoSuchElementException,)  # exceptions ignored during calls to the method
 7 
 8 
 9 class WebDriverWait(object):
10     def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None):
11         """Constructor, takes a WebDriver instance and timeout in seconds.
12 
13            :Args:
14             - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
15             - timeout - Number of seconds before timing out
16             - poll_frequency - sleep interval between calls
17               By default, it is 0.5 second.
18             - ignored_exceptions - iterable structure of exception classes ignored during calls.
19               By default, it contains NoSuchElementException only.
20 
21            Example:
22             from selenium.webdriver.support.ui import WebDriverWait \n
23             element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) \n
24             is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\ \n
25                         until_not(lambda x: x.find_element_by_id("someId").is_displayed())
26         """
27         self._driver = driver
28         self._timeout = timeout
29         self._poll = poll_frequency
30         # avoid the divide by zero
31         if self._poll == 0:
32             self._poll = POLL_FREQUENCY
33         exceptions = list(IGNORED_EXCEPTIONS)
34         if ignored_exceptions is not None:
35             try:
36                 exceptions.extend(iter(ignored_exceptions))
37             except TypeError:  # ignored_exceptions is not iterable
38                 exceptions.append(ignored_exceptions)
39         self._ignored_exceptions = tuple(exceptions)
40 
41     def until(self, method, message=''):
42         """Calls the method provided with the driver as an argument until the \
43         return value is not False."""
44         screen = None
45         stacktrace = None
46 
47         end_time = time.time() + self._timeout
48         while True:
49             try:
50                 value = method(self._driver)
51                 if value:
52                     return value
53             except self._ignored_exceptions as exc:
54                 screen = getattr(exc, 'screen', None)
55                 stacktrace = getattr(exc, 'stacktrace', None)
56             time.sleep(self._poll)
57             if time.time() > end_time:
58                 break
59         raise TimeoutException(message, screen, stacktrace)
60 
61     def until_not(self, method, message=''):
62         """Calls the method provided with the driver as an argument until the \
63         return value is False."""
64         end_time = time.time() + self._timeout
65         while True:
66             try:
67                 value = method(self._driver)
68                 if not value:
69                     return value
70             except self._ignored_exceptions:
71                 return True
72             time.sleep(self._poll)
73             if time.time() > end_time:
74                 break
75         raise TimeoutException(message)
复制代码

 哈哈,我始终相信贴出来总会有人看。WebDriverWait 类位于selenium.webdriver.support.ui下面的例子很简单,

Example:
from selenium.webdriver.support.ui import WebDriverWait \n
element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) \n
is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\ \n
                 until_not(lambda x: x.find_element_by_id("someId").is_displayed())

WebDriverWait 里面主要有两个方法,一个是until和until_not

那么我们可以这样用:
WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("某个按钮")).click()

  意思就是在10秒内等待某个按钮被定位到,咱们再去点击。就是每隔0.5秒内调用一下until里面的表达式或者方法函数,要么10秒内表达式执行成功,要么10秒后抛出超时异常。

然后我们再看expected_conditions:
复制代码
  1 from selenium.common.exceptions import NoSuchElementException
  2 from selenium.common.exceptions import NoSuchFrameException
  3 from selenium.common.exceptions import StaleElementReferenceException
  4 from selenium.common.exceptions import WebDriverException
  5 from selenium.common.exceptions import NoAlertPresentException
  6 
  7 """
  8  * Canned "Expected Conditions" which are generally useful within webdriver
  9  * tests.
 10 """
 11 class title_is(object):
 12     """An expectation for checking the title of a page.
 13     title is the expected title, which must be an exact match
 14     returns True if the title matches, false otherwise."""
 15     def __init__(self, title):
 16         self.title = title
 17 
 18     def __call__(self, driver):
 19         return self.title == driver.title
 20 
 21 class title_contains(object):
 22     """ An expectation for checking that the title contains a case-sensitive
 23     substring. title is the fragment of title expected
 24     returns True when the title matches, False otherwise
 25     """
 26     def __init__(self, title):
 27         self.title = title
 28 
 29     def __call__(self, driver):
 30         return self.title in driver.title
 31 
 32 class presence_of_element_located(object):
 33     """ An expectation for checking that an element is present on the DOM
 34     of a page. This does not necessarily mean that the element is visible.
 35     locator - used to find the element
 36     returns the WebElement once it is located
 37     """
 38     def __init__(self, locator):
 39         self.locator = locator
 40 
 41     def __call__(self, driver):
 42         return _find_element(driver, self.locator)
 43 
 44 class visibility_of_element_located(object):
 45     """ An expectation for checking that an element is present on the DOM of a
 46     page and visible. Visibility means that the element is not only displayed
 47     but also has a height and width that is greater than 0.
 48     locator - used to find the element
 49     returns the WebElement once it is located and visible
 50     """
 51     def __init__(self, locator):
 52         self.locator = locator
 53 
 54     def __call__(self, driver):
 55         try:
 56             return _element_if_visible(_find_element(driver, self.locator))
 57         except StaleElementReferenceException:
 58             return False
 59 
 60 class visibility_of(object):
 61     """ An expectation for checking that an element, known to be present on the
 62     DOM of a page, is visible. Visibility means that the element is not only
 63     displayed but also has a height and width that is greater than 0.
 64     element is the WebElement
 65     returns the (same) WebElement once it is visible
 66     """
 67     def __init__(self, element):
 68         self.element = element
 69 
 70     def __call__(self, ignored):
 71         return _element_if_visible(self.element)
 72 
 73 def _element_if_visible(element, visibility=True):
 74     return element if element.is_displayed() == visibility else False
 75 
 76 class presence_of_all_elements_located(object):
 77     """ An expectation for checking that there is at least one element present
 78     on a web page.
 79     locator is used to find the element
 80     returns the list of WebElements once they are located
 81     """
 82     def __init__(self, locator):
 83         self.locator = locator
 84 
 85     def __call__(self, driver):
 86         return _find_elements(driver, self.locator)
 87 
 88 class text_to_be_present_in_element(object):
 89     """ An expectation for checking if the given text is present in the
 90     specified element.
 91     locator, text
 92     """
 93     def __init__(self, locator, text_):
 94         self.locator = locator
 95         self.text = text_
 96 
 97     def __call__(self, driver):
 98         try :
 99             element_text = _find_element(driver, self.locator).text
100             return self.text in element_text
101         except StaleElementReferenceException:
102             return False
103 
104 class text_to_be_present_in_element_value(object):
105     """
106     An expectation for checking if the given text is present in the element's
107     locator, text
108     """
109     def __init__(self, locator, text_):
110         self.locator = locator
111         self.text = text_
112 
113     def __call__(self, driver):
114         try:
115             element_text = _find_element(driver,
116                                          self.locator).get_attribute("value")
117             if element_text:
118                 return self.text in element_text
119             else:
120                 return False
121         except StaleElementReferenceException:
122                 return False
123 
124 class frame_to_be_available_and_switch_to_it(object):
125     """ An expectation for checking whether the given frame is available to
126     switch to.  If the frame is available it switches the given driver to the
127     specified frame.
128     """
129     def __init__(self, locator):
130         self.frame_locator = locator
131 
132     def __call__(self, driver):
133         try:
134             if isinstance(self.frame_locator, tuple):
135                 driver.switch_to.frame(_find_element(driver,
136                                                      self.frame_locator))
137             else:
138                 driver.switch_to.frame(self.frame_locator)
139             return True
140         except NoSuchFrameException:
141             return False
142 
143 class invisibility_of_element_located(object):
144     """ An Expectation for checking that an element is either invisible or not
145     present on the DOM.
146 
147     locator used to find the element
148     """
149     def __init__(self, locator):
150         self.locator = locator
151 
152     def __call__(self, driver):
153         try:
154             return _element_if_visible(_find_element(driver, self.locator), False)
155         except (NoSuchElementException, StaleElementReferenceException):
156             # In the case of NoSuchElement, returns true because the element is
157             # not present in DOM. The try block checks if the element is present
158             # but is invisible.
159             # In the case of StaleElementReference, returns true because stale
160             # element reference implies that element is no longer visible.
161             return True
162 
163 class element_to_be_clickable(object):
164     """ An Expectation for checking an element is visible and enabled such that
165     you can click it."""
166     def __init__(self, locator):
167         self.locator = locator
168 
169     def __call__(self, driver):
170         element = visibility_of_element_located(self.locator)(driver)
171         if element and element.is_enabled():
172             return element
173         else:
174             return False
175 
176 class staleness_of(object):
177     """ Wait until an element is no longer attached to the DOM.
178     element is the element to wait for.
179     returns False if the element is still attached to the DOM, true otherwise.
180     """
181     def __init__(self, element):
182         self.element = element
183 
184     def __call__(self, ignored):
185         try:
186             # Calling any method forces a staleness check
187             self.element.is_enabled()
188             return False
189         except StaleElementReferenceException as expected:
190             return True
191 
192 class element_to_be_selected(object):
193     """ An expectation for checking the selection is selected.
194     element is WebElement object
195     """
196     def __init__(self, element):
197         self.element = element
198 
199     def __call__(self, ignored):
200         return self.element.is_selected()
201 
202 class element_located_to_be_selected(object):
203     """An expectation for the element to be located is selected.
204     locator is a tuple of (by, path)"""
205     def __init__(self, locator):
206         self.locator = locator
207 
208     def __call__(self, driver):
209         return _find_element(driver, self.locator).is_selected()
210 
211 class element_selection_state_to_be(object):
212     """ An expectation for checking if the given element is selected.
213     element is WebElement object
214     is_selected is a Boolean."
215     """
216     def __init__(self, element, is_selected):
217         self.element = element
218         self.is_selected = is_selected
219 
220     def __call__(self, ignored):
221         return self.element.is_selected() == self.is_selected
222 
223 class element_located_selection_state_to_be(object):
224     """ An expectation to locate an element and check if the selection state
225     specified is in that state.
226     locator is a tuple of (by, path)
227     is_selected is a boolean
228     """
229     def __init__(self, locator, is_selected):
230         self.locator = locator
231         self.is_selected = is_selected
232 
233     def __call__(self, driver):
234         try:
235             element = _find_element(driver, self.locator)
236             return element.is_selected() == self.is_selected
237         except StaleElementReferenceException:
238             return False
239 
240 class alert_is_present(object):
241     """ Expect an alert to be present."""
242     def __init__(self):
243         pass
244 
245     def __call__(self, driver):
246         try:
247             alert = driver.switch_to.alert
248             alert.text
249             return alert
250         except NoAlertPresentException:
251             return False
252 
253 def _find_element(driver, by):
254     """Looks up an element. Logs and re-raises ``WebDriverException``
255     if thrown."""
256     try :
257         return driver.find_element(*by)
258     except NoSuchElementException as e:
259         raise e
260     except WebDriverException as e:
261         raise e
262 
263 def _find_elements(driver, by):
264     try :
265         return driver.find_elements(*by)
266     except WebDriverException as e:
267         raise e
复制代码

哈哈,我相信这个py文件大家一看就能懂。这无非就是一些预期条件。

结合上面的WebDriverWait,我们可以这么用:

复制代码
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

'''
10秒钟等待浏览器弹出的对话框,如果出现,就点击确定按钮
'''
WebDriverWait(chromedriver,10).until(EC.alert_is_present()).accept()
复制代码
我们的自动化脚本跑得快慢或者出现异常,很大程度上取决于我们设定的等待时间,如果你还是习惯于time.sleep(5)这种方式的话,这将会浪费很多时间。
根据expected_conditions.py文件的写法,我们也可以定义一些自己的期待类,例如:
复制代码
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class must_get_url(object):
    '''
    必须到达的URL
       参数:
       url    - 必须到达的地址
    '''
    def __init__(self, url):
        self.url = url

    def __call__(self, driver):
        driver.get(self.url)
        return self.url == driver.current_url

options = webdriver.ChromeOptions()
options.add_argument("--test-type")
chromedriver =     webdriver.Chrome(r"E:\MyProject\WebDriver\chromedriver.exe",chrome_options=options)
WebDriverWait(chromedriver,10).until(must_get_url("https://www.baidu.com"))
 
 
 
 

转载地址:http://www.cnblogs.com/yicaifeitian/p/4749149.html
 
<think>嗯,用户想了解Selenium的学习进阶,首先我需要考虑他们的当前水平。可能他们已经掌握了Selenium的基础,比如元素定位、基本操作等,现在想深入提升。那进阶的内容应该包括哪些呢?框架设计、高级API、并行测试、集成CI/CD这些可能是重点。 框架设计方面,用户可能需要了解如何组织测试用例,比如PO模式,这样代码更易维护。还有数据驱动测试,用外部数据源来参数化测试,提高复用性。测试报告生成也很重要,比如用Allure生成美观的报告,帮助团队分析结果。 然后是高级API,比如处理弹窗、iframe、文件上传下载,这些在实际项目中常见。还有执行JavaScript脚本,处理复杂交互。等待机制也很关键,隐式显式等待的区别应用场景需要解释清楚。 并行测试分布式执行可以提升效率,用Selenium Grid或者Docker容器化技术来实现。集成CI/CD的话,Jenkins、GitHub Actions这些工具如何与Selenium结合,自动化测试流程。 此外,性能优化异常处理也是进阶内容。比如减少不必要的等待时间,处理网络延迟,元素定位失败时的重试机制。还有移动端测试,Appium与Selenium的结合,可能用户也会感兴趣。 最后,推荐一些学习资源,比如官方文档、在线课程,以及开源项目,帮助用户实践。可能需要提醒他们多动手做项目,参与社区,持续学习新技术。要确保内容结构清晰,步骤明确,让用户能一步步提升技能。</think>好的!关于 **Selenium 学习进阶**,以下是系统化的学习路径建议,帮助你从基础到高级逐步掌握自动化测试技能: --- ### **一、基础巩固(必备知识)** 1. **核心组件** - **WebDriver**:掌握不同浏览器(Chrome、Firefox、Edge)的驱动配置。 - **元素定位**:熟练使用 XPath、CSS Selector、ID 等定位策略。 - **常用操作**:点击、输入、表单提交、页面跳转、窗口切换等。 2. **等待机制** - **隐式等待**:`implicitly_wait` 全局等待。 - **显式等待**:`WebDriverWait` + `expected_conditions` 精确控制条件等待。 3. **数据驱动测试** - 使用 `unittest` 或 `pytest` 管理测试用例。 - 参数化测试数据(如 CSV、Excel、JSON)。 --- ### **二、进阶技能(提升效率与稳定性)** 1. **Page Object Model (PO 设计模式)** - 将页面元素操作封装为类,提高代码复用性。 - 示例: ```python class LoginPage: def __init__(self, driver): self.driver = driver self.username = (By.ID, "username") self.password = (By.ID, "password") def login(self, username, password): self.driver.find_element(*self.username).send_keys(username) self.driver.find_element(*self.password).send_keys(password) ``` 2. **高级交互** - **鼠标/键盘操作**:使用 `ActionChains` 实现拖拽、悬停、组合键。 - **文件上传/下载**:处理浏览器弹窗非 HTML 控件。 - **Cookie 管理**:读取、添加、删除浏览器 Cookie。 3. **框架集成** - **测试报告**:集成 `Allure` 或 `HTMLTestRunner` 生成可视化报告。 - **日志记录**:使用 `logging` 模块跟踪测试过程。 - **异常处理**:捕获截图、记录错误信息。 --- ### **三、高阶应用(企业级解决方案)** 1. **分布式测试** - **Selenium Grid**:跨浏览器、跨设备并行执行测试。 - **Docker 化**:通过容器技术快速部署测试环境。 2. **持续集成(CI/CD)** - 集成 Jenkins、GitHub Actions 或 GitLab CI。 - 实现自动化触发测试任务。 3. **性能优化** - 减少不必要的等待时间。 - 使用 Headless 模式(无界面运行)提升速度。 4. **移动端测试** - 结合 **Appium** 实现 Android/iOS 应用自动化。 - 使用 `desired_capabilities` 配置设备参数。 --- ### **四、专项突破(实际场景问题)** 1. **复杂场景处理** - **iframe 切换**:`driver.switch_to.frame()` - **弹窗处理**:Alert、JavaScript 弹窗。 - **动态元素**:XPath 动态表达式(如 `contains()`、`starts-with()`)。 2. **反爬虫绕过** - 修改浏览器指纹(User-Agent、WebGL 参数)。 - 使用代理 IP 池避免封禁。 3. **JavaScript 执行** - 通过 `driver.execute_script()` 调用 JS 代码。 - 示例:滚动页面、修改元素属性。 --- ### **五、学习资源推荐** 1. **官方文档**:[Selenium 官网](https://www.selenium.dev/documentation/) 2. **书籍**: - 《Selenium 自动化测试指南》 - 《Mastering Selenium WebDriver 3.0》 3. **实战项目**: - 电商网站自动化下单流程。 - 社交媒体自动登录与内容抓取。 4. **社区**: - Stack Overflow:解决具体问题。 - GitHub:学习开源项目(如 SeleniumBase、WebDriverManager)。 --- ### **六、关键注意事项** 1. **维护性**:代码需模块化,避免冗余。 2. **稳定性**:增加失败重试机制。 3. **版本兼容**:注意 Selenium、浏览器驱动、浏览器的版本匹配。 通过以上路径,你可以逐步从基础功能测试进阶到复杂的企业级自动化解决方案。**实践是核心**,建议通过实际项目加深理解!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值