浏览器导航
导航
启动浏览器后,您要做的第一件事就是打开您的网站。这可以在一行中完成:
driver.get("https://selenium.dev")
获取当前URL
您可以使用以下方法从浏览器的地址栏中读取当前URL:
driver.current_url
返回
按下浏览器的后退按钮:
driver.back()
前进
按下浏览器的前进按钮:
driver.forward()
刷新
刷新当前页面:
driver.refresh()
获取标题
您可以从浏览器中读取当前页面标题:
driver.title
Windows和标签页
获取窗口句柄
WebDriver不会在窗口和选项卡之间进行区分。如果您的站点打开一个新的选项卡或窗口,Selenium将允许您使用窗口句柄来使用它。每个窗口都有一个唯一的标识符,该标识符在单个会话中保持不变。您可以使用以下方法获取当前窗口的窗口句柄:
driver.current_window_handle
切换视窗或标签
单击在新窗口中打开的链接 将使新窗口或屏幕上的标签聚焦,但是WebDriver将不知道操作系统认为哪个窗口处于活动状态。要使用新窗口,您需要切换到新窗口。如果只有两个选项卡或窗口打开,并且您知道从哪个窗口开始,则通过消除过程,您可以遍历WebDriver可以看到的两个窗口或选项卡,然后切换到非原始窗口或选项卡。
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Start the driver
with webdriver.Firefox() as driver:
# Open URL
driver.get("https://seleniumhq.github.io")
# Setup wait for later
wait = WebDriverWait(driver, 10)
# Store the ID of the original window
original_window = driver.current_window_handle
# Check we don't have other windows open already
assertlen(driver.window_handles) ==1
# Click the link which opens in a new window
driver.find_element_by_link_text("new window").click()
# Wait for the new window or tab
wait.until(EC.number_of_windows_to_be(2))
# Loop through until we find a new window handle
for window_handle in driver.window_handles:
if window_handle != original_window:
driver.switch_to.window(window_handle)
break
# Wait for the new tab to finish loading content
wait.until(EC.title_is("SeleniumHQ Browser Automation"))
创建新窗口(或)新标签并切换
创建一个新窗口(或)选项卡,并将新窗口或选项卡聚焦在屏幕上。您无需切换为使用新窗口(或)标签。如果您在新窗口之外打开了两个以上的窗口(或)选项卡,则可以在WebDriver可以看到的两个窗口或选项卡上循环,然后切换到非原始窗口或选项卡。
注意:此功能适用于Selenium 4和更高版本。
# Opens a new tab and switches to new tab
driver.switch_to.new_window('tab')
# Opens a new window and switches to new window
driver.switch_to.new_window('window')
关闭窗口或标签
当完成窗口或选项卡后,它又不是浏览器中打开的最后一个窗口或选项卡,则应将其关闭并切换回以前使用的窗口。假设您遵循了上一节中的代码示例,则将先前的窗口句柄存储在变量中。放在一起,您将获得:
#Close the tab or window
driver.close()
#Switch back to the old tab or window
driver.switch_to.window(original_window)
关闭窗口后忘记忘记切换回另一个窗口句柄,将使WebDriver在现在关闭的页面上执行,并触发No Such Window Exception。您必须切换回有效的窗口句柄才能继续执行。
在会话结束时退出浏览器
完成浏览器会话后,应调用quit而不是close:
driver.quit()
退出将:关闭与该WebDriver会话关联的所有窗口和选项卡
关闭浏览器进程
关闭后台驱动程序
通知Selenium Grid不再使用浏览器,以便其他会话可以使用它(如果您正在使用Selenium Grid)
退出失败将使额外的后台进程和端口在您的计算机上运行,这可能会在以后引起您的问题。
一些测试框架提供了一些方法和注释,您可以将其插入并在测试结束时拆除。
# We don't have a Python code sample yet - Help us out and raise a PR
如果未在测试环境中运行WebDriver,则可以考虑使用try / finally 大多数语言都提供了该功能,因此异常仍将清除WebDriver会话。
try:
#WebDriver code here...
finally:
driver.quit()
Python的WebDriver现在支持python上下文管理器,当使用with关键字时,它可以在执行结束时自动退出驱动程序。
with webdriver.Firefox() as driver:
# WebDriver code here...
# WebDriver will automatically quit after indentation框架和iframe
框架是现在不赞成使用的方法,它可以从同一域中的多个文档构建网站布局。除非您使用HTML5之前的Webapp,否则您不太可能与他们合作。iframe允许从完全不同的域插入文档,并且仍然很常用。
如果您需要使用框架或iframe,Webdriver允许您以相同的方式使用它们。考虑一下iframe中的按钮。如果使用浏览器开发工具检查元素,则可能会看到以下内容:
Click here
如果不是iframe,我们希望使用类似以下内容的按钮:
# This Wont work
driver.find_element_by_tag_name('button').click()
但是,如果iframe外部没有按钮,则可能会收到一个没有此类元素的错误。发生这种情况是因为Selenium仅了解顶级文档中的元素。要与按钮交互,我们将需要首先切换到框架,类似于切换窗口的方式。WebDriver提供了三种切换到框架的方式。
使用WebElement
使用WebElement进行切换是最灵活的选择。您可以使用首选选择器找到框架并切换到该框架。
# Store iframe web element
iframe = driver.find_element_by_css_selector("#modal > iframe")
# switch to selected iframe
driver.switch_to.frame(iframe)
# Now click on button
driver.find_element_by_tag_name('button').click()
使用名称或ID
如果您的框架或iframe具有id或name属性,则可以改用它。如果名称或ID在页面上不是唯一的,则找到的第一个将被切换到。
# Switch frame by id
driver.switch_to.frame('buttonframe')
# Now, Click on the button
driver.find_element_by_tag_name('button').click()
使用索引
也可以使用框架的索引,例如可以使用JavaScript中的window.frames查询。
# Switch to the second frame
driver.switch_to.frame(1)
离开框架
要保留iframe或框架集,请切换回默认内容,如下所示:
# switch back to default content
driver.switch_to.default_content()
窗口管理
屏幕分辨率会影响Web应用程序的呈现方式,因此WebDriver提供了用于移动和调整浏览器窗口大小的机制。
获取窗口大小
获取浏览器窗口的大小(以像素为单位)。
# Access each dimension individually
width = driver.get_window_size().get("width")
height = driver.get_window_size().get("height")
# Or store the dimensions and query them later
size = driver.get_window_size()
width1 = size.get("width")
height1 = size.get("height")
设定视窗大小
恢复窗口并设置窗口大小。
driver.manage().window().setSize(new Dimension(1024, 768));
获取窗口位置
获取浏览器窗口左上角的坐标。
driver.set_window_size(1024, 768)
设定视窗位置
将窗口移到所选位置。
# Access each dimension individually
x = driver.get_window_position().get('x')
y = driver.get_window_position().get('y')
# Or store the dimensions and query them later
position = driver.get_window_position()
x1 = position.get('x')
y1 = position.get('y')
最大化窗口
放大窗口。对于大多数操作系统,窗口将填满整个屏幕,而不会阻塞操作系统自己的菜单和工具栏。
driver.maximize_window()
全屏窗口
填充整个屏幕,类似于在大多数浏览器中按F11键。
driver.fullscreen_window()
等待
WebDriver通常可以说具有阻塞API。因为它是一个进程外库来 指示浏览器该做什么,并且因为Web平台具有本质上异步的性质,所以WebDriver不会跟踪DOM的活动实时状态。这带来了一些挑战,我们将在这里讨论。
根据经验,由于使用Selenium和WebDriver而引起的大多数间歇性问题都与浏览器和用户说明之间发生的争用情况有关。一个示例可能是用户指示浏览器导航到页面,然后在尝试查找元素时收到没有此类元素错误。
参考以下文档:
Race Condition Examplevar initialised = false;
window.addEventListener("load", function() {
var newElement = document.createElement("p");
newElement.textContent = "Hello from JavaScript!";
document.body.appendChild(newElement);
initialised = true;
});
WebDriver的说明可能看起来很简单:
driver.navigate("file:///race_condition.html")
el = driver.find_element_by_tag_name("p")
assert el.text == "Hello from JavaScript!"
这里的问题是, WebDriver中使用的默认 页面加载策略会监听document.readyState 更改为 "complete"从呼叫返回导航之前。因为p元素是在文档完成加载之后添加的,所以此WebDriver脚本可能是间歇性的。“可能”是断断续续的,因为无法保证异步触发的元素或事件会在没有显式等待或阻止这些事件的情况下得到保证。
幸运的是,在WebElement.click和_WebElement.sendKeys_)可以保证是同步的,因为函数调用不会返回(或者回调不会以回调样式的语言触发),直到该命令已在浏览器中完成。高级用户交互API(
等待正在进行的自动任务执行需要一定的时间,然后再继续下一步。
为了克服浏览器和WebDriver脚本之间的竞争状况问题,大多数Selenium客户端附带了一个等待包。在使用等待时,您使用的是通常称为
明确等待
Selenium客户可以使用命令式,程序性语言进行显式等待。它们允许您的代码暂停程序执行或冻结线程,直到传递给它的条件解决为止。以一定的频率调用该条件,直到等待超时超时为止。这意味着只要条件返回虚假值,它将一直尝试并等待。
由于显式等待使您可以等待条件发生,因此它们非常适合在浏览器及其DOM和WebDriver脚本之间同步状态。
为了纠正前面提到的错误指令集,我们可以使用等待来等待findElement调用,直到脚本中动态添加的元素已添加到DOM中为止:
from selenium.webdriver.support.ui import WebDriverWait
def document_initialised(driver):
return driver.execute_script("return initialised")
driver.navigate("file:///race_condition.html")
WebDriverWait(driver).until(document_initialised)
el = driver.find_element_by_tag_name("p")
assert el.text == "Hello from JavaScript!"
我们将条件作为函数引用传入,该等待将重复运行,直到其返回值为true。“真实的”返回值是在手头语言中评估为布尔值true的任何值,例如字符串,数字,布尔值,对象(包括WebElement)或填充的(非空)序列或列表。这意味着一个空列表评估为false。当条件为真且阻塞等待被中止时,条件的返回值将成为等待的返回值。
有了这些知识,并且由于默认情况下wait工具不会忽略任何此类元素错误,因此我们可以将指令重构为更加简洁:
from selenium.webdriver.support.ui import WebDriverWait
driver.navigate("file:///race_condition.html")
el = WebDriverWait(driver).until(lambda d: d.find_element_by_tag_name("p"))
assert el.text == "Hello from JavaScript!"
在该示例中,我们传入了一个匿名函数(但我们也可以像我们之前所做的那样显式定义它,以便可以重用)。传递给我们的条件的第一个也是唯一的参数始终是对驱动程序对象WebDriver的引用 (d在示例中称为)。在多线程环境中,应该小心操作传递给该条件的驱动程序引用,而不是外部作用域中对驱动程序的引用。
因为等待将不会吞没找不到元素时引发的此类元素错误,所以条件将重试直到找到元素。然后它将使用返回值WebElement,并将其传递回我们的脚本。
如果条件失败,例如,从未达到该条件的真实返回值,则等待将抛出/引发一个错误/异常,称为超时错误。
选项(Options)
可以根据您的需要定制等待条件。有时不必等待默认超时的全部时间,因为未达到成功条件的代价可能会很高。
通过等待,您可以传入一个参数来覆盖超时:
WebDriverWait(driver, timeout=3).until(some_condition)
预期条件(Expected conditions)
因为必须同步DOM和您的指令是很常见的事,所以大多数客户端还带有一组预定义的预期条件。顾名思义,它们是为频繁的等待操作预定义的条件。
不同语言绑定中可用的条件各不相同,但这不是其中的一些穷举列表:警报存在
元素存在
元素可见
标题包含
标题是
元素陈旧
可见文字
您可以参考每个客户端绑定的API文档,以找到预期条件的详尽列表:
隐式等待(Implicit wait)
还有另一种类型的等待,不同于 显式等待,称为隐式等待。通过隐式等待,WebDriver在尝试查找任何元素时会轮询DOM一定时间。当网页上的某些元素无法立即使用并且需要一些时间来加载时,这很有用。
默认情况下,隐式等待元素出现是禁用的,需要在每个会话中手动启用。混合显式等待和隐式等待会导致意想不到的后果,即即使元素可用或条件为true,也要等待最长的睡眠时间。
警告: 请勿混合使用隐式和显式等待。这样做可能导致无法预测的等待时间。例如,将隐式等待设置为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")
流畅的等待(FluentWait)
FluentWait实例定义了等待条件的最长时间,以及检查条件的频率。
用户可以配置等待以在等待时忽略特定类型的异常,例如 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")))
网页元素(Keyboard)
表示一个DOM元素。WebElements可以通过使用一个WebDriver实例从文档根目录中搜索,或者在另一个WebElement下搜索:
driver = Firefox()
driver.get("http://www.google.com")
search_form = driver.find_element_by_tag_name("form")
search_box = search_form.find_element_by_name("q")
search_box.send_keys("webdriver")
模拟按键(sendKeys)
即使遇到修改键序列,sendKeys也会在DOM元素中键入一个键序列。
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
# Navigate to url
driver.get("http://www.google.com")
# Enter "webdriver" text and perform "ENTER" keyboard action
driver.find_element_by_name("q").send_keys("webdriver"+Keys.ENTER)
按下键盘(keydown)
keyDown用于模拟按下修改键(CONTROL, SHIFT, ALT)的动作
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
# Navigate to url
driver.get("http://www.google.com")
# Enter "webdriver" text and perform "ENTER" keyboard action
driver.find_element_by_name("q").send_keys("webdriver"+Keys.ENTER)
# Perform action ctrl + A (modifier CONTROL + Alphabet A) to select the page
webdriver.ActionChains(driver).key_down(Keys.CONTROL).send_keys("a").perform()
键盘弹起(keyup)
keyUp用于模拟修改键(CONTROL、SHIFT、ALT)的键释放动作。
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
# Navigate to url
driver.get("http://www.google.com")
# Store google search box WebElement
search = driver.find_element_by_name("q")
action = webdriver.ActionChains(driver)
# Enters text "qwerty" with keyDown SHIFT key and after keyUp SHIFT key (QWERTYqwerty)
action.key_down(Keys.SHIFT).send_keys_to_element(search, "qwerty").key_up(Keys.SHIFT).send_keys("qwerty").perform()
声明:以上文档翻译自selenium官方文档,翻译工具使用Google翻译+有道词典(部分句子略显生硬,后期优化)。
参考