selenium的三種等待方式


一、背景

UI自動化過程中,必然會遇到環境不穩定,網絡慢情況,加載問題,如果不做任何處理就會因為沒有找到元素而報錯。另外一種情況就是頁面使用了ajax異步加載機制(現在都是resetful,客戶端和服務端都是分離的),不知道頁面是什么時候到達的。這時我們就要用到wait,而在selenium 中,我們一共有三種等待。

固定等待、隱式等待和顯式等待。

 

1、time.sleep(固定等待)  

本質:讓當前的線程睡眠,實質是線程的阻塞(blocking),用wait 方式實現。

缺點:網絡條件好浪費時間,嚴重影響項目的性能

好處:調試腳本可以用

 

2、implicitly_wait(隱式等待)

本質:在腳本的開始設置一個最長等待時間,如果在規定時間內網頁加載完成,則執行下一步;否則可能拋出異常。隱式等待對整個driver周期都起作用,在最開始設置一次就可以了,不要當作固定等待使用。

缺點:javascript一般都是放在我們的body的最后進行加載,實際這時頁面的元素都已經加載完畢,我們卻還在等待全部頁面加載結束。

 

3、WebDriverWait(顯式等待)

本質:動態的等待,判斷某一個元素是不是已經出現了,比如title是不是叫百度或百度搜索,根據動態的一些條件來輪詢,它會不停的輪詢去給我們檢測,條件是成功還是失敗,比如0.5s就檢測一次這個元素在這個條件下是成功還是失敗。同時設置輪詢的超時時間。

 

如果同時設置了顯式等待,和隱式等待,就看誰設置的等待時間長,誰的超時等待時間長,就用誰的執行。

二、WebDriverWait(顯式等待)

1、模塊

from selenium.webdriver.support.wait import WebDriverWait

2、WebDriverWait 的源碼

# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

import time
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import TimeoutException

POLL_FREQUENCY = 0.5  # How long to sleep inbetween calls to the method
IGNORED_EXCEPTIONS = (NoSuchElementException,)  # exceptions ignored during calls to the method


class WebDriverWait(object):
    def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None):
        """Constructor, takes a WebDriver instance and timeout in seconds.

           :Args:
            - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
            - timeout - Number of seconds before timing out
            - poll_frequency - sleep interval between calls
              By default, it is 0.5 second.
            - ignored_exceptions - iterable structure of exception classes ignored during calls.
              By default, it contains NoSuchElementException only.

           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())
        """
        self._driver = driver
        self._timeout = timeout
        self._poll = poll_frequency
        # avoid the divide by zero
        if self._poll == 0:
            self._poll = POLL_FREQUENCY
        exceptions = list(IGNORED_EXCEPTIONS)
        if ignored_exceptions is not None:
            try:
                exceptions.extend(iter(ignored_exceptions))
            except TypeError:  # ignored_exceptions is not iterable
                exceptions.append(ignored_exceptions)
        self._ignored_exceptions = tuple(exceptions)

    def __repr__(self):
        return '<{0.__module__}.{0.__name__} (session="{1}")>'.format(
            type(self), self._driver.session_id)

    def until(self, method, message=''):
        """Calls the method provided with the driver as an argument until the \
        return value is not False."""
        screen = None
        stacktrace = None

        end_time = time.time() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, 'screen', None)
                stacktrace = getattr(exc, 'stacktrace', None)
            time.sleep(self._poll)
            if time.time() > end_time:
                break
        raise TimeoutException(message, screen, stacktrace)

    def until_not(self, method, message=''):
        """Calls the method provided with the driver as an argument until the \
        return value is False."""
        end_time = time.time() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if not value:
                    return value
            except self._ignored_exceptions:
                return True
            time.sleep(self._poll)
            if time.time() > end_time:
                break
        raise TimeoutException(message)

參數

webDriverWait參數 含義
driver 傳入WebDriver實例
timeout 超時時間,等待的最長時間
poll_frequency 調用util或util_not中的方法的間隔時間,默認是0.5s
ignored_exceptions 忽略的異常
方法:util、util_not的參數 說明
method 在等待期內,每隔一段時間調用這個傳入的方法,直到返回值不是False
message 如果超時拋出TimeoutException,將message傳入異常

 

 

 

 

 

 

 

 

 

 

三、三種等待方式的實例

from selenium import webdriver
from time import sleep
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 三種等待方法
class TestCase(object):
    def __init__(self):
        self.driver = webdriver.Chrome()
        self.driver.get('https://www.baidu.com')
        sleep(2)

    def test_sleep(self):
        self.driver.find_element_by_id('kw').send_keys("selenium")
        sleep(2) # 線程的阻塞 blocking wait 方式實現
        self.driver.find_element_by_id('su').click()
        sleep(3)
        self.driver.quit()

    def time_implicitly(self):
        self.driver.implicitly_wait(10)
        self.driver.find_element_by_id('kw').send_keys("webdriver")
        self.driver.find_element_by_id('su').click()
        # sleep(2)
        self.driver.quit()

    def time_wait(self):
        wait = WebDriverWait(self.driver,2,0.5)
        wait.until(EC.title_is('百度一下,你就知道'))
        self.driver.find_element_by_id('kw').send_keys("webdriver")
        self.driver.find_element_by_id('su').click()
        sleep(2)
        self.driver.quit()


if __name__=="__main__":
    case = TestCase()
    # case.test_sleep()
    # case.time_implicitly()
    case.time_wait()

 

題外話:

1、什么是restful:

https://blog.csdn.net/weixin_41229588/article/details/108219391

restful資源表現層狀態轉化

1)資源:比如一段文字,一張圖片,一種服務,一首歌曲等

2)表現層:資源的表現形式。如文本可以用txt格式,html格式,json格式來表現。

3)狀態轉換:http是無狀態協議,所有的狀態都保存在服務器端,因此如果客戶端想要操作服務層,必須通過某種手段,讓服務器發生“狀態轉換”,而這種轉化是建立在表現層之上的,所以就是“表現層狀態轉化”。

4)客戶端用到的手段就是http協議。具體來說就是hppt協議的四種表現方式,如get,post,put,delete。Get 獲取資源,post 用來新建資源(更新資源),put用來更新資源,delete 用來刪除資源。

總結一下什么是restful架構:

每一個uri代表一種資源;客戶端和服務器之間傳遞這種資源的某種表現層;客戶端通過http的四種方法,對服務器資源進行操作,實現表現層狀態轉換。

 

2、什么是ajax:

https://blog.csdn.net/qq_40459545/article/details/111935158

談到ajax,首先說ajax不是javaScript的規范,Asynchronous JavaScript and XML的縮寫,意思就是用JavaScript執行異步網絡請求,Ajax 是一種用於創建快速動態網頁的技術,在無需重新加載整個網頁的情況下,能夠更新部分網頁。

如果仔細觀察一個Form的提交,你就會發現,一旦用戶點擊“Submit”按鈕,表單開始提交,瀏覽器就會刷新頁面,然后在新頁面里告訴你操作是成功了還是失敗了。如果不幸由於網絡太慢或者其他原因,就會得到一個404頁面。

這就是Web的運作原理:一次HTTP請求對應一個頁面。

如果要讓用戶留在當前頁面中,同時發出新的HTTP請求,就必須用JavaScript發送這個新請求,接收到數據后,再用JavaScript更新頁面,這樣一來,用戶就感覺自己仍然停留在當前頁面,但是數據卻可以不斷地更新。

最早大規模使用AJAX的就是Gmail,Gmail的頁面在首次加載后,剩下的所有數據都依賴於AJAX來更新。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM