官方文档:https://selenium-python-zh.readthedocs.io/en/latest/index.html 推荐文档:http://www.python3.vip/tut/auto/selenium/01/
新语法(更新 2022-1-1)
之前的语法 broser.find_element_by_xpath(‘//span’) 弃用 ,使用新语法,broser.find_element(By.XPATH,’//span’) 替代,注意里面的 大小写,否则会报错。
from selenium.webdriver.common.by import By #要导入包
button=broser.find_element(By.XPATH,'//span')
今天本来是在搜索 Quantumult 的资料,然后油管给我推荐了Quantumult X的自动签到,想到自动签到,我有几个平台的自动签到还有点价值,手动点实在不现实很容易忘记,考虑到自己正好会点python皮毛,看看能否有脚本支持这个,于是找到了 Selenium,就有了今天这个文章(我是小白,笔记的作用主要是帮助自己学习,而非教别人,所以文中多数是自己根据自己的理解来写的,毕竟我学习是帮助自己解决问题,不在乎那些专业名词。当然我也希望可以帮助到看到这篇文章的人)。
1、环境配置
注意:如果使用的anaconda安装的Python,只需要把驱动文件,放在 C:\ProgramData\Anaconda3\Scripts 路径下即可。因为anaconda安装的时候,该路径已经添加到环境变量了。安装报错,点我
1.安装浏览器驱动,这里需要浏览器版本要和驱动版本保持一致,否则会调用失败。
86.0.4240.22和86.0.4240.111属于同一个版本; 86.0.4240.22和86.0.4242.111属于不同的版本;
友情提示: 如果你用的官方的浏览器安装包,建议关闭自动更新功能,因为浏览器一更新到大版本,驱动就失效了。
自动更新驱动脚本:
(更新到最新,好像不太好用,最新的驱动不一定适合)https://blog.csdn.net/weijiaxin2010/article/details/86651042
(根据浏览器版本进行驱动更新,实用!)
https://www.cnblogs.com/new-june/p/14249974.html
2.配置环境变量。
主要是告诉系统我们的驱动放在哪儿了,点击 此电脑—>右键 属性—>输入“高级系统设置”—>高级—>环境变量—>系统变量(选中path)—>编辑,将“C:\webdriver”目录添加到Path的值中。
一定要注意的是, 把浏览器驱动所在目录 C:\webdriver 加入环境变量 Path 的, 注意:是目录哦!不是浏览器驱动全路径 C:\webdriver*chromedriver.exe *
添加到环境变量以后,在调用驱动的时候就不需要指定驱动所在路径了。
就好比Python加入环境变量后打开命令行 直接输入Python就可以使用,而没有添加环境变量前就需要先cd进入目录才可以唤醒Python。
3.安装 Selenium ,安装遇到问题点我(可能是没有安装pip)。
conda install selenium(因为我们已经安装了anaconda,所以这样更快)
pip install selenium
4.验证
运行下面代码,能够正常打开百度页面,说明安装成功。
from selenium import webdriver
driver = webdriver.Chrome() # 创建 WebDriver 对象,指明chrome浏览器
driver.get('http://www.baidu.com')
driver.quit()
如果想用Edge浏览器怎么办呢?
很简单,首先要下载对应浏览器的版本驱动,把文件放在已经添加过环境变量的目录C:\webdriver下 ,其他的用法和Chrome一样。你可以对比下前后的区别,好像就改了一个单词。
小技巧:选中文件,按住shirft,然后鼠标右键,找到 “复制为路径” 目录就完整复制了 “C:\webdriver\chromedriver.exe”
from selenium import webdriver
driver = webdriver.Edge() # 创建 WebDriver 对象,指明Edge浏览器
driver.get('http://www.baidu.com')
# print(driver.title)
driver.quit()
注意:和Chrome驱动放在同一路径下,并且已经添加了环境变量,还是报错怎么办?我们看下报错内容,我们发现程序是无法找到名为 MicrosoftWebDriver.exe 的文件,这和我们在官网下载的驱动文件名字 msedgedriver.exe 不一致,我们需要手动把官网下载的驱动改为 MicrosoftWebDriver.exe 就可以了。
2、简单实例
使用前我们需要了解一些基本操作;首先我们导入依赖包,然后调用浏览器,这里需要注意,如果你的驱动已经加入了环境变量,就不需要指定位置,否则需要填写驱动位置来实现调用。
from selenium import webdriver # 从selenium库中调用webdriver模块
driver = webdriver.Chrome() # 实例化驱动(类+括号表示实例化)
# driver = webdriver.Chrome(executable_path='/path/to/chromedriver') # 指定驱动位置
driver.get('https://www.baidu.com') # 通过浏览器向服务器发送URL请求
driver.close() # 关闭网页
3、选择元素
常用语法:
driver.find_element_by_id() #根据id属性值获取元素列表
driver.find_element_by_class_name() #根据类名获取元素列表
driver.find_elements_by_tag_name() #根据标签名元素获取元素列表
driver.find_element_by_link_text() #根据标签的文本获取元素列表(精确定位)
driver.find_element_by_partial_link_text() #根据标签(包含)的文本获取元素列表(模糊定位)
driver.find_element_by_xpath() #返回一个包含元素的列表
driver.find_elements_by_css_selector() #通过CSS样式来获取元素列表
获取元素:
通过WebElement对象的 get_attribute 方法来获取元素的属性值
# 获取元素的文本内容
element = wd.find_element_by_id('kw')
print(element.text)
# 获取元素属性,比如要获取元素属性class的值,就可以使用 element.get_attribute('class')
element = wd.find_element_by_id('input_name')
print(element.get_attribute('class'))
# 获取输入框里面的文字
element = wd.find_element_by_id("kw")
print(element.get_attribute('value')) # 获取输入框中的文本
# 获取整个元素对应的(外部)HTML
element = wd.find_element_by_id('input_name')
print(element.get_attribute('outerHTML'))
# 获取整个元素对应的(内部)HTML
element = wd.find_element_by_id('input_name')
print(element.get_attribute('innerHTML'))
通过WebElement对象的 text 属性,可以获取元素 展示在界面上的 文本内容。但有时候,元素的文本内容没有展示在界面上,或者没有完全完全展示在界面上。可以尝试使用 element.get_attribute(‘innerText’) ,或者 element.get_attribute(‘textContent’)
css选择:tag、id、class
id、tag、class_name都是html的基础知识,很简单,F12就可以找到,然后Ctrl+F,输入我们找到的元素,查看下元素的唯一性。如果选择的元素较多,需要我们配合正则表达式一起使用。
标签名不加任何修饰、id名前用#、class名前用点
# 比如 要选择 所有的tag名为div的元素,就可以是这样
elements = wd.find_elements_by_css_selector('div')
# 根据id属性 选择元素的语法是在id号前面加上一个井号: #id值
element = wd.find_element_by_css_selector('#searchtext')
# 根据class属性 选择元素的语法是在 class 值 前面加上一个点: .class值
elements = wd.find_elements_by_css_selector('.animal')
css选择:后代选择
# 比如这是一个html,
<p class='tag name'>
<p>
这是第二个标签
</p>
</p>
# 我们选择的方式就是 p.dou.name,
# 从外面的P开始,取里面的tag name,因为程序不允许空格,所以我们用点进行连接。
p.tag.name p # 取所有内部标签(子孙辈都算)
p.tag.name>p # 取所有内部标签(只取子辈)
css选择:属性选择
<a href="https://www.douban.com/" one-link-mark="yes">我的豆瓣</a>
# 根据属性选择元素,使用中括号:选择属性href值为 https://www.douban.com/ 的元素。
element = wd.find_element_by_css_selector('[href="https://www.douban.com/"]')
# 【标签名+属性】:表示a标签下且属性href值为https://www.douban.com/的元素
a[href="https://www.douban.com/"]
# 属性值【包含 某个字符串】的元素:比如:a标签下的href属性里包含 douban 的字符串
a[href*="douban"]
# 属性值【以某个字符串 开头】 的元素:比如:a标签下的href属性里以 http 开头的字符串
a[href^="http"]
# 属性值【以某个字符串 结尾】 的元素:比如:a标签下的href属性里以 .com 结尾的字符串
a[href$=".com"]
# 属性值【多个】怎么取:比如:div标签下class的值为misc且ctyp的值为gun的属性
#注意:两个都用中括号隔开,并且不需要加引号
div[class=misc][ctype=gun]
#LinkText:带有链接对应的完整文本(完全适配)。
driver.find_element_by_link_text('我的豆瓣')
#Partial_LinkText:带有链接对应的部分文本(模糊匹配)。
driver.find_element_by_partial_link_text('豆瓣')
那么我们怎么验证 CSS Selector 的语法是否正确选择了我们要选择的元素呢?按F12 打开 开发者工具栏,点击 Elements 标签后, 同时按 Ctrl + F 键, 在搜索框里输入你选取的元素。
css选择:组选择
CSS selector的另一个强大之处在于: 选择语法 可以 联合使用
<div id='bottom'>
<div class='footer1'>
<span class='copyright'>版权</span>
<span class='date'>发布日期:2018-03-03</span>
</div>
<div class='footer2'>
<span>备案号
<a href="http://www.miitbeian.gov.cn">苏ICP备88885574号</a>
</span>
</div>
</div>
我们以上面的html为例,来看下面的几个例子:如果要获取第三行的数据,怎么办呢?
# 上下级关系
div.footer1 > span.copyright
# 表示div节点下class属性值为footer1里面,span节点下class属性值为copyright的元素
# 也可以简单写为 .footer1 > .copyright
使用逗号进行分割,也就是组选择。上面的属于上下级关系,还有一种是组合交集关系。
# 同时选择所有class 为 footer1 和 footer2 的元素(class用点)
elements = wd.find_elements_by_css_selector('.footer1 , .footer2')
# 同时选择所有tag名为div的元素 和 id为BYHY的元素(id用#)
elements = wd.find_elements_by_css_selector('div,#BYHY')
# 注意事项(下面两种写法寓意不同):
t1 > span,p 表示t1下的span元素和页面所有的p标签元素(>只对后面紧挨的元素有效);
#t1>span,#t1>p 表示t1下的span元素和p元素;
css选择:按次序选择节点
我们以下面的html为例(http://cdn1.python3.vip/files/selenium/sample1b.html),介绍下次序选择节点
<body>
<div id='t1'>
<h3> 唐诗 </h3>
<span>李白</span>
<p>静夜思</p>
<span>杜甫</span>
<p>春夜</p>
</div>
<div id='t2'>
<h3> 宋词 </h3>
<span>苏轼</span>
<p>赤壁怀古</p>
<p>明月几时有</p>
<p>江城子·乙卯正月二十日夜记梦</p>
<p>蝶恋花·春景</p>
<span>辛弃疾</span>
<p>京口北固亭怀古</p>
<p>青玉案·元夕</p>
<p>西江月</p>
</div>
</body>
# 顺序选择 ----------
# 父元素的第n个子节点,我们选择第二个节点,并且类型是span,也就是李白和苏轼
span:nth-child(2) # 类型:nth-child(n)
# 父元素的倒数第n个子节点,我们选择倒数第一个节点,类型是p,也就是春夜和西江月
p:nth-last-child(1)
# 类型选择 ----------
# 父元素的第几个某类型的子节点,我们选择第1个span类型 的子元素
span:nth-of-type(1)
# 父元素的倒数第几个某类型的子节点,我们选择倒数第1个p类型的子元素
p:nth-last-of-type(1)
#奇偶选择 -----------
p:nth-child(even) # 偶数
p:nth-child(odd) # 奇数
#相邻(兄弟)节点 -----------
h3 + span #h3后面紧跟着的兄弟节点 span
h3 ~ span #h3后面所有的兄弟节点 span
By ( 定位方式,定位内容值 )
实际上,对自动化做 Page Object 设计 的时候,一般都会用 By 的方式来封装代码,更易于我们维护代码。
# 1、导入依赖类
from selenium.webdriver.common.by import By
# 2、使用
driver.find_element(By.ID, "element_id")
driver.find_element(By.NAME, "element_name")
driver.find_element(By.CLASS_NAME, "element_class_name")
driver.find_element(By.TAG_NAME, "element_tag_name")
driver.find_element(By.LINK_TEXT, "element_link_text")
driver.find_element(By.PARTIAL_LINK_TEXT, "element_partial_link_text")
driver.find_element(By.XPATH, "//*[@class='element_xpath']")
driver.find_element(By.CSS_SELECTOR, "element_css_selector")
上面查找元素的方法都是针对单个元素标签,如果要查找匹配多个元素,只需要将 element 改成 elements 即可。
# 单个元素
driver.find_element(By.ID, "element_id")
# 多个元素
driver.find_elements(By.ID, "element_id")
选择框的处理:
并且按F12,观察HTML的内容。常见的选择框包括: radio框、checkbox框、select下拉框
<div id="s_radio">
<input type="radio" name="teacher" value="小江老师">小江老师<br>
<input type="radio" name="teacher" value="小雷老师">小雷老师<br>
<input type="radio" name="teacher" value="小凯老师" checked="checked">小凯老师
</div>
# radio框(单选框,直接点选) -----------
wd.find_element_by_css_selector(
'#s_radio input[value="小雷老师"]').click() #css选择(id+标签+属性)
# checkbox框(复选框,先取消已选中的,再点选) -----------
# 先把已经选中的选项全部点击一下
elements = wd.find_elements_by_css_selector('#s_checkbox input[checked="checked"]')
for element in elements:
element.click()
# 再点击小雷老师
wd.find_element_by_css_selector("#s_checkbox input[value='小雷老师']").click()
对于Select 选择框, Selenium 专门提供了一个 Select类 进行操作。
select_by_value(‘小雷老师’) 根据value的属性值,选择元素; select_by_index(1) 根据选项的次序 (从0开始),选择元素;
select_by_visible_text(‘小雷老师’) 根据选项的可见文本 ,选择元素;
deselect_by_value 根据value的属性值, 去除 选中元素; deselect_by_index 根据选项的次序,去除 选中元素; deselect_by_visible_text 根据选项的可见文本,去除 选中元素 deselect_all 去除 选中所有元素
#select单选框 -----------
from selenium.webdriver.support.ui import Select # 导入Select类
select = Select(wd.find_element_by_id("ss_single")) # 创建Select对象(找到位置)
select.select_by_visible_text("小雷老师") # 通过 Select 对象选中小雷老师(在对应的位置下找到可见文本小雷老师)
#select多选框 -----------
from selenium.webdriver.support.ui import Select # 导入Select类
select = Select(wd.find_element_by_id("ss_multi")) # 创建Select对象(找到位置)
# 清除所有 已经选中 的选项
select.deselect_all()
# 选择小雷老师 和 小凯老师
select.select_by_visible_text("小雷老师")
select.select_by_visible_text("小凯老师")
4、xpath选择:
1. 路径选择
绝对路径选择(具体位置):从根节点开始的,到某个节点,每层都依次写下来,每层之间用 / 分隔的表达式,就是某元素的 绝对路径
# 选择html下面的body下面的div元素
elements = driver.find_elements_by_xpath("/html/body/div")
# 对应的css选择器写法就是
elements = driver.find_elements_by_css_selector("html>body>div")
相对路径选择(所有位置):有的时候,我们需要选择网页中某个元素, 不管它在什么位置 。xpath需要前面加 // , 表示从当前节点往下寻找所有的后代元素,不管它在什么位置。(// 表示所有位置)
# 选择所有的 div 元素里面的 所有的 p 元素
elements = driver.find_elements_by_xpath("//div//p")
# 对应的css选择器写法就是
elements = driver.find_elements_by_css_selector("div p")
通配符(所有子节点):如果要选择所有div节点的所有直接子节点,可以使用表达式 //div/(// 表示所有子节点)
elements = driver.find_elements_by_xpath("//div/*")
for element in elements:
print(element.get_attribute('outerHTML'))
# 对应的css选择器写法就是
elements = driver.find_elements_by_css_selector("div > *")
2. 属性选择
根据属性来选择元素 是通过 这种格式来的 //元素标签[@属性名=’属性值’]
注意: 属性名注意前面有个@(在css选择器里id用 ‘#’,class用 ‘.’ ,在xpath里统一用@) 属性值一定要用引号, 可以是单引号,也可以是双引号
<p id="beijing" class='capital huge-city'>
北京
</p>
选择id为 beijing 的元素,//[@id=’beijing’] // 表示不考虑开头是什么
选择所有P元素中 class为 ‘capital huge-city’ 的元素,可以这样 //p[@class=’capital huge-city’](属性值有空格在css里面可以看做是两个属性值(.capital 或 .huge-city都可以定位),但是在xpath里要想选择,必须是所有属性值,不可拆分。)
同样的道理,//*表示开头是任意元素(相当于不考虑选取元素的上级是什么),//p表示开始是p。
要选择 具有multiple属性的所有页面元素(不考虑属性值) ,可以用 //[@multiple] ,也可以搭配我们在 css属性选择 里学到的 =包含,^=开头为,$=结尾为等语法结合使用。
xpath里面也有对应的语法:
要选择 style属性值 包含 color 字符串的 页面元素 ,可以这样 //[contains(@style,’color’)]
要选择 style属性值 以 color 字符串 开头 的 页面元素 ,可以这样 //[starts-with(@style,’color’)]
要选择 style属性值 以 某个 字符串 结尾 的 页面元素 ,是 //*[ends-with(@style,’color’)],
(ends-with这个是2.0的语法,目前浏览器还不支持。)
3. 按次序选择
前面我们学过css表达式可以根据元素在父节点中的次序选择, 非常实用。xpath也可以根据次序选择元素。 语法比css更简洁,直接在方括号中使用数字表示次序。
注意,选择的是 第2个p类型的子元素 (相当于css选择里 p:nth-of-type(2) ) 。
# 某类型 第几个子元素 -----------
//p[2] 不限制父元素,第2个p类型的子元素
//div/p[2] 选择父元素为div中的第2个p类型的子元素
# 不限制类型 第几个子元素 -----------
//div/*[2] 选择父元素为div中第2个子元素,不管是什么类型,采用通配符(第3行的标题)
# 某类型 倒数第几个 子元素 -----------
//p[last()] P类型的倒数第一个子元素(注意这是倒数1)
//p[last()-1] 选取p类型倒数第2个子元素
//div/p[last()-2] 选择父元素为div中p类型倒数第3个子元素
# 范围选择 ----------
//option[position()<3] 选取option类型的前2个子元素(一般用于选择网站的前面几个数据)
//*[@class='multi_choice']/*[position()<=3] 选择class属性为multi_choice的前3个子元素
//*[@class='multi_choice']/*[position()>=last()-2] 选择class属性为multi_choice的后3个子元素
4.组选择、父节点、兄弟节点
多个表达式选择的结果都是要选择的元素;
css 组选择,表达式之间用 逗号 隔开;xpath也有组选择, 是用 竖线 隔开多个表达式。
# 要选所有的option元素 和 所有的 h4 元素
//option | //h4 # xpath写法
option,h4 # css写法
# 要选所有的 class 为 single_choice 和 class 为 multi_choice 的元素
//*[@class='single_choice'] | //*[@class='multi_choice'] # xpath写法
.single_choice,.multi_choice # css写法
xpath可以选择父节点, 这是css做不到的。某个元素的父节点用 /.. 表示
当某个元素没有特征可以直接选择,但是它有子节点有特征, 就可以采用这种方法,先选择子节点,再指定父节点。
# 要选择 id 为 china 的节点的父节点,可以这样写
//*[@id='china']/..
# 还可以继续找上层父节点,比如
//*[@id='china']/../..
css选择器,要选择某个节点的后续兄弟节点,用 波浪线;xpath的语法 following-sibling::
# 要选择 class 为 single_choice 的元素的(后面)所有兄弟节点
//*[@class='single_choice']/following-sibling::* # xpath写法
.single_choice ~ * # css写法
# 要选择 class 为 single_choice 的元素的(后面)所有div节点
//*[@class='single_choice']/following-sibling::div # xpath写法
.single_choice ~ div # css写法
# 要选择 class 为 single_choice 的元素的(前面)所有兄弟节点(css没有这种方法)
//*[@class='single_choice']/preceding-sibling::* # xpath写法
万能法宝
几乎所有定位用它一个就够了。找到元素-右键-检查,选择 Elements,找到对应的元素,右键 copy-copy xpath即可,也可以使用插件 ChroPath 来找 。
注意element和elements的区别:
driver.find_element_by_xpath()
返回符合条件的第一个元素,如果没有符合条件的元素,抛出异常 NoSuchElementException;
driver.find_elements_by_xpath()
返回符合条件的所有元素,如果没有符合条件的,返回空列表。
5、操控元素
# 内部元素操作
driver.find_element_by_id("element_btn").click() # 点击
driver.find_element_by_id("element_edit").send_keys("Python") # 输入文本(字符串)
driver.find_element_by_id("element_edit").clear() # 清空输入框
# 浏览器导航
driver.get("https://selenium.dev") # 打开网站
driver.current_url #获取当前url
driver.forward() # 前进
driver.back() # 后腿
driver.refresh() # 刷新当前页面
driver.title() # 从浏览器中读取当前页面的标题
# 窗口和标签页
driver.window_handles # 获取当前所有窗口,返回值是一个窗口句柄列表
driver.current_window_handle # 获得当前窗口的窗口句柄
driver.switch_to_window(windows[0]) # 根据窗口索引进行切换
driver.switch_to.window(original_window) # 切回到之前的标签页或窗口
driver.switch_to.new_window('tab') # 打开新标签页并切换到新标签页(注意: 此功能适用于Selenium 4以及更高版本.)
driver.switch_to.new_window('window') # 打开一个新窗口并切换到新窗口(注意: 此功能适用于Selenium 4以及更高版本.)
driver.close() # 关闭当前窗口页面
driver.quit() # 关闭所有窗口页面
# 窗口管理
driver.set_window_size(1024, 768) # 设置窗口大小
driver.set_window_position(0, 0) # 设置窗口位置,将窗口移动到设定的位置 0,0是左上角
driver.maximize_window() # 最大化窗口,窗口将填满屏幕
driver.minimize_window() # 最小化窗口,将窗口隐藏在系统托盘中(注意: 此功能适用于Selenium 4以及更高版本.)
driver.fullscreen_window() # 全屏窗口,类似于浏览器中按F11
driver.save_screenshot('./image.png') # 屏幕截图,返回以Base64格式编码的屏幕截图.
# cookie
cookies = driver.get_cookies() # 获取cookies信息
driver.add_cookie() # 添加cookie
driver.delete_cookie() # 删除cookie
driver.delete_all_cookies()
页面的前进后退 & 标签切换
相关教程:https://www.bilibili.com/video/BV1N64y187Qb/
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get('http://www.baidu.com/')
driver.find_element_by_class_name('s_ipt').send_keys('邓紫棋', Keys.ENTER)
time.sleep(2)
driver.back() # 回退
time.sleep(2)
driver.forward() # 前进
time.sleep(2)
driver.quit() # 退出
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get('http://www.baidu.com/')
# 输入文本
driver.find_element_by_class_name('s_ipt').send_keys('邓紫棋', Keys.ENTER)
time.sleep(10)
# 点击第一个
driver.find_element_by_xpath('//*[@id="2"]/div/div/h3/a').click()
time.sleep(3)
# 窗口之间的切换,第一个打开是0,第二个打开是1
driver.switch_to.window(driver.window_handles[1])
# 找到文本
detail = driver.find_element_by_xpath(
'/html/body/div[3]/div[2]/div/div[1]/div[2]/div').text
print(detail)
# 关掉后切换到第一个
driver.close()
driver.switch_to.window(driver.window_handles[0])
切换到新窗口
[
](https://www.bilibili.com/video/BV1N64y187Qb/)
WebDriver对象有window_handles 属性,这是一个列表对象, 里面包括了当前浏览器里面所有的窗口句柄(可以理解为窗口ID)。
from selenium import webdriver # 导入依赖
import time
driver = webdriver.Chrome() # 实例化
driver.implicitly_wait(10) # 隐式等待
driver.get('https://weixin.sogou.com/')
# 点击打开新窗口的链接
link = driver.find_element_by_xpath(
'//*[@id="topwords"]/li[1]/a').click() # 点击热词第一
print(driver.title) # 打印当前窗口的标题栏文本
# 遍历句柄 ---------------------------
for handle in driver.window_handles:
time.sleep(2) # 为了看不到变化,我们加个时间
# 先切换到该窗口
driver.switch_to.window(handle)
# 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
if '搜狗微信搜索' in driver.title:
# 如果是,那么这时候WebDriver对象就是对应的该窗口,并跳出循环
break
同样的,如果我们在新窗口 操作结束后, 还要回到原来的窗口,该怎么办?我们可以仍然使用上面的方法,依次切入窗口,然后根据 标题栏 之类的属性值判断。
不过,还有更简单的方法。就是先保存我们当前窗口,之后再回来。
from selenium import webdriver # 导入依赖
import time
wd = webdriver.Chrome() # 实例化驱动
wd.implicitly_wait(10) # 设置等待
wd.get('https://weixin.sogou.com/')
# mainWindow变量保存当前窗口的句柄
mainWindow = wd.current_window_handle
link = wd.find_element_by_xpath(
'//*[@id="topwords"]/li[1]/a').click() # 点击热词第一
time.sleep(2)
# 通过前面保存的老窗口的句柄,自己切换到老窗口
wd.switch_to.window(mainWindow)
print(wd.title) # 打印当前窗口的标题栏文本
6、更多动作 ActionChains()
之前我们对web元素做的操作主要是:选择元素,然后 点击元素 或者 输入 字符串。还有一些不常用的但是需要知道的动作,比如 鼠标右键点击、双击、移动鼠标到某个元素、鼠标拖拽等。
这些操作,可以通过 Selenium 提供的 ActionChains 类来实现。
两种写法:
# 链式写法:
menu = driver.find_element_by_css_selector(".nav") # 定义位置
hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1") # 定义位置
ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform()
# 分布式写法:
menu = driver.find_element_by_css_selector(".nav") # 定义位置
hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1") # 定义位置
actions = ActionChains(driver) #开头实例化
actions.move_to_element(menu) #动作1
actions.click(hidden_submenu) #动作2
actions.perform() #结尾执行
ActionChains方法列表(说明文档在安装目录下的 action_chains.py) | |
---|---|
click(on_element=None) | 单击鼠标左键 |
click_and_hold(on_element=None) | 点击鼠标左键,不松开 |
context_click(on_element=None) | 点击鼠标右键 |
double_click(on_element=None) | 双击鼠标左键 |
drag_and_drop(source, target) | 拖拽到某个元素然后松开 |
drag_and_drop_by_offset(source, xoffset, yoffset) | 拖拽到某个坐标然后松开 |
key_down(value, element=None) | 按下某个键 |
key_up(value, element=None) | 松开某个键 |
move_by_offset(xoffset, yoffset) | 鼠标从当前位置移动到某个坐标 |
move_to_element(to_element) | 鼠标移动到某个元素 |
move_to_element_with_offset(to_element, xoffset, yoffset) | 移动到距(左上角坐标)多少距离的位置 |
release(on_element=None) | 在某个元素位置松开鼠标左键 |
perform() | 执行链中的所有动作 |
send_keys(*keys_to_send) | 发送某个键到当前焦点的元素 |
案例说明:
# 链式写法
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep
driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.maximize_window()
driver.get('http://sahitest.com/demo/clicks.htm')
click_btn = driver.find_element_by_xpath('//input[@value="click me"]') # 单击按钮
doubleclick_btn = driver.find_element_by_xpath(
'//input[@value="dbl click me"]') # 双击按钮
rightclick_btn = driver.find_element_by_xpath(
'//input[@value="right click me"]') # 右键单击按钮
ActionChains(driver).click(click_btn).double_click(
doubleclick_btn).context_click(rightclick_btn).perform() # 链式用法
print(driver.find_element_by_name('t2').get_attribute('value'))
sleep(2)
driver.quit()
# 分布式写法
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep
driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.maximize_window()
driver.get('http://www.baidu.com')
more = driver.find_element_by_name('tj_briicon') # 更多
music = driver.find_element_by_name('tj_mp3') # 音乐
new1 = driver.find_element_by_class_name('title-content-title') # 第一个新闻
input = driver.find_element_by_id('kw') # 搜索框
action = ActionChains(driver) # 实例化(链式写法不需要)
# action.drag_and_drop(new1, input).perform() # 把新闻第一移动到输入框
# action.click_and_hold(new1).release(input).perform() # 效果同上,也能起到移动的作用
action.move_to_element(more).perform() # 移动到更多
action.move_to_element(music).click().perform() # 移动到音乐 click要放在perform之前
# 链式写法
# ActionChains(driver).move_to_element(more).click(music).perform()
sleep(2)
driver.quit()
冻结窗口:
有时候我们会遇到有些元素无法F12,比如上面百度的首页,鼠标移开后菜单就消失。这时候我们就需要把窗口冻结才可以让鼠标去下面的审查元素里找到元素属性。
当然也可以有个方法,就是选中元素后右键-检查,也可以定位到元素属性。
不过我们今天使用的是debug
在 开发者工具栏 console 里面执行如下js代码
setTimeout(function(){debugger}, 5000)
这句代码什么意思呢?表示在 5000毫秒后,执行 debugger 命令。执行该命令会浏览器会进入debug状态。 debug状态有个特性, 界面被冻住, 不管我们怎么点击界面都不会触发事件。
使用步骤: debugger教程.mp4
- 在 console 里输入上面代码,回车执行后立即鼠标放在更多上面;
- 然后等5秒,界面就会执行 debugger 命令而被冻住;
- 这时候我们就可以点击查看箭头,查看其属性了;
弹窗处理:
弹出的对话框有三种类型,分别是 Alert(警告信息)、confirm(确认信息)和prompt(提示输入)
Alert 弹出框,目的就是显示通知信息,只需用户看完信息后,点击 OK(确定) 就可以了。 Confirm弹出框,主要是让用户确认是否要进行某个操作。有 确定 和 取消 操作。 Prompt 弹出框 是需要用户输入一些信息,提交上去。 操作包含 accept()、dismiss()、send_keys()
# --- accept 确认 ---
driver.switch_to.alert.accept() # 点击 OK 按钮
# --- dismiss 取消 ---
driver.switch_to.alert.dismiss() # 点击 取消 按钮
# --- send_keys 输入后确认 ---
print(driver.switch_to.alert.text) # 获取警告框的提示信息
driver.switch_to.alert.send_keys('哈哈') # 输入信息
# --- send_keys 输入后确认(换种写法) ---
alert = driver.switch_to.alert # 切换到对话框,并把该值赋予新的变量
print(alert.text) # 获取警告框的提示信息
alert.send_keys('Web自动化') # 输入信息 操作包含 accept()、dismiss()、send_keys()
注意 : 有些弹窗并非浏览器的alert 窗口,而是html元素,这种对话框,只需要通过之前介绍的选择器选中并进行相应的元素进行操作就可以了。
7、内嵌页面,切换到frame
有时候会遇到一些无法获得位置的页面,什么意思呢?比如说iframe,就是网页内嵌套一个页面。如果我们按照正常的获取元素是无效的,这就需要我们告诉计算机它是嵌套的页面,然后再取值。打个简单的比喻
<html>
<body class=''abc>
<iframe class="eee"></iframe>
</body>
</html>
比如上面就是一个简单的网页框架,里面包含body和iframe标签,我们直接使用 driver.find_element_by_class_name(‘abc’)是可以定位到abc的,但是直接driver.find_element_by_class_name(‘eee’)是不能定位到eee的,因为系统不知道你的取值是在iframe标签里,所以我们需要先告诉系统我们要取iframe里的元素,然后才可以取定位取值。相反,如果需要取iframe标签外的元素,就需要退出iframe,也就是使用 driver.switch_to.default_content() ,切换回原来的页面。
比如豆瓣的首页登录框就是这样的 https://www.douban.com/
from selenium import webdriver
import time
driver = webdriver.Chrome() # 实例化
driver.get('https://www.douban.com/') # 打开网址
iframe_Switch = driver.find_element_by_tag_name('iframe') # 用tag标签找到定位这个iframe元素
driver.switch_to.frame(iframe_Switch) # 使用iframe 的对象切换到iframe
# driver.switch_to.frame("frame_id") # 使用iframe 的id切换到iframe
driver.find_element_by_class_name('account-tab-account').click()
time.sleep(1)
driver.find_element_by_id('username').send_keys('zhanghao') # 输入账号
driver.find_element_by_id('password').send_keys('mima') # 输入密码
driver.find_element_by_link_text('登录豆瓣').click()
time.sleep(5)
driver.switch_to.default_content() # # 切换到外层页面,退出iframe
如果查找完元素之后,我们还需要查找页面上非内嵌的网页的元素,就需要退出iframe了,否则程序还是在
上面我们使用的是name来获取iframe框架,也可以试用WebElement、name或id、索引值等方法,更多内容查看:https://www.selenium.dev/documentation/zh-cn/webdriver/browser_manipulation/#frames-and-iframes
拓展 如果用的是 import time ,那么调用时候就是用 time.sleep() 如果用的是 from time import sleep,那么调用时候就只需要 sleep() 即可
8、定位不到元素怎么办?
该方案作者:https://blog.csdn.net/MrLevo520/article/details/51954203 错误提示:(NoSuchElementException: Unable to locate element)
出现的原因:元素没加载完
元素加载没完成,同样的路径定位,每次测试结果确是不一样的,有时候抛出错误,有时候正常!和你的定位方法半毛钱关系没有,而很大程度上取决于你的电脑和网速!
解决方案1:implicitly_wait() 找到元素在运行
Selenium 的 Webdriver 对象 有个方法叫 implicitly_wait, 该方法接受一个参数, 用来指定 最大等待时长,也叫隐式等待。
当发现元素没有找到的时候, 并不立即返回找不到元素的错误。而是周期性(每隔半秒钟)重新寻找该元素,直到该元素找到,或者超出指定最大等待时长,这时才抛出异常(如果是 find_elements 之类的方法, 则是返回空列表)。
implicitly_wait()是找不到的时候等待,sleep()是强制等待;比如我们在选择下拉框的地址时候就需要用sleep,而不能用implicitly_wait,因为implicitly_wait是找不到时候的等待,我们需要的是找到 选择河南省后,等待一秒再选郑州市等等操作。
只需要在开头设置 wd.implicitly_wait(10),那么后续所有的 find_element 或者 find_elements 之类的方法调用都会采用上面的策略:
from selenium import webdriver
wd = webdriver.Chrome()
wd.implicitly_wait(10) # 设置最大等待时长为 10秒
wd.get('https://www.baidu.com')
element = wd.find_element_by_id('kw')
element.send_keys('搜什么\n')
element = wd.find_element_by_id('1')
print(element.text)
解决方案2:WebDriverWait() 找到元素在运行
其实两种方式是一样的,10秒内每0.5秒扫描一次,超过10秒停止,不同的是这个需要对元素单独设置,会比较麻烦一些。
# 解决方案A:添加两行代码
wait = ui.WebDriverWait(driver_item, 10)
wait.until(lambda driver_item: driver.find_element_by_方法("定位路径"))
WebDriverWait(driver,10) 的意思是;10秒内每隔500毫秒(默认是0.5秒)扫描1次页面变化,当出现指定的元素后进入下一行;如果10秒内没有获取到元素则停止,所以我们一般设置稍微大一点。这样就不需要 time.sleep() 了,可以加快运行速度(动态方法);driver_item是前面操作webdriver.Chrome()的句柄,根据自定义自行设置,一般用drive。
from selenium import webdriver
import selenium.webdriver.support.ui as ui # 导入包
driver_item = webdriver.Chrome()
# 查找的时间
wait = ui.WebDriverWait(driver_item, 10)
driver_item.get("https://movie.douban.com/")
# 查找的元素,找到后继续下一行
wait.until(lambda driver_item: driver_item.find_element_by_xpath(
'//*[@id="db-nav-movie"]/div[2]/div/ul/li[3]'))
driver_item.find_element_by_xpath(
'//*[@id="db-nav-movie"]/div[2]/div/ul/li[3]').click()
还有一种组合语句,这一种更简洁一点。
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait # 导入包
driver_item = webdriver.Chrome()
driver_item.get("https://movie.douban.com/")
# 10秒内一直每0.5秒查找一次元素,查到后继续下一行
WebDriverWait(driver_item, 10).until(lambda driver_item: driver_item.find_element_by_xpath(
'//*[@id="db-nav-movie"]/div[2]/div/ul/li[3]'))
driver_item.find_element_by_xpath(
'//*[@id="db-nav-movie"]/div[2]/div/ul/li[3]').click()
常用配置汇总:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
url = 'http://www.xxxxx.com/login.html'
chrome_options = webdriver.ChromeOptions()
# 设置为开发者模式访问,防止被网站识别出来是selenium
chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])
# 设置浏览器不加载图片,从而加快页面加载速度
prefs = {"profile.managed_default_content_settings.images": 2}
chrome_options.add_experimental_option("prefs", prefs)
# 添加代理
chrome_options.add_argument('--proxy-server=http://101.37.79.125:3128') #添加代理
# 达到目标后停止加载
capa = DesiredCapabilities.CHROME
capa["pageLoadStrategy"] = "none" #懒加载模式,不等待页面加载完毕
# 设置日志等级
chrome_options.add_argument('log-level=3') # INFO = 0 WARNING = 1 LOG_ERROR = 2 LOG_FATAL = 3 default is 0
# chrome-headerless模式
chrome_options.add_argument('--headless')
# 手机模式打开浏览器
mobile_emulation = {'deviceName': 'iPhone 6'}
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
# 启动chrome浏览器
driver = webdriver.Chrome(chrome_options=chrome_options,desired_capabilities=capa) #desired_capabilities参数就是上面设置的,如果没有设置就不加
driver.get(url)
cookies = driver.get_cookies()