等待
WebDriver 通常可以说有一个阻塞 API。因为它是一个指示浏览器做什么的进程外库,而且 web 平台本质上是异步的,所以 WebDriver 不跟踪 DOM 的实时活动状态。
大多数由于使用 Selenium 和 WebDriver 而产生的间歇性问题都与浏览器和用户指令之间的 竞争条件 有关。例如,用户指示浏览器导航到一个页面,然后在试图查找元素时得到一个 no such element 的错误。
测试文档 race_condition.html:
<!doctype html>
<meta charset=utf-8>
<title>Race Condition Example</title>
<script defer>
var initialised = false;
window.addEventListener("load", function() {
var newElement = document.createElement("p");
newElement.textContent = "Hello from JavaScript!";
// 使用 setTimeout() 延时加载
setTimeout(function(){
document.body.appendChild(newElement);
initialised = true;
},2000)
});
</script>
代码
from selenium import webdriver
import os
path = os.path.join(os.getcwd(),'race_condition.html')
driver = webdriver.Chrome()
driver.get(path)
el = driver.find_element_by_tag_name("p")
assert el.text == "Hello from JavaScript!"
因为 p 元素是在文档完成加载之后添加的,所以这个 WebDriver 脚本可能是间歇性的。
幸运的是,WebElement 接口上可用的正常指令集——例如 WebElement.click 和 WebElement.sendKeys—是保证同步的,因为直到命令在浏览器中被完成之前函数调用是不会返回的(或者回调是不会在回调形式的语言中触发的)。高级用户交互APIs,键盘和鼠标是例外的,因为它们被明确地设计为“按我说的做”的异步命令。
等待是在继续下一步之前会执行一个自动化任务来消耗一定的时间。
显式等待
显示等待 是 Selenium 客户可以使用的命令式过程语言。它们允许您的代码暂停程序执行,或冻结线程,直到满足通过的 条件 。这个条件会以一定的频率一直被调用,直到等待超时。这意味着只要条件返回一个假值,它就会一直尝试和等待。
由于显式等待允许您等待条件的发生,所以它们非常适合在浏览器及其 DOM 和 WebDrive r脚本之间同步状态。
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
import os
def document_initialised(driver):
return driver.execute_script("return initialised")
path = os.path.join(os.getcwd(),'race_condition.html')
driver = webdriver.Chrome()
driver.get(path)
WebDriverWait(driver,10).until(document_initialised)
# no such element: Unable to locate element: {"method":"css selector","selector":"p"}
el = driver.find_element_by_tag_name("p")
# el = wait.until(lambda d: d.find_element_by_tag_name("p"))
assert el.text == "Hello from JavaScript!"
将 条件 作为函数引用传递, 等待 将会重复运行直到其返回值为 true。“truthful” 返回值是在当前语言中计算为 boolean true 的任何值,例如字符串、数字、boolean、对象(包括 WebElement )或填充(非空)的序列或列表。这意味着 空列表 的计算结果为 false。当条件为 true 且阻塞等待终止时,条件的返回值将成为等待的返回值。
因为等待实用程序默认情况下会忽略 no such element 的错误,所以我们可以重构我们的指令使其更简洁:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
import os
path = os.path.join(os.getcwd(),'race_condition.html')
driver = webdriver.Chrome()
driver.get(path)
el = WebDriverWait(driver,10).until(lambda d: d.find_element_by_tag_name("p"))
assert el.text == "Hello from JavaScript!"
传递了一个匿名函数。在多线程环境中,您应该小心操作传入条件的驱动程序引用,而不是外部范围中对驱动程序的引用。
因为等待将会吞没在没有找到元素时引发的 no such element 的错误,这个条件会一直重试直到找到元素为止。然后它将获取一个 WebElement 的返回值,并将其传递回我们的脚本。
如果条件失败,例如从未得到条件为真实的返回值,等待将会抛出/引发一个叫 timeout error 的错误/异常。
预期的条件
由于必须同步 DOM 和指令是相当常见的情况,所以大多数客户端还附带一组预定义的 预期条件 。顾名思义,它们是为频繁等待操作预定义的条件。
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
WebDriverWait(driver,10).until(EC.title_is('测试'))
后附 expected_conditions
隐式等待
还有第二种区别于显示等待 类型的 隐式等待 。通过隐式等待,WebDriver 在试图查找_任何_元素时在一定时间内轮询 DOM。当网页上的某些元素不是立即可用并且需要一些时间来加载时是很有用的。
默认情况下隐式等待元素出现是禁用的,它需要在单个会话的基础上手动启用。将显式等待和隐式等待混合在一起会导致意想不到的结果,就是说即使元素可用或条件为真也要等待睡眠的最长时间。
警告: 不要混合使用隐式和显式等待。这样做会导致不可预测的等待时间。例如,将隐式等待设置为10秒,将显式等待设置为15秒,可能会导致在20秒后发生超时。
隐式等待是告诉 WebDriver 如果在查找一个或多个不是立即可用的元素时轮询 DOM 一段时间。默认设置为 0,表示禁用。一旦设置好,隐式等待就被设置为会话的生命周期。
driver = Firefox()
driver.implicitly_wait(10)
driver.get("http://somedomain/url_that_delays_loading")
my_dynamic_element = driver.find_element(By.ID, "myDynamicElement")
流畅等待
流畅等待实例定义了等待条件的最大时间量,以及检查条件的频率。
用户可以配置等待来忽略等待时出现的特定类型的异常,例如在页面上搜索元素时出现的NoSuchElementException。
driver = Firefox()
driver.get("http://somedomain/url_that_delays_loading")
wait = WebDriverWait(driver, 10, poll_frequency=1, ignored_exceptions=[ElementNotVisibleException, ElementNotSelectableException])
element = wait.until(EC.element_to_be_clickable((By.XPATH, "//div")))
expected_conditions
1、title 标题
1)title_is 网页标题是否显示特定内容(必须完全符合)
result = EC.title_is(‘百度一下,你就知道’)
2)title_contains 网页标题是否包含特定内容
result = EC.title_contains(‘百度’)
2、url 网址
1)url_contains 网页网址是否包含特定内容
标签:05,Python,Selenium,元素,driver,EC,element,located,locator From: https://blog.51cto.com/u_1439909/6321643
result = EC.url_contains(‘baidu’)
2)url_matches 网页网址是否匹配特定内容
#url是https://www.baidu.com/
pattern = r’/(\w+)