背景历史
2004年Jason Huggins身在ThoughtWorks发起了Selenium项目。
Selenium1.0包括三部分:
- Selenium IDE:嵌入到Firefox浏览器中的一个插件,实现对浏览器操作的录制和回放
- Selenium Grid:实现大量用例的分布式测试
- Selenium RC:Selenium Remote Control,支持多种不同语言编写的测试脚本,去控制访问浏览器,从而达到测试的目的。Selenium RC分为Client Libraries和Selenium Server。Client Libraries库主要用于编写测试脚本,用来控制Selenium Server的库。Selenium Server负责控制浏览器行为。
2006年Google的Simon Stewart发起了WebDriver项目。
WebDriver是通过原生浏览器支持或者浏览器扩展来直接控制浏览器。WebDriver针对各个浏览器而开发,取代了嵌入到被测Web应用中的JavaScript,与浏览器紧密集成,因此支持创建更高级的测试,避免了JavaScript安全模型导致的限制。除了来自浏览器厂商的支持之外,WebDriver还利用操作系统级的调用,模拟用户输入。
2009年,Selenium和Webdriver合并,2011年Selenium2.0诞生。
Selenium2.0包含四个部分:
- Selenium IDE
- Selenium Grid
- Selenium RC
- WebDriver:利用浏览器原生的API,封装成一套更加面向对象的API,直接操作浏览器页面里的元素,甚至操作浏览器本身(截屏,窗口大小,启动,关闭,安装插件,配置证书之类的)。由于使用的是浏览器原生的API,速度得到了大大提高。
WebDriver作为Selenium RC的替代方案,成为Selenium2.0的核心功能。
2016年7月,Selenium3.0版本发布
- 去掉了Selenium RC
- 需要java8以上版本
- Selenium的Firefox浏览器需要单独的驱动
- Mac OS集成Safari浏览器驱动,默认路径:/usr/bin/safaridriver
2021年10月13日,Selenium4.0发布
- 需要Python3.7以上版本
- capabilities书写格式变更
- 定位元素方法格式变更find_element_by_xxx(‘yyy’)改为find_element(By.xxx,’yyy’)
- executable_path语法废弃,使用Serviece方式替代
- 新增相对定位方法
Selenium特点
- 免费开源
- 支持多平台:Windows、Mac、Linux
- 支持多种编程语言:Java、C、C++、Python、Ruby、PHP、Perl、JavaScript等
- 支持多种浏览器:Firefox、Chome、Safari、Edge、Opera、IE等
- 支持分布式运行测试
(本系列文章中,不会介绍关于IE浏览器的测试,IE浏览器已于2022年6月15日停止维护!)
环境搭建
安装Selenium (这里使用最新版本4)
$ pip install selenium
本机的python高于3.7,默认会安装最新版本,当前是4.8.0
下载浏览器
Firefox:https://www.mozilla.org/zh-CN/firefox/enterprise/ (这里使用延长支持版)
Chrome:https://www.chromedownloads.net/chrome64osx/ (这里是历史版本的下载)
Edge:https://www.microsoft.com/zh-cn/edge/download?form=MA13FJ
Safari:Mac系统自带浏览器。(Windows版本已于2012年停止更新)
(浏览器版本不建议安装最新版,而是安装稳定版)
下载浏览器驱动
(下载的浏览器驱动,需要与浏览器的版本对应上,否则无法调起浏览器报错)
Firefox Driver:https://github.com/mozilla/geckodriver/releases/
Chrome Driver:http://chromedriver.storage.googleapis.com/index.html
https://registry.npmmirror.com/binary.html?path=chromedriver/
Edge Driver:https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
Safari Driver:随系统安装会自动安装驱动。
- Safari11.1及之前的版本:
- 浏览器偏好设置 - 高级 - 在菜单栏中显示“开发”菜单
- 浏览器开发菜单 - 允许远程自动化
- 授权safaridriver启动托管本地web服务器的XPC服务。要允许此操作,请手动运行
/usr/bin/safridriver
一次,然后按照身份验证提示进行操作。
- Safari12及之后的版本,需执行
safaridriver --enable
下载下来的驱动程序,需要存放到一个在系统环境变量中定义了的位置:
- Mac下,可以将浏览器的驱动文件存放在
/usr/local/bin
,也可以是Python的bin目录 - Windows下,可以将浏览器的驱动文件存放在
Windows/system32
,也可以是Python的bin目录
上面只是给了个例子,也可以存放在其他目录中,但必须是在系统环境变量中进行了定义的。后续的项目实战中,会将驱动文件存放在项目的lib目录中,使用代码指定驱动程序的路径,而不是在环境变量中定义,以方便管理。
Selenium原理
上面介绍selenium历史的时候,已经得知从3.0版本已经去掉了RC模块,由WebDriver来取代RC模块,即使用封装好的WebDriver API来操作浏览器及网页元素。(下面介绍的所有的Webdriver的语法、操作等都是在介绍API的使用。)
但,目前很多网上的最新教程虽然介绍的是selenium3或4,但原理还是讲“Remote Control、Client Libraries和Selenium Server”,这是错误的。selenium3或4,已经没有RC(Remote Control)模块了。
WebDriver是W3C的一个标准( https://w3c.github.io/webdriver/ ),WebDriver与浏览器之间的交互是标准的Server-Client的模式,Server是Remote Server端,是任意的浏览器;Client是测试脚本(testcase)。(客户端Client发送一个request请求,服务器端返回一个response响应数据)
WeiDriver的工作流程可以简单的描述为:
- 创建一个WebDriver实例,启动目标浏览器,并绑定到指定端口。启动的浏览器将作为WebDriver的Remote Server。
- Client端通过CommandExcuter发送HTTP Request给Remote Server的侦听端口。
- Remote Server需要依赖浏览器驱动,例如Firefox Driver等,来转化成浏览器的原生操作。

其中第2、3步骤不需要我们干预,我们只需要掌握第1步骤中测试脚本的设计,即如何使用WebDriver APIs对driver传送指令、传送什么指令。
测试代码发送指令给浏览器驱动,浏览器驱动通过“JsonWireProtocol”(基于HTTP通信)将指令转成浏览器的原生操作。
比如:site-packages/selenium/webdriver/remote/webdriver.py
中driver.get()
get方法的源码:
......
def execute(self, driver_command: str, params: dict = None) -> dict:
"""Sends a command to be executed by a command.CommandExecutor.
:Args:
- driver_command: The name of the command to execute as a string.
- params: A dictionary of named parameters to send with the command.
:Returns:
The command's JSON response loaded into a dictionary object.
"""
params = self._wrap_value(params)
if self.session_id:
if not params:
params = {"sessionId": self.session_id}
elif "sessionId" not in params:
params["sessionId"] = self.session_id
response = self.command_executor.execute(driver_command, params)
if response:
self.error_handler.check_response(response)
response["value"] = self._unwrap_value(response.get("value", None))
return response
# If the server doesn't send a response, assume the command was
# a success
return {"success": 0, "value": None, "sessionId": self.session_id}
def get(self, url: str) -> None:
"""Loads a web page in the current browser session."""
self.execute(Command.GET, {"url": url})
......
调用get()
方法,会执行execute(Command.GET, url)
方法,通过上面的注释信息可以得到“Sends a command to be executed by a command.CommandExecutor”调用execute()
方法就会通过command.CommandExecutor
去执行一个命令,这里的命令是Command.GET
,对应到remote_connection.py源代码中的
......
self._commands = {
Command.NEW_SESSION: ("POST", "/session"),
Command.QUIT: ("DELETE", "/session/$sessionId"),
Command.W3C_GET_CURRENT_WINDOW_HANDLE: ("GET", "/session/$sessionId/window"),
Command.W3C_GET_WINDOW_HANDLES: ("GET", "/session/$sessionId/window/handles"),
Command.GET: ("POST", "/session/$sessionId/url"),
......
这里的session、sessionId指的是remote server和浏览器的会话,通过这个会话变成对浏览器的操作。
基础语法
创建测试
创建一个py文件,导入webdriver
# 导入selenium模块的webdriver函数
from selenium import webdriver
# 通过“webdriver.浏览器”获得一个浏览器对象
# browser是变量名,可以是任意名,但一般情况指定为"driver"或"browser"
browser = webdriver.Chrome()
# browser = webdriver.Safari()
# browser = webdriver.Firefox()
# browser = webdriver.Edge()
运行上面的代码,可以正确调起对应的浏览器,表示环境已经配置正确。
若浏览器的版本号与driver的版本号不匹配,就会出现类似下面的报错:
selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of Microsoft Edge WebDriver only supports Microsoft Edge version 110
Current browser version is 108.0.1462.76 with binary path /Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge
通过selenium访问一个网址
# 导入selenium模块的webdriver函数
from selenium import webdriver
# 通过webdriver.浏览器获得一个浏览器对象
# browser是变量名,可以是任意名,但一般情况指定为"driver"或"browser"
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/"
# 访问指定的网址
browser.get(url)
运行上面的代码

操作浏览器
控制浏览器窗口大小
通过
set_window_size()
方法来设置浏览器的窗口大小from selenium import webdriver browser = webdriver.Firefox() url = "http://101.43.8.10:9696/" # 访问指定的网址 browser.get(url) # 设置浏览器窗口大小为(1280,800) browser.set_window_size(1280, 800)
控制浏览器页面后退、前进
通过
back()
方法和forward()
方法来实现页面的后退和前进操作from selenium import webdriver browser = webdriver.Firefox() # 实例网站:SHOPWIND商城 url1 = "http://101.43.8.10:9696/" # 实例网站:ShopXO商城 url2 = "http://101.43.8.10:6996/" # 访问指定的网址 browser.get(url1) browser.get(url2) # 从url2回退到url1 browser.back() # 从url1前进到url2 browser.forward()
浏览器页面刷新
通过
refresh()
方法实现浏览器的页面刷新from selenium import webdriver browser = webdriver.Firefox() # 实例网站:SHOPWIND商城 url = "http://101.43.8.10:9696/" # 访问指定的网址 browser.get(url) # 刷新浏览器页面 browser.refresh()
最大化、最小化浏览器窗口
通过使用
maximize_window()
方法和minimize_window()
方法实现最大化及最小化浏览器窗口from selenium import webdriver browser = webdriver.Firefox() # 实例网站:SHOPWIND商城 url = "http://101.43.8.10:9696/" # 访问指定的网址 browser.get(url) # 最大化浏览器窗口 browser.maximize_window() # 最小化浏览器窗口 browser.minimize_window()
关闭标签页
通过使用
close()
方法来关闭浏览器的标签页from selenium import webdriver browser = webdriver.Firefox() # 实例网站:SHOPWIND商城 url = "http://101.43.8.10:9696/" # 访问指定的网址 browser.get(url) # 关闭标签页 browser.close()
关闭浏览器
通过使用
quit()
方法来关闭浏览器from selenium import webdriver browser = webdriver.Firefox() # 实例网站:SHOPWIND商城 url = "http://101.43.8.10:9696/" # 访问指定的网址 browser.get(url) # 关闭浏览器 browser.quit()
获取浏览器属性
可以通过浏览器对象,获取对象的相关属性:
title:页面标题
current_url:当前页面地址
page_source:页面的源代码
(还有句柄相关属性,会在后续内容进行介绍)
from selenium import webdriver browser = webdriver.Firefox() # 实例网站:SHOPWIND商城 url = "http://101.43.8.10:9696/" # 访问指定的网址 browser.get(url) # 打印输出页面标题 print(browser.title) # 打印输出页面url print(browser.current_url) # 关闭标签页 browser.close()
执行代码
ShopWind开源电商系统 - 专业的B2B2C电商系统解决方案 - Powered by ShopWind http://101.43.8.10:9696/
打印输出源代码内容较多,这里不进行演示。
8大页面元素定位方式
定位页面元素有以下8种:
- id 通过元素的id值进行定位,一个html中每个id是唯一的。如果有id,id定位是首选!
- name 通过元素的名称name属性进行定位,name不是唯一的,可以重名
- class name 通过元素的类名来定位
- link text 通过link_text定位超链接文本的
- partial link text 是link_text的模糊搜索模式
- tag name 通过标签tag进行定位,不建议使用
- xpath 通过元素路径进行定位,最为推荐使用的定位方式 ( XPath详解 )
- css selector 通过css选择器进行定位,是比较推荐的一种定位方式
在实际工作中,一般以xpath或css_selector为主(xpath和css_selector二选一,不建议混合使用),以id、name为辅(在实际工作中,不是所有元素都有id,name存在重复定义现象等)
定位元素使用使用:
find_element("", "") # 定位一个元素,第一个“”中为上面8种方式之一,第二个“”为对应的值
find_elements("", "") # 定位一组元素,第一个“”中为上面8种方式之一,第二个“”为对应的值
find_element_by_xx()
已经弃用。
通过实例网页来演示8种定位方式的使用
SHOPWIND商城登录页:http://101.43.8.10:9696/login.html
By id
from selenium import webdriver
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("id", "username").send_keys('buyer')
browser.find_element("id", "password").send_keys('123456')
browser.quit()
执行上面代码,可以看到成功定位到了username和password两个元素,并在其中输入了对应的值。
其中,
send_keys()
,是向可输入的控件中输入指定内容
另,在执行测试时发现输入框中默认带了指定值,通过send_keys()
输入值导致输入框的值变成了“buyerbuyer”,“123456123456”,重复了。这需要在执行输入前,先使用clear()
清空输入框的默认值。
from selenium import webdriver
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("id", "username").clear()
browser.find_element("id", "username").send_keys('buyer')
browser.find_element("id", "password").clear()
browser.find_element("id", "password").send_keys('123456')
browser.quit()
By name
from selenium import webdriver
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("name", "username").clear()
browser.find_element("name", "username").send_keys('buyer')
browser.find_element("name", "password").clear()
browser.find_element("name", "password").send_keys('123456')
browser.quit()
By class name
登录页面的“登录”按钮可以通过class name
进行定位
from selenium import webdriver
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("name", "username").clear()
browser.find_element("name", "username").send_keys('buyer')
browser.find_element("name", "password").clear()
browser.find_element("name", "password").send_keys('123456')
browser.find_element("class name", 'login-submit').click()
browser.quit()
其中,click()
是对定位到的元素执行鼠标点击操作
By link text
页面上的“立即注册”按钮可以使用link text
方式进行定位
from selenium import webdriver
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("link text", "立即注册").click()
browser.quit()
By partial link text
页面上的“立即注册”按钮可以使用partial link text
方式进行定位,这里使用“立即”两个字
from selenium import webdriver
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("partial link text", "立即").click()
browser.quit()
By xpath
from selenium import webdriver
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("xpath", '//input[@placeholder="用户名"]').clear()
browser.find_element("xpath", '//input[@name="username"]').send_keys('buyer')
browser.find_element("xpath", '//input[@type="password"]').clear()
browser.find_element("xpath", '//input[@name="password"]').send_keys('123456')
browser.find_element("xpath", '//input[@title="登录"]').click()
browser.quit()
By css selector
通过CSS选择器进行定位,需要对CSS比较了解,这里不再详细描述CSS相关的知识。
下面是通过id及标签的层级关系进行定位
from selenium import webdriver
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("css selector", '#username').clear()
browser.find_element("css selector", '#username').send_keys('buyer')
browser.find_element("css selector", '#password').clear()
browser.find_element("css selector", '#password').send_keys('123456')
browser.find_element("css selector", '#login_form > dl:nth-child(4) > dd > input.login-submit').click()
browser.quit()
By tag name
找不到合适的例子举例,tag name
,是非常不推荐的定位方式。
除了上面的定位方式外,还可以通过下面的方式进行定位,效果是一样的,这里不再详细说明。
from selenium.webdriver.common.by import By browser.find_element(By.ID, 'username') browser.find_element(By.NAME, 'username') browser.find_element(By.CLASS_NAME, 'username') browser.find_element(By.LINK_TEXT, '立即注册') browser.find_element(By.PARTIAL_LINK_TEXT, '立即') browser.find_element(By.XPATH, '//input[@placeholder="用户名"]') browser.find_element(By.CSS_SELECTOR, '#username') browser.find_element(By.TAG_NAME, '')
3种等待模式
上面的代码,在执行时,都是一闪而过。在真实的手动操作时,操作网页都有个加载过程,极快的代码执行速度会有可能导致页面元素还没有加载出来,代码已经执行到下一步骤,导致程序误判没有找到对应的元素而执行失败。这就需要在代码中适当的位置加入等待时间。
selenium提供了3种等待方式:
- 强制等待
- 隐性等待(智能等待)
- 显性等待(智能等待)
强制等待
使用time模块
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("css selector", '#username').clear()
browser.find_element("css selector", '#username').send_keys('buyer')
browser.find_element("css selector", '#password').clear()
browser.find_element("css selector", '#password').send_keys('123456')
time.sleep(2) # 等待2秒
browser.find_element("css selector", '#login_form > dl:nth-child(4) > dd > input.login-submit').click()
time.sleep(2) # 等待2秒
browser.quit()
可以看到在点击登录按钮前和后各等待了2秒(sleep(2)
),但这个时间写死的,固定一定要等2秒+2秒。这样有个坏处,就是若执行脚本时网络环境差,进行了10秒才点击了登录按钮,这时等待2秒杀就已经报错了;亦或者,0.5秒钟已经点击完成了登录,但设置等待了2秒,这样整个执行过程就多耗时了1.5秒。
隐性等待
通过selenium提供的implicitly_wait()
方法等待元素出现。比如设置了10秒implicitly_wait(10)
,若元素1秒即可加载出来,那么加载出来后即结束等待,即1秒后就开始执行下面的代码。若元素等待了10秒钟后还没有显示出来,那么就会直接执行下面的代码,引起报错。
隐性等待,是全局的等待时间,只需设置一次。
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
browser.find_element("css selector", '#username').clear()
browser.find_element("css selector", '#username').send_keys('buyer')
browser.find_element("css selector", '#password').clear()
browser.find_element("css selector", '#password').send_keys('123456')
browser.find_element("css selector", '#login_form > dl:nth-child(4) > dd > input.login-submit').click()
browser.quit()
隐性等待只能用于查找元素、等待元素出现,即find_element()
显性等待
通过selenium提供的WebDriverWait()
类,等待当前要操作的元素
from selenium.webdriver.support.wait import WebDriverWait
通过selenium提供的expected_conditions模块,判断等待条件是否满足
from selenium.webdriver.support import expected_conditions
expected_conditions
提供了很多个判断方法,这里只举一个最常用的presence_of_element_located()
元素是否存在(默认每0.5秒去判断一次,这个频率可以自己设置poll_frequency=0.5
,一般无需改动)。
wait等待。。。直到util。。。判断方法presence_of_element_located
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696/login.html"
# 访问指定的网址
browser.get(url)
browser.find_element("css selector", '#username').clear()
browser.find_element("css selector", '#username').send_keys('buyer')
browser.find_element("css selector", '#password').clear()
browser.find_element("css selector", '#password').send_keys('123456')
browser.implicitly_wait(10)
browser.find_element("css selector", '#login_form > dl:nth-child(4) > dd > input.login-submit').click()
# 定义定位元素的方法及对应值
loc = ('xpath', '//*[@id="main"]/div/div/p/b')
# 最多等5秒,判断上面定义的元素是否存在
WebDriverWait(browser, 5).until(expected_conditions.presence_of_element_located(loc))
# 返回定位到的元素的文本信息
text = browser.find_element(*loc).text
# 断言文本信息是否等于登录成功
assert text == "登录成功"
上面的代码是显性等待的例子,是否有必要添加等待,需要根据实际情况来判断,这里只是演示要添加显示等待的基本方法。
3大切换
handle窗口切换
当点击页面上的某个元素后,会重新打开一个页签,这时代码操作在停留在上一个页签,若要操作新开的页签页面中的内容,就要进行handle窗口切换。
from selenium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
browser = webdriver.Firefox()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.find_element('xpath', '//a[@class="login-btn"]').click()
time.sleep(1)
browser.find_element("xpath", '//input[@placeholder="用户名"]').clear()
browser.find_element("xpath", '//input[@name="username"]').send_keys('buyer')
browser.find_element("xpath", '//input[@type="password"]').clear()
browser.find_element("xpath", '//input[@name="password"]').send_keys('123456')
browser.find_element("xpath", '//input[@title="登录"]').click()
browser.implicitly_wait(10)
loc = ('xpath', '//*[@id="main"]/div/div/p/b')
WebDriverWait(browser, 5).until(expected_conditions.presence_of_element_located(loc))
text = browser.find_element(*loc).text
assert text == "登录成功"
time.sleep(2)
# 点击页面头部的banner广告,在新页签打开页面
browser.find_element("xpath", "//img[@class='lazyload block']").click()
# 打印全部的窗口信息
print(browser.window_handles)
# 打印当前正在操作的窗口信息
print(browser.current_window_handle)
# 切换到新开的页面窗口
browser.switch_to.window(browser.window_handles[-1])
time.sleep(1)
# 打印当前正在操作的窗口信息
print(browser.current_window_handle)
# 获取新开页面的元素内容
text1 = browser.find_element("xpath", "//div[@class='channel2-special-goods']//h2").text
print(text1)
time.sleep(5)
browser.quit()
上面的代码进行了窗口切换的演示,为了方便演示加入了较多的time.sleep()
其中,
- window_handles:获取当前打开的所有窗口句柄,返回类型为一个列表;
- current_window_handle:获取当前正在操作的窗口句柄;
- switch_to.window():切换窗口,需要传递一个参数,代表切换到哪个窗口;
还有另外一个判断方法,先通过window_handles获取全部打开的句柄handles,然后执行新开窗口的操作,通过new_window_is_opened()
方法判断是否有新句柄(新的句柄总数大于之前的句柄总数)
WebDriverWait(browser, 5).until(expected_conditions.new_window_is_opened(handles))
iframe切换
iframe表示在html中再嵌入一层或多层html。目前的网站,多数都是使用框架写的,很少再有iframe了。这里只列举几个iframe切换的常用方法,不再进行举例说明。(很老旧的一些系统、网站还是有iframe的)
- switch_to.frame():切换到frame,需要一个参数,frame名称、frame下标或WebElement对象均可
- switch_to.default_content():切换到主html页面
- switch_to.parent_frame():切换到上一层html页面(父页面)
当定位的iframe可以用时自动切换过去:
WebDriverWait(browser, 5).until(expected_conditions.frame_to_be_available_and_switch_to_it(iframe))
alert弹窗切换
alert弹窗,即浏览器原生的弹窗。由于目前网站都是使用框架,alert弹窗都变成了框架或开发自己写的弹窗,即alert弹窗也较少使用。这里只列举几个alert弹窗切换的常用方法,不再进行举例说明。
- switch_to.alert:切换到alert弹框
- accept():确定
- dismiss():取消
等待alert弹出并自动切换WebDriverWait(browser, 5).until(expected_conditions.alert_is_present)
常用操作
鼠标操作
鼠标操作一般包括:单击、双击、右击、光标悬停、拖拽等,下面逐一介绍。
单击
前面已经介绍了browser.find_element('', '').click()
这种形式的单击操作,接下来通过selenium提供的ActionChains
模块来模拟鼠标操作,下面的几个鼠标事件都有这个模块进行实现。
from selenium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
# 定义一个鼠标模拟对象
action = ActionChains(browser)
# 定位登录按钮
login = browser.find_element('xpath', '//a[@class="login-btn"]')
# 点击登录按钮,通过perform进行执行
action.click(login).perform()
time.sleep(5)
browser.quit()
上面的关键代码可以写成一行
ActionChains(browser).click(browser.find_element('xpath', '//a[@class="login-btn"]')).perform()
可以看到通过ActionChains
提供的单击操作复杂很多,更建议执行使用browser.find_element('', '').click()
。
光标悬停
通过ActionChains
的move_to_element
悬停指定元素上
from selenium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
# 定义一个鼠标模拟对象
action = ActionChains(browser)
# 定位左侧导航家电五金
jiadian = browser.find_element('link text', '家用电器、五金')
# 光标移动到家电元素位置悬停
action.move_to_element(jiadian).perform()
time.sleep(5)
browser.quit()
拖拽
通过ActionChains
的move_to_element
悬停指定元素上
source = driver.find_element('xpath','//*[@id="1"]/div/div[3]/div/div[1]')
time.sleep(1)
target = driver.find_element('xpath','//*[@id="4"]/div/div/div')
time.sleep(1)
# 从source的位置拖拽到target的位置,source是指按下鼠标的位置,target是指抬起鼠标按键的位置
ActionChains(driver).drag_and_drop(source,target).perform()
双击
通过double_click()
,实现双击,这里只做一下简单演示。
# 定义一个鼠标模拟对象
action = ActionChains(browser)
# 定位登录按钮
login = browser.find_element('xpath', '//a[@class="login-btn"]')
# 双击登录按钮
action.double_click(login).perform()
右击
通过context_click()
,实现鼠标右击,这里只做一下简单演示。
# 定义一个鼠标模拟对象
action = ActionChains(browser)
# 定位登录按钮
login = browser.find_element('xpath', '//a[@class="login-btn"]')
# 鼠标右击登录按钮
action.context_click(login).perform()
键盘操作
单个控件的操作
通过导入Keys模块,来实现通过代码实现键盘操作
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
dlb=browser.find_element('xpath', '//a[@class="login-btn"]')
dlb.send_keys(Keys.ENTER)
dlb.send_keys(Keys.CONTROL, Keys.ALT, Keys.SPACE)
全局操作
通过ActionChains模块,来实现通过代码实现键盘操作,对整个页面有效
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
ac = ActionChains(browser)
ac.send_keys(Keys.CONTROL, Keys.SPACE).perform()
ac.send_keys(Keys.CONTROL,‘a’).perform()
ac.send_keys(Keys.F1).perform()
下拉列表
下拉列表,即select标签,selenium中提供了对应的模块进行操作。(注意,目前有很多所谓的下拉列表,并不是通过select标签实现的)
from selenium import webdriver
import time
from selenium.webdriver.support.select import Select
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
browser.find_element('xpath', '//a[@class="login-btn"]').click()
time.sleep(1)
browser.find_element("xpath", '//input[@placeholder="用户名"]').clear()
browser.find_element("xpath", '//input[@name="username"]').send_keys('buyer')
browser.find_element("xpath", '//input[@type="password"]').clear()
browser.find_element("xpath", '//input[@name="password"]').send_keys('123456')
browser.find_element("xpath", '//input[@title="登录"]').click()
browser.implicitly_wait(10)
browser.get('http://101.43.8.10:9696/my_address/index.html')
browser.find_element("xpath", "//div[@class='eject_btn']").click()
# 定位select元素
select_el1 = browser.find_element("xpath", "//div[@id='region']//select")
# 获取select对象
select_el_list1 = Select(select_el1)
# 通过索引选择下拉框中的数据,注意第一个值的索引是0,这个网站,第一个值为”请选择“
select_el_list1.select_by_index(10)
time.sleep(1)
# 定位select二级元素
select_el2 = browser.find_element("xpath", "//select[2]")
select_el_list2 = Select(select_el2)
time.sleep(1)
select_el_list2.select_by_index(1)
time.sleep(1)
# 通过html页面中的value值进行下拉框数据的选择
select_el_list1.select_by_value('2')
time.sleep(1)
# 通过下拉选项值的文本内容进行选择
select_el_list1.select_by_visible_text("河北省")
time.sleep(5)
browser.quit()
其中,先进行元素定位,将定位到的元素以参数形式传给Select(),获得下拉框选项内容的WebElement。通过索引select_by_index()
、值select_by_value()
或文本select_by_visible_text()
的形式来选择具体的值。
除了上面的select专属方式,也可以通过点击展开下拉列表,然后点击要选择的元素进行选择。
checkbox
这里使用12306网站的作为例子,勾选车次类型演示checkbox的操作
import time
from selenium import webdriver
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E4%B8%8A%E6%B5%B7,SHH&ts=%E5%8C%97%E4%BA%AC,BJP&date=2023-01-29&flag=N,N,Y"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
# 定位车次类型,这次返回的是一个列表
train_types = browser.find_elements("name", "cc_type")
# 遍历列表,勾选每一个选项
for train_type in train_types:
# 判断type属性是否等于checkbox
if train_type.get_attribute("type") == "checkbox":
train_type.click()
# 勾选某个选项
# train_types[1].click()
time.sleep(5)
browser.quit()
radiobox
import time
from selenium import webdriver
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E4%B8%8A%E6%B5%B7,SHH&ts=%E5%8C%97%E4%BA%AC,BJP&date=2023-01-29&flag=N,N,Y"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
# 单程往返单选框,组定位,返回一个列表
come_go = browser.find_elements("name", "singleRoundType")
# 本例子中只有两个选项:单程和往返,这里勾选往返
come_go[1].click()
time.sleep(5)
browser.quit()
submit()
按钮的type类型若为submit,在点击按钮的时候,可以使用submit()来代替click()
from selenium import webdriver
import time
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
browser.find_element('xpath', '//a[@class="login-btn"]').click()
time.sleep(1)
browser.find_element("xpath", '//input[@placeholder="用户名"]').clear()
browser.find_element("xpath", '//input[@name="username"]').send_keys('buyer')
browser.find_element("xpath", '//input[@type="password"]').clear()
browser.find_element("xpath", '//input[@name="password"]').send_keys('123456')
browser.find_element("xpath", '//input[@title="登录"]').submit()
time.sleep(5)
browser.quit()
JS操作
某些情况下,使用selenium无法或者较难实现的时候,通过调用JS代码可以曲线实现。通过execute_script()
方法
修改控件属性
例如有些需要操作的控件,设置成了readonly只读或者disabled置灰无法进行值的输入,可以通过JS代码去掉对应的属性,即可继续使用selenium操作。这里的例子是12306网站,在没有选择往返程时,返程时间控件是置灰的无法操作,这里通过JS去掉disabled属性
import time
from selenium import webdriver
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E4%B8%8A%E6%B5%B7,SHH&ts=%E5%8C%97%E4%BA%AC,BJP&date=2023-01-29&flag=N,N,Y"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
data = browser.find_element("xpath", "//input[@id='train_date']")
browser.find_element("xpath", "//input[@id='train_date']").clear()
time.sleep(1)
browser.find_element("xpath", "//input[@id='train_date']").send_keys("2023-02-02")
back_train_date = browser.find_element("id", "back_train_date")
# 当前返程日期控件为置灰的,需要去掉disabled属性
js = "let el=arguments[0];el.removeAttribute('disabled')"
# 执行js
browser.execute_script(js, back_train_date)
time.sleep(1)
browser.find_element("id", "back_train_date").clear()
browser.find_element("id", "back_train_date").send_keys("2023-02-05")
time.sleep(30)
browser.quit()
滑动滚动条
定位元素、操作元素,是无需一定要元素可见的,即当前窗口中没有显示出元素,但页面已经加载完,元素也已经加载,只是没有显示(需要拖拽滚动即可让元素显示出来的),这种情况是无需进行滑动滚动条的。
滑动滚动条的应用场景是:页面存在懒加载或慢加载的情况下,必须将页面滚动条拖拽到某个位置,对应的元素才被加载出来,这样才能定位到元素进行操作。
scrollTo 滚动到
scrollTo(0, document.body.scrollHeight)
从顶部滚动到底部scrollTo(document.body.scrollHeight, 0)
从底部滚动到底部scrollTo(0, document.body.scrollHeight / 2)
从顶部滚动到页面中间位置from selenium import webdriver import time browser = webdriver.Chrome() # 实例网站:SHOPWIND商城 url = "http://101.43.8.10:9696" # 访问指定的网址 browser.get(url) browser.implicitly_wait(10) browser.execute_script("scrollTo(0, document.body.scrollHeight)") time.sleep(1) browser.execute_script("scrollTo(document.body.scrollHeight, 0)") time.sleep(1) browser.execute_script("scrollTo(0, document.body.scrollHeight / 2)") time.sleep(5) browser.quit()
scrollBy 滚动(xx像素)
from selenium import webdriver import time browser = webdriver.Chrome() # 实例网站:SHOPWIND商城 url = "http://101.43.8.10:9696" # 访问指定的网址 browser.get(url) browser.implicitly_wait(10) # 页面向下滚动500像素高度 browser.execute_script("scrollBy(0, 500)") time.sleep(5) browser.quit()
scrollIntoView 滚动到元素
from selenium import webdriver import time browser = webdriver.Chrome() # 实例网站:SHOPWIND商城 url = "http://101.43.8.10:9696" # 访问指定的网址 browser.get(url) browser.implicitly_wait(10) login_btn = browser.find_element('xpath', '//a[@class="login-btn"]') # 滚动到登录按钮,顶部对齐 browser.execute_script("arguments[0].scrollIntoView()", login_btn) time.sleep(2) # 滚动到登录按钮,底部对齐 browser.execute_script("arguments[0].scrollIntoView(false)", login_btn) time.sleep(5) browser.quit()
selenium提供了
location_once_scrolled_into_view
方法来实现滚动到元素对应位置from selenium import webdriver import time browser = webdriver.Chrome() # 实例网站:SHOPWIND商城 url = "http://101.43.8.10:9696" # 访问指定的网址 browser.get(url) browser.implicitly_wait(10) login_btn = browser.find_element('xpath', '//a[@class="login-btn"]') # 滚动条滚动到登录按钮的位置 login_btn.location_once_scrolled_into_view time.sleep(5) browser.quit()
上传
send_keys
若上传文件的控件是由input
标签及type="file"
,那么可以直接使用send_keys
直接传递上传文件即可
from selenium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
browser.find_element('xpath', '//a[@class="login-btn"]').click()
time.sleep(1)
browser.find_element("xpath", '//input[@placeholder="用户名"]').clear()
browser.find_element("xpath", '//input[@name="username"]').send_keys('buyer')
browser.find_element("xpath", '//input[@type="password"]').clear()
browser.find_element("xpath", '//input[@name="password"]').send_keys('123456')
browser.find_element("xpath", '//input[@title="登录"]').submit()
browser.get('http://101.43.8.10:9696/apply/fill.html')
browser.find_element('name', 'identity_front').send_keys('/Users/laobai/workspaces/selnium_test_01/demo01/01.jpg')
time.sleep(5)
browser.quit()
pywinauto
这个库只对windows系统有效
安装:
$ pip install pywinauto
示例:
from selenium import webdriver
import time
from pywinauto.keyboard import send_keys
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
browser.find_element('xpath', '//a[@class="login-btn"]').click()
time.sleep(1)
browser.find_element("xpath", '//input[@placeholder="用户名"]').clear()
browser.find_element("xpath", '//input[@name="username"]').send_keys('buyer')
browser.find_element("xpath", '//input[@type="password"]').clear()
browser.find_element("xpath", '//input[@name="password"]').send_keys('123456')
browser.find_element("xpath", '//input[@title="登录"]').submit()
browser.get('http://101.43.8.10:9696/apply/fill.html')
# 定位上传按钮
upload_btn = browser.find_element('name', 'identity_front')
# 点击上传按钮
upload_btn.click()
time.sleep(1)
# 向对话框中传递文件
send_keys(r'c:\01.jpg')
# 点击确定按钮
send_keys('{VK_RETURN}')
time.sleep(5)
browser.quit()
pyautogui
这是一个跨平台的第三方库,类似于按键精灵。谨慎安装,会一并安装近90个第三方库,建议安装到虚拟环境中。
安装
$ pip install pyautogui
示例
from selenium import webdriver
import time
import pyautogui
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
browser.find_element('xpath', '//a[@class="login-btn"]').click()
time.sleep(1)
browser.find_element("xpath", '//input[@placeholder="用户名"]').clear()
browser.find_element("xpath", '//input[@name="username"]').send_keys('buyer')
browser.find_element("xpath", '//input[@type="password"]').clear()
browser.find_element("xpath", '//input[@name="password"]').send_keys('123456')
time.sleep(1)
browser.find_element("xpath", '//input[@title="登录"]').submit()
time.sleep(2)
browser.get('http://101.43.8.10:9696/apply/fill.html')
# 定位上传按钮
upload_btn = browser.find_element('xpath', "//dd[@class='pb10']//div[@class='add-image-btn']")
# 点击上传按钮
upload_btn.click()
time.sleep(2)
# 输入要上传文件的路径
pyautogui.write("/Users/laobai/workspaces/selnium_test_01/demo01/01.jpg")
# 点击确认按钮,参数中的2,指的是按2次回车,第一次去确认路径上的文件,第二次是上传文件
pyautogui.press("enter", 2)
time.sleep(5)
browser.quit()
截图
通过save_screenshot()
和get_screenshot_as_file()
可以实现截图,这里两个方法几乎没有区别,截图的后缀推荐使用png
from selenium import webdriver
import time
browser = webdriver.Chrome()
# 实例网站:SHOPWIND商城
url = "http://101.43.8.10:9696"
# 访问指定的网址
browser.get(url)
browser.implicitly_wait(10)
browser.find_element('xpath', '//a[@class="login-btn"]').click()
time.sleep(1)
browser.find_element("xpath", '//input[@placeholder="用户名"]').clear()
browser.find_element("xpath", '//input[@name="username"]').send_keys('buyer')
browser.find_element("xpath", '//input[@type="password"]').clear()
browser.find_element("xpath", '//input[@name="password"]').send_keys('123456')
browser.find_element("xpath", '//input[@title="登录"]').submit()
browser.get('http://101.43.8.10:9696/user/profile.html')
browser.find_element("name", "im_qq").send_keys("123456")
browser.get_screenshot_as_file('04.png')
browser.save_screenshot('05.png')
time.sleep(5)
browser.quit()