开发时有时会遇到网页爬取限制的情况,那么此时可以通过 Selenium 来解决这个问题,因为 Selenium 是模拟浏览器执行网页爬取,相比 Request/API 操作更安全,服务器会完全认为是用户在用浏览器进行操作,如此可以实现网页自动化操作,由于 Selenium 是完全模拟浏览器操作,因此效率相比 API 更低。
1 Selenium 介绍
Selenium 简单来说是一个用于Web应用程序的自动化工具。
- 官方网址:Selenium
- 中文文档:Selenium with Python中文翻译文档
- 安装:pip install selenium
它允许用户使用各种编程语言(如Python, Java, C#等)来驱动自动化,实现模拟真实用户在浏览器中的操作,如点击、输入、选择、滚动等,可用于自动化测试或爬虫开发。
Selenium与各种浏览器(如Chrome,Firefox,IE等)兼容,并提供交互式界面便于开发和调试。
2 驱动下载及测试
浏览器驱动是 Selenium 构建浏览器对象的基础,它是一种可以让 Selenium 与特定的浏览器进行交互的组件,能将 Selenium 命令翻译成与特定浏览器对应的命令,以实现对浏览器的自动化操作。
因此浏览器驱动对于 Selenium 非常重要,同时针对不同的浏览器,需要安装不同的驱动。下面以下载 Chrome 驱动作为演示:
2.1 确定浏览器版本
首先点击 chrome 浏览器最右侧的“...”图标,然后点击弹出的“帮助”中的“关于Google Chrome”,查看自己的版本信息。
这里我的版本是112.0.5615,下载对应版本的 Chrome 驱动。
2.2 下载驱动
Chrome 驱动链接:https://chromedriver.storage.googleapis.com/index.html
打开该链接,选择对应的版本单机(二选一)
由于我是使用 Window 环境进行开发,因此下载 window 版本驱动,按操作系统进行下载即可。
解压后有两个文件,我们需要的是 .exe 后缀的驱动。
2.3 测试驱动
接下来就是测试驱动成功与否了,我将其放到项目的根目录下(大家可自行选择放位置,Selenium 需要的是读取该驱动的路径)
# 导入webdriver
from selenium import webdriver# 创建一个浏览器对象
driver = webdriver.Chrome(executable_path='./chromedriver.exe')
执行该文件,驱动成功启动 Chrome 浏览器 👇
3 模拟浏览器及页面相关操作
Selenium 实现网页自动化首先是从一个网站开始的,简单来说就是如何操作浏览器,有了浏览器对象,我们才可以针对请求页面进行操作。
3.1 创建及关闭浏览器对象
executable_path 指定的是浏览器驱动的路径,我这里是相对路径,绝对路径也可。
# 导入webdriver
from selenium import webdriver# 创建一个浏览器对象
driver = webdriver.Chrome(executable_path='./chromedriver.exe')#关闭浏览器
driver.close() #关闭当前页面,但浏览器驱动会残留影响内存
driver.quit() #关闭当前页面 + 浏览器驱动
3.2 设置浏览器大小
而maximize_window则是设置浏览器为全屏,set_window_size()方法用来设置浏览器大小(就是分辨率)
import time
# 导入webdriver
from selenium import webdriver
# 创建一个浏览器对象
driver = webdriver.Chrome(executable_path='./chromedriver.exe')#1.浏览器最大化
driver.maximize_window()
time.sleep(2)#2.获取当前浏览器尺寸
size = driver.get_window_size()
print(size)#3.设置当前浏览器尺寸
driver.set_window_size(400, 400)
time.sleep(2)
size = driver.get_window_size()
print(size)#关闭浏览器
driver.quit()
3.3 访问页面
通过 driver.get 方法进行页面访问,传入参数即为 url 地址。
# 导入webdriver
from selenium import webdriver
# 创建一个浏览器对象
driver = webdriver.Chrome(executable_path='./chromedriver.exe')#打开网页地址
driver.get('https://www.baidu.com/')#关闭浏览器
driver.quit()
3.4 获取页面相关属性
通过 Selenium 打开网页,可以获取网页标题、网址、页面源码等信息。
# 导入webdriver
from selenium import webdriver
# 创建一个浏览器对象
driver = webdriver.Chrome(executable_path='./chromedriver.exe')
#打开网页地址
driver.get('https://www.baidu.com/')#1.获取当前页面标题
title = driver.title
print(title)#2.获取当前页面地址
url = driver.current_url
print(url)#3.获取当前页面标源代码
source = driver.page_source
print(source)#关闭浏览器
driver.quit()
控制台输出:
3.5 页面前进、后退、截图
import time
# 导入webdriver
from selenium import webdriver
# 创建一个浏览器对象
driver = webdriver.Chrome(executable_path='./chromedriver.exe')
#1.打开 baidu
driver.get('https://www.baidu.com/')
time.sleep(2)#2.打开bilibili页面
driver.get('https://www.bilibili.com/')
time.sleep(2)#3.页面回退到 baidu
driver.back()#4.页面前进
driver.forward()#5.页面刷新
driver.refresh()#6.页面截图
#(1)方式一
data = driver.get_screenshot_as_png()
with open('bi1.jpg','wb') as f:f.write(data)
#(2)方式二
driver.get_screenshot_as_file('bi2.png')#关闭浏览器
driver.quit()
4 页面元素定位
通过 Selenium 进入对应的页面后,便可对页面中的元素(按钮、输入框等)进行操作,可分为两步:
- 定位元素信息,返回元素对象
- 调用方法完成元素的模拟操作
通过 Selenium 进行页面元素定位的前提是基本了解前端的页面布局及各种标签含义,首先我们简单地过一下。以百度官网为例,按【F12】或者右键检查进入开发者工具,红框中显示的就是页面元素代码(HTML样式),我们要做的就是从元素代码中定位获取我们需要的元素。
接下来我们来进行元素定位的学习,Selenium 对此提供了一系列的方法,主要包括以下这七种,一般来说 id 和 name 在当前页面是唯一的,xpath 使用也较为普遍。
webdriver 对象的find_element 方法用于定位单个元素,find_elements 方法用于定位元素集合(如find_elements_by_id('') )。
4.1 id 属性定位
我们选择输入框并右键点击检查元素,即可定位到该输入框的元素信息。其中 input 是该元素的标签名(tag_name);id、name、calss 等键值对均为该元素的属性,可用于元素定位。因此该输入框元素的 id 属性为 'kw'。
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#1.id属性定位,传回一个元素对象
element_input = driver.find_element_by_id('kw')
print(element_input) #关闭浏览器
driver.quit()
4.2 name 属性定位
同上,该输入框元素的 name 属性为 'wd'。
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#2.name属性定位,传回一个元素对象
element_input = driver.find_element_by_name('wd')
print(element_input)#关闭浏览器
driver.quit()
4.3 class 属性定位
该输入框元素的 class 属性为 's_ipt',但是 class 属性经常会重复,需要保证其唯一方可正确定位,该页面的 class 属性正好唯一,因此可进行 class 属性定位。
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#3.class属性定位,传回一个元素对象
element_input = driver.find_element_by_class_name('s_ipt')
print(element_input)#关闭浏览器
driver.quit()
4.4 tag 标签定位
tag 标签若要正确定位,也必须保证其唯一性,但是输入框元素的 tag name = input,不符合唯一性的要求,因此用 tag name = textarea 的元素进行测试~
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#4.tag标签定位,传回一个元素对象
element_input = driver.find_element_by_tag_name('textarea')
print(element_input)#关闭浏览器
driver.quit()
4.5 link_text 链接文本定位
① find_element_by_link_text 全文本
如上图,标签的><之间存在文本,这种元素则可以通过链接文本定位的方式定位。
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#5.link_text 全链接文本定位,传回一个元素对象
element_input = driver.find_element_by_link_text('更多')
print(element_input)#关闭浏览器
driver.quit()
② find_element_by_link_text 部分文本
如图,我们通过链接文本形式进行元素定位有时会遇到文本过长的情况,此时可以通过部分文本匹配元素!
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#5.link_text 部分链接文本定位,传回一个元素对象
element_input = driver.find_element_by_partial_link_text('更')
print(element_input)#关闭浏览器
driver.quit()
4.6 css 选择器定位
大家如果有了解前端的话,对css应该蛮熟悉,它用来描述THML和XML的元素显示样式,在css语言中有 css选择器,在Selenium中也可以使用这种选择器来定位元素。
① css结合基本属性定位
css选择器也支持基本属性(id、class、tag)定位方式。
语法:
- driver.find_element_by_css_selector("#id值") #css+id定位
- driver.find_element_by_css_selector(".class值") #css+class定位
- driver.find_element_by_css_selector("标签名") #css+标签定位
参数说明:
- #:井号代表id(类似 id = id值)
- . : 点代表class(类似 class = class值)
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#6.1css结合基本属性定位(id,class,标签)
element_input1 = driver.find_element_by_css_selector('#kw') #id
element_input2 = driver.find_element_by_css_selector('.s_ipt') #class
element_input3 = driver.find_element_by_css_selector('textarea') #标签
print(element_input1)
print(element_input2)
print(element_input3)#关闭浏览器
driver.quit()
② css结合其他属性定位
语法:
- driver.find_element_by_css_selector('[属性名=属性值]') #css+其他属性
- driver.find_element_by_css_selector('[属性名1=属性值1][属性名2=属性值2]') #css+多个其他属性
参数说明:
- [] :用方括号来指定属性
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#6.2css其他属性定位
element_input = driver.find_element_by_css_selector("[id='kw'][name='wd']")
#其他属性定位
print(element_input)#关闭浏览器
driver.quit()
③ css标签结合其他属性定位
我们也可以通过标签+属性来进行定位
语法:
- driver.find_element_by_css_selector(‘标签名#id值’) #标签+id属性定位
- driver.find_element_by_css_selector(‘标签名.class值’) #标签+class属性定位
- driver.find_element_by_css_selector('标签名[属性名=属性值]') #标签+其他属性定位
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#6.3css标签结合其他属性定位
element_input1 = driver.find_element_by_css_selector('input#kw') #id
element_input2 = driver.find_element_by_css_selector('input.s_ipt') #class
element_input3 = driver.find_element_by_css_selector("input[name='wd']") #标签
print(element_input1)
print(element_input2)
print(element_input3)#关闭浏览器
driver.quit()
④ css层级定位
在定位某个元素时,若无简洁标签属性可供参考,我们可以先定位到该元素的上级或上上级元素,随后通过层级关系获取该元素的位置。
语法:
- driver.find_element_by_css_selector('标签1>标签2')
参数说明:
- 标签1>标签2: 表示父级定位到子级
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#6.4css层级定位
element_input = driver.find_element_by_css_selector('form>span>input#kw')
print(element_input)#关闭浏览器
driver.quit()
⑤ css索引定位
如上图,“新闻”按钮同级目录下存在6个与他一样的a标签,因此像这种有多个相同标签名的元素,可以使用索引定位,通过索引来指定具体哪个 a 标签的元素。
注:与python列表索引的概念不同,此处的标签索引是从1开始;python列表的索引是从0开始。
语法:
- driver.find_element_by_css_selector('标签:nth-child(n)') #正着数第n个标签
- driver.find_element_by_css_selector('标签:nth-last-child(n)') #倒着数第n个标签
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#6.5css索引定位
element_input1 = driver.find_element_by_css_selector('div#s-top-left>a:nth-child(1)') #正着数第1个a
element_input2 = driver.find_element_by_css_selector('div#s-top-left>a:nth-last-child(7)') #倒着数第7个a
print(element_input1)
print(element_input2)#关闭浏览器
driver.quit()
⑤ css模糊匹配
有时也会遇到属性值过长的情况,此时我们可以通过模糊匹配来处理,只需要属性值的部分内容即可。
语法:
- driver.find_element_by_css_selector("[属性名~='部分属性值']") #1.属性值由多个空格隔开,匹配其中一个值的方法
- driver.find_element_by_css_selector("[属性名^='属性值开头']") #2.匹配字符串开头
- driver.find_element_by_css_selector("[属性名$='属性值结尾']") #3.匹配字符串结尾
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#6.6css模糊匹配
element_input1 = driver.find_element_by_css_selector("input[class~='s_btn']")
element_input2 = driver.find_element_by_css_selector("input[class^='bg']")
element_input3 = driver.find_element_by_css_selector("input[class$='s_btn']")
print(element_input1)
print(element_input2)
print(element_input3)#关闭浏览器
driver.quit()
4.7 xpath 表达式定位
其实 xpath 定位和 css 选择器类似,只是写法有所区别。Selenium 元素定位的基础方法(比如通过id、name、class_name等)局限性较大,首先各元素不一定都有 id 属性,其次元素的id属性也并非固定不变,因此我们真正需要熟练掌握的是通过 xpath 和 css 定位,一般掌握其中一种即可应对大部分定位工作,xpath 更为常用。
xpath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。 下面列出了最有用的路径表达式:
① xpath结合属性定位
语法:
- driver.find_element_by_xpath(".//input[@id='kw']") #单个属性定位
- driver.find_element_by_xpath(".//input[@id='kw' and @name='wd']") #多个属性定位
参数说明:
- [] :表示要根据属性找元素
- @ :后边跟属性的key,表示要通过哪个属性定位
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#7.1xpath结合属性定位
element_input1 = driver.find_element_by_xpath(".//input[@id='kw']")
element_input2 = driver.find_element_by_xpath(".//input[@id='kw' and @name='wd']")
print(element_input1)
print(element_input2)#关闭浏览器
driver.quit()
② xpath文本定位
标签文本是><里边的字符串,非键值对。
语法:
- driver.find_element_by_xpath(".//a[text()='更多']")
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#7.2xpath文本定位
element_input = driver.find_element_by_xpath(".//a[text()='更多']")
print(element_input)#关闭浏览器
driver.quit()
③ xpath层级定位
实际开发时,若需求元素没有像 id、name、class 等基本属性,那么我们就需要借助相邻的元素定位,首先我们可以定位到相邻元素,然后通过层级关系来定位最终元素。
语法:
- driver.find_element_by_xpath(".//form[@id='form']/span/input") #由上到下的层级关系
- driver.find_element_by_xpath(".//input[@class='s_ipt']/parent::span") #父子元素定位
- driver.find_element_by_xpath(".//input[@class='s_ipt']//preceding-sibling::span") #哥哥元素定位
- driver.find_element_by_xpath(".//input[@class='s_ipt']//following-sibling::i") #弟弟元素定位
参数说明:
- parent::span :向父级定位,父级的标签名为span
- preceding-sibling::span :向哥哥级定位,哥哥级的标签名为span
- following-sibling::span :向弟弟级定位,弟弟级的标签名为i
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#7.3 xpath层级定位
element_input1 =driver.find_element_by_xpath(".//form[@id='form']/span/input")#由上到下的层级关系
element_input2 =driver.find_element_by_xpath(".//input[@class='s_ipt']/parent::span")#父子元素定位
element_input3 =driver.find_element_by_xpath(".//input[@class='s_ipt']//preceding-sibling::span") #哥哥元素定位
element_input4 =driver.find_element_by_xpath(".//input[@class='s_ipt']//following-sibling::i") #弟弟元素定位
print(element_input1)
print(element_input2)
print(element_input3)
print(element_input4)#关闭浏览器
driver.quit()
④ xpath索引定位
xpath 的标签索引也是从1开始的。
语法:
- driver.find_element_by_xpath(".//div[@id='s-top-left']/a[1]") #根据索引选择标签
- driver.find_element_by_xpath(".//div[@id='s-top-left']/a[last()]") #最后一个标签
- driver.find_element_by_xpath(".//div[@id='s-top-left']/a[last()-1]") #倒数第二个标签
参数说明:
- 1 :指同名标签的第一个标签
- last() :指同名标签的最后一个标签
- last()-1 :指同名标签的倒数第二个标签
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#7.4xpath索引定位
element_input1 = driver.find_element_by_xpath(".//div[@id='s-top-left']/a[1]") #根据索引选择标签
element_input2 = driver.find_element_by_xpath(".//div[@id='s-top-left']/a[last()]") #最后一个标签
element_input3 = driver.find_element_by_xpath(".//div[@id='s-top-left']/a[last()-1]") #倒数第二个标签
print(element_input1)
print(element_input2)
print(element_input3)#关闭浏览器
driver.quit()
⑤ xpath模糊匹配
语法:
- driver.find_element_by_xpath(".//span[start-with(@class, 'soutu-hover')]") #匹配开头
- driver.find_element_by_xpath(".//span[ends-with(@class, 'hover-tip')]") #匹配结尾
- driver.find_element_by_xpath(".//span[contains(text(), '搜索')]") #包含“搜索”
ends-with方法是xpath 2.0的语法,而浏览器只支持xpth 1.0,因此可能会出现报错。
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#7.5xpath模糊定位
element_input1 = driver.find_element_by_xpath(".//span[start-with(@class,'soutu-hover')]") #匹配开头
element_input2 = driver.find_element_by_xpath(".//span[ends-with(@class,'hover-tip')]") #匹配结尾
element_input3 = driver.find_element_by_xpath(".//span[contains(text(), '搜索')]") #包含匹配
print(element_input1)
print(element_input2)
print(element_input3)#关闭浏览器
driver.quit()
5 模拟操作页面元素
定位元素后,我们将得到一个元素对象,接下来便是针对这个元素对象做模拟操作。
5.1 按钮点击操作
语法:
- element.click() #对象.方法
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#1.按钮点击操作
element = driver.find_element_by_xpath(".//div[@id='s-top-left']/a[1]")
element.click()#关闭浏览器
driver.quit()
5.2 文本框操作
语法:
- element.send_keys('python') #输入
- element.clear() #清空文本框
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#2.文本框操作
element = driver.find_element_by_id("kw")
element.send_keys('python') #输入
element.clear() #清空文本框#关闭浏览器
driver.quit()
5.3 获取元素文本
语法:
- element.text #text不是方法,不加括号
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#3.获取标签文本
element = driver.find_element_by_xpath(".//div[@id='s-top-left']/a[1]")
s = element.text #获取文本
print(s)#关闭浏览器
driver.quit()
5.4 获取元素属性
语法:
- element.get_attribute(属性名) #入参为具体属性名,如 id、class 等
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')#4.获取标签属性值
element = driver.find_element_by_xpath(".//input[@id='su']")
s1 = element.get_attribute('class') #获取 class 属性值
s2 = element.get_attribute('value') #获取 value 属性值
print(s1)
print(s2)#关闭浏览器
driver.quit()
6 切换页面的iframe、handlers
实际开发时,我们经常会遇到iframe和handler两种窗口切换。Iframe指的是在主html中嵌入子html页面,即一个页面中嵌套着一个或多个页面;Handler指的是新的页面选项卡,即浏览器上方增加了一个页面。在使用Handler切换后,我们的操作仍然在原来的窗口,如果需要在新的窗口中继续操作元素,则需要使用handle窗口切换方法。
6.1 iframe切换
图中阴影部分就是 iframe,可以理解为页面中嵌套着一个小页面,如果我们想要定位账号密码输入框,必须先切换到小页面才能定位,否则将会报错。
语法:
- driver.switch_to.frame(value) #1.直接使用id值切换,如果iframe标签中有id属性,可以用这个方法直接传id的值
- driver.switch_to.frame(driver.find_element_by_xxx(value)) #2.通过出入元素对象切换
- driver.switch_to.parent_frame() #3.跳回上层的页面
- driver.switch_to.default_content() #4.跳回最外层的页面
import time
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://mail.163.com/')
# 定位到iframe,并切换
el_iframe = driver.find_element_by_xpath(".//div[@id='loginDiv']/iframe")
driver.switch_to.frame(el_iframe)
# 先定位,输入用户名
el_username = driver.find_element_by_name("email")
el_username.send_keys('yinyu123')
time.sleep(2)
# 关闭浏览器
driver.quit()
6.2 handler切换
当我们点击百度首页的新闻按钮,会弹出一个新窗口。若要访问新闻页的元素,则需要先切换至该窗口,否则无法获取。
语法:
- driver.window_handles #1.获取当前打开的所有窗口句柄,返回类型为一个列表,window_handles是对象属性,没有括号
- driver.current_window_handle #2.获取当前窗口的句柄
- driver.switch_to.window(handle_id) #3.切换窗口,handle_id参数代表的是一个窗口句柄
import time
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')
# 按钮点击操作
element = driver.find_element_by_xpath(".//div[@id='s-top-left']/a[1]") #新闻按钮
element.click()
time.sleep(3)#1.获取当前浏览器的全部窗体
all_handles = driver.window_handles
#2.切换到最新的窗体
driver.switch_to.window(all_handles[-1])
#3.获取当前标题
print(driver.title) #输出【百度新闻——海量中文资讯平台】,说明切换成功# 关闭浏览器
driver.quit()
7 三种元素等待方式
实际开发中,定位元素时经常会碰到元素加载慢的情况(元素加载需要一个时间,比如我们平时用浏览器也会遇到网页加载慢情形)。如果元素还未加载完,此时进行点击操作则是无效的,前边有提到使用 time.sleep() 方法进行页面等待,这就是元素等待的一种。
测试流程 👇
7.1 强制等待
最简单粗暴的方式就是强制等待 sleep(xx),不论元素加载成功与否,都必须等待 xx 时间。但是该方式较为死板,严重影响执行速度。
语法:
- time.sleep(3)
import time
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')# 按钮点击操作
element = driver.find_element_by_xpath(".//div[@id='s-top-left']/a[1]")
element.click()
# 强制等待3秒
time.sleep(3)
# 页面跳转
driver.switch_to.window(driver.window_handles[1]) # 此行代码用来定位新跳出的页面
print(driver.title)
# 获取输出文本
text = driver.find_element_by_xpath(".//a[@data-control='pane-news']").text
print(text)#关闭浏览器
driver.quit()
7.2 隐式等待
隐式等待设置了一个最长等待时间,若网页在规定时间内加载完成,程序执行下一步,否则一直等待直至时间截止,才执行下一步。然而,此方法存在一个缺陷,即程序会一直等待整个页面加载完成,即使有时页面所需元素早已加载完成,但是由于某些 js 等因素导致加载缓慢。
语法:
- driver.implicitly_wait(5)
import time
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')# 按钮点击操作
element = driver.find_element_by_xpath(".//div[@id='s-top-left']/a[1]")
element.click()
# 页面跳转
time.sleep(1) #保证页面跳转成功
driver.switch_to.window(driver.window_handles[1]) # 此行代码用来定位新跳出的页面
#隐式等待
driver.implicitly_wait(5)
# 获取输出文本
text = driver.find_element_by_xpath(".//a[@data-control='pane-news']").text
print(text)#关闭浏览器
driver.quit()
7.3 显式等待
使用显式等待,结合WebDriverWait类的until()和until_not()方法,即可根据需求灵活等待。通俗来讲,程序每隔一定时间检查一次条件是否成立,如果成立则继续执行,否则持续等待直至超时,最后抛出TimeoutException异常。
① WebDriverWait 举例
语法:
- WebDriverWait(driver,10,0.5).until(EC.presence_of_element_located(locator)) #最长时间10秒钟,每0.5秒判断该元素是否加载成功
import time
# 导入webdriver
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://www.baidu.com/')
# 按钮点击操作
element = driver.find_element_by_xpath(".//div[@id='s-top-left']/a[1]")
element.click()
# 页面跳转
time.sleep(1) #保证页面跳转成功
driver.switch_to.window(driver.window_handles[1]) # 此行代码用来定位新跳出的页面# 显性等待
locator = (By.XPATH,".//a[@data-control='pane-news']")
WebDriverWait(driver, 10, 0.5).until(EC.presence_of_element_located(locator))
# 获取输出文本
text = driver.find_element_by_xpath(".//a[@data-control='pane-news']").text
print(text)#关闭浏览器
driver.quit()
② 显性等待之EC模块
显示等待经常会使用 EC 模块,WebDriverWait的until和until_not方法中我们经常要用到,它会根据网页标题、网址以及元素是否可见等条件来决定我们是否需要继续等待。
引入相关模块:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
判定方法汇总:
#1.判断当前页面的title是否完全等于(==)预期字符串,返回是布尔值
title_is#2.判断当前页面的title是否包含预期字符串,返回布尔值
title_contains#3.判断某个元素是否已被加载,并不代表该元素一定可见
presence_of_element_located#4.判断某个元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0
visibility_of_element_located#5.跟上面的方法做一样的事情,只是上面的方法要传入locator,这个方法直接传定位到的element
就好了
visibility_of#6.判断是否至少有1个元素存在于dom树中。举个例子,如果页面上有n个元素的class都是'column-md-3',那么只要有1个元素存在,这个方法就返回True
presence_of_all_elements_located#7.判断某个元素中的text是否包含了预期的字符串
text_to_be_present_in_element#8.判断某个元素中的value属性是否包含了预期的字符串
text_to_be_present_in_element_value#9.判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False
frame_to_be_available_and_switch_to_it#10.判断某个元素中是否不存在于dom树或不可见
invisibility_of_element_located#11.判断某个元素中是否可见并且是enable的,这样的话才叫clickable
element_to_be_clickable#12.等某个元素从dom树中移除,注意,这个方法也是返回True或False
staleness_of#13.判断某个元素是否被选中了,一般用在下拉列表>* element_selection_state_to_be:判断
某个元素的选中状态是否符合预期
element_to_be_selected#14.跟上面的方法作用一样,只是上面的方法传入定位到的element,而这个方法传入locator
element_located_selection_state_to_be#15.判断页面上是否存在alert弹出框
alert_is_present
8 实现163邮箱自动化登录
8.1 元素定位快速验证
比如我想定位“账号登陆”元素,编写完 xpath 信息后,可在右边代码处 ctrl+f 弹出定位输入框,将编写完的 xpath 信息填入即可,若匹配准确将自动定位, 该定位输入框也支持 css 选择器。
id、name、class 等单属性的 xpath 表达式:
//*[@id='id值']
//*[@name='name值']
//*[@iclass ='class 值']
8.2 163邮箱登录实战
最后来实战下,通过 Selenium 实现163邮箱自动化登录!
# 导入webdriver
from selenium import webdriver
#获取驱动路径
driver_path = './chromedriver.exe'
#创建一个浏览器对象
driver = webdriver.Chrome(executable_path=driver_path)
#设置全屏
driver.maximize_window()
#请求某个url
driver.get('https://mail.163.com/')
#定位到iframe,并切换
el_iframe = driver.find_element_by_xpath(".//div[@id='loginDiv']/iframe")
driver.switch_to.frame(el_iframe)
#先定位,输入用户名
el_username = driver.find_element_by_name("email")
el_username.send_keys('yinyu123')
#先定位,输入密码
el_psw = driver.find_element_by_name("password")
el_psw.send_keys('xxxx')
#先定位,点击登录
el_login = driver.find_element_by_id("dologin")
el_login.click()
#切到最外层iframe
driver.switch_to.default_content()
#隐式等待
driver.implicitly_wait(5)
#断言是否登录成功
username_text = driver.find_element_by_xpath(".//div[@class='gWel-greet']/span/span[1]").text
assert username_text == 'yinyu123','断言失败:{}'.format(username_text)
print("登录成功")
#关闭浏览器
driver.quit()