官网:Selenium

文档:

Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动操作,不同是Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器)。

Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。

注意:本笔记默认读者会CSS,HTML等基础的Web语言

安装

pip install selenium

快速入门

引用selenium教程 - 简书 (jianshu.com)

# IPython2 测试代码

# 导入 webdriver
from selenium import webdriver

# 要想调用键盘按键操作需要引入keys包
from selenium.webdriver.common.keys import Keys

# 调用环境变量指定的PhantomJS浏览器创建浏览器对象
driver = webdriver.PhantomJS()

# 如果没有在环境变量指定PhantomJS位置
# driver = webdriver.PhantomJS(executable_path="./phantomjs"))

# get方法会一直等到页面被完全加载,然后才会继续程序,通常测试会在这里选择 time.sleep(2)
driver.get("http://www.baidu.com/")

# 获取页面名为 wrapper的id标签的文本内容
data = driver.find_element_by_id("wrapper").text

# 打印数据内容
print data

# 打印页面标题 "百度一下,你就知道"
print driver.title

# 生成当前页面快照并保存
driver.save_screenshot("baidu.png")

# id="kw"是百度搜索输入框,输入字符串"长城"
driver.find_element_by_id("kw").send_keys(u"马云")

# id="su"是百度搜索按钮,click() 是模拟点击
driver.find_element_by_id("su").click()

# 获取新的页面快照
driver.save_screenshot("马云.png")

# 打印网页渲染后的源代码
print driver.page_source

# 获取当前页面Cookie
print driver.get_cookies()

# ctrl+a 全选输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')

# ctrl+x 剪切输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')

# 输入框重新输入内容
driver.find_element_by_id("kw").send_keys(u"王健林")

# 模拟Enter回车键
driver.find_element_by_id("su").send_keys(Keys.RETURN)

# 清除输入框内容
driver.find_element_by_id("kw").clear()

# 生成新的页面快照
driver.save_screenshot("王健林.png")

# 获取当前url
print driver.current_url

# 关闭当前页面,如果只有一个页面,会关闭浏览器
# driver.close()

# 关闭浏览器
driver.quit()

引用Selenium

使用from selenium import webdriverfrom selenium.webdriver.common.keys import Keys引用Selenium和Selenium keys(用于使用特定的按键,比如说F2等等)包

API

初始化Selenium

首先安装浏览器驱动,笔者用的是Edge和Chrome(这个用的最多),这两个驱动分别在Microsoft Edge Driver - Microsoft Edge Developerchromedriver存储目录(由于114以上版本不更新,需要进入最新的chromedriver地址https://chromedriver.com/download下载driver)

下载,下载方法如下:

  1. Edge

进入网页,找到Stable Channel,根据自己的系统位数选择下载即可。

  1. Chrome

首先查看自己Chrome的版本号,在Chrome输入chrome://version即可查看Chrome的版本号

进入网页,找到相应的版本号后,点击下载即可

保存好浏览器驱动后,使用如下代码,让Selenium找到相应的驱动后即可开启浏览器

driver = webdriver.Chrome("xxx/browserDriver/chromedriver.exe")# Chrome 浏览器驱动存放路径
driver = webdriver.Edge("xxx/browserDriver/msedgedriver.exe")# Edge 浏览器驱动存放路径

也可以将浏览器驱动存放在python的根目录下,不用输入存放路径

driver = webdriver.Chrome()
driver = webdriver.Edge()

这样,Selenium初始化完毕。

可以使用headless无UI进行selenium,通常运用在爬虫中,特别的,headless模式通常运用在Chrome浏览器中

# Chrome后台静默运行
__options = webdriver.ChromeOptions()
__options.add_argument('--no-sandbox') # 解决DevToolsActivePort文件不存在的报错
__options.add_argument('--start-maximized') # 最大化运行(全屏窗口),不设置,取元素会报错
__options.add_argument('--disable-infobars') # 禁用浏览器正在被自动化程序控制的提示
__options.add_argument('window-size=1920x1080') # 设置浏览器分辨率
__options.add_argument('--disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug
__options.add_argument('--hide-scrollbars')  # 隐藏滚动条,应对一些特殊页面
__options.add_argument('blink-settings=imagesEnabled=false') # 不加载图片,提升运行速度
__options.add_argument('--headless') # 浏览器不提供可视化界面。Linux下如果系统不支持可视化不加这条会启动失败
__options.add_argument("--ignore-certificate-errors") # 忽视掉证书认证的不安全连接的错误
# 传入user-agent,欺骗网站,使得它认为是在实际的浏览器上运行,这样的话运行的网络速度是和UI运行的时候是一样的
__options.add_argument('user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')
__options.add_argument("--ignore-ssl-errors")
__driver = webdriver.Chrome(executable_path = "./browserDriver/chromedriver.exe",options=__options)# Chrome 浏览器驱动存放路径

user-agent可以通过在Chrome浏览器中输入chrome://version的用户代理查找到,这里笔者使用的是最新的chrome浏览器(作为自动化工具)

打开网址

driver.get("https://www.baidu.com/")

定位UI元素

引用selenium教程 - 简书 (jianshu.com),有少量修改

通过如下选择器可以精准找到网页的HTML元素和标签。

find_elements_by_id
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector

示例:

driver.find_element_by_id("txtMobileTexter").send_keys("12345")# 通过id获取元素,发送字符12345
driver.find_element_by_xpath("//*[@id='mobileSelSend").click()# 通过xpath获取元素,并点击
driver.find_element_by_link_text("发送").text# 通过元素中的字符获取元素获取文本
# 获取指定元素,并判断是否存在
try:
    driver.find_element_by_xpath("/html/body/div[1]/div[1]/div[2]/div[2]/span")
    print("成功")
except:
    print("失败")

其中,find_element_by_xxxxfind_elements_by_xxxx的区别是,find_element_by_xxxx是适用于某一个页面中的某个元素,而find_elements_by_xxxx中可能包含多个元素,返回的是list,例如:

driver.find_element_by_id("txtMobileTexter").click() # 点击id为txtMobileTexter的这个元素
driver.find_elements_by_id("txtMobileTexter")[0].click() # 点击id为txtMobileTexter的第一个元素

find_element_by_xxxx或者find_elements_by_xxxx新版本的selenium已不适用,取而代之的是find_element(by=By.xxx, value=value)find_elements(by=By.xxx, value=value),其作用相当于find_element_by_xxxx或者find_elements_by_xxxx。需要导入By这个包,具体为:from selenium.webdriver.common.by import By

xpath说明:

符号

说明

/

从根节点选取,使用绝对路径,路径必须完全匹配

//

从整个文档中选取,使用相对路径

.

从当前节点开始选取

从当前节点父节点开始选取

@

选取属性

text()

获取文本

案例

引用(7条消息) Scrapy爬虫:XPath语法灵动的艺术的博客-CSDN博客scrapy xpath语法

路径表达式

结果

body

选取 body 元素的所有子节点。

/head

选取根元素下head。假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!

div/a

选取属于 div 的子元素的所有 a 元素。

//a

选取所有 a 子元素,而不管它们在文档中的位置。

div//a

选择属于 div 元素的后代的所有 a 元素,而不管它们位于 bookstore 之下的什么位置。

//@class

选取名为 class 的所有属性。

./a

选取当前元素下的a

…/a

选取父元素下的a

a/@href

选取a标签的href属性

a/text()

选取a标签下的文本

鼠标动作链

以下代码和文字(包括本小章节到页面等待章节前)引用了网址selenium教程 - 简书 (jianshu.com),有少量修改

引入鼠标动作库from selenium.webdriver import ActionChains这样就可以使用复杂的鼠标动作了。

# 鼠标移动到 ac 位置
ac = driver.find_element_by_xpath('element')
ActionChains(driver).move_to_element(ac).perform()

# 在 ac 位置单击
ac = driver.find_element_by_xpath("elementA")
ActionChains(driver).move_to_element(ac).click(ac).perform()

# 在 ac 位置双击
ac = driver.find_element_by_xpath("elementB")
ActionChains(driver).move_to_element(ac).double_click(ac).perform()

# 在 ac 位置右击
ac = driver.find_element_by_xpath("elementC")
ActionChains(driver).move_to_element(ac).context_click(ac).perform()

# 在 ac 位置左键单击按住
ac = driver.find_element_by_xpath('elementF')
ActionChains(driver).move_to_element(ac).click_and_hold(ac).perform()

# 将 elementD 拖拽到 elementE') 位置
ac1 = driver.find_element_by_xpath('elementD')
ac2 = driver.find_element_by_xpath('elementE')
ActionChains(driver).drag_and_drop(ac1, ac2).perform()

如果是普通的点击,也可以直接使用如下代码点击,不用ActionChains类

driver.find_element_by_xpath("//button[@type='button']").click()

选择表单

若碰到<select> </select>标签的下拉框,需要使用引用from selenium.webdriver.support.ui import Select。代码如下:

# 找到 name 的选项卡
select = Select(driver.find_element_by_name('status'))
# 
select.select_by_index(1)
select.select_by_value("0")
select.select_by_visible_text(u"未审核")

以上是三种选择下拉框的方式,它可以根据索引来选择,可以根据值来选择,可以根据文字来选择。

  • index 索引从 0 开始

  • value是option标签的一个属性值,并不是显示在下拉框中的值

  • visible_text是在option标签文本的值,是显示在下拉框的值

全部取消选择的代码如下:

select.deselect_all()

上传文件

首先区分出上传按钮的种类,大体上可以分为两种

  • 一种是input框

  • 另外一种就比较复杂,通过js、flash等实现,标签非input

input上传

该方法大概针对该类型的html:

<input type="file" name="file" id="file" /> 

遇到该类型的html,selenium可以十分简单粗暴得上传图片:

upload = driver.find_element_by_id('file')
upload.send_keys('d:\\all_money.wmv')  # send_keys

非input上传

这种上传千奇百怪,有用a标签的,有用div的,有用button的,有用object的,selenium没有办法通过直接在网页上处理掉这些上传,唯一的办法就是打开OS弹框,去处理弹框。

但是OS弹框涉及的层面已经不是selenium能解决的了,大体上有以下几种解决方案:

  • autoIT:借助外力,我们去调用其生成的au3或exe文件。

  • pywin32库:识别对话框句柄,进而操作

  • SendKeys库

  • keybd_event:跟pywin32库类似,但是是模拟按键,ctrl+a,ctrl+c, ctrl+v…

页面前进和后退

driver.forward()     # 前进
driver.back()        # 后退

页面切换

切换窗口

浏览器会有很多窗口,所以要有方法来实现窗口的切换

driver.switch_to.window("this is window name")

也可以使用 window_handles 方法来获取每个窗口的操作对象

for handle in driver.window_handles:
    driver.switch_to.window(handle)

切换到iframe(通过页面的UI)

页面中可能会存在iframe元素,需要切换到iframe里面才可以让Selenium操作里面的内容

driver.switch_to.frame(driver.find_element_by_xpath("/html/body/div[3]/div[5]/div[1]/div[7]/iframe"))

弹窗处理

当触发了某个事件之后,页面出现了弹窗提示,处理如下代码提示或者获取提示信息方法

alert = driver.switch_to.alert()
alert.accept()# 点击弹窗的确认
alert.text# 获取弹窗文本内容

Cookies

获取页面每个Cookies值

for cookie in driver.get_cookies():
    print "%s -> %s" % (cookie['name'], cookie['value'])

删除Cookies

# By name
driver.delete_cookie("CookieName")

# all
driver.delete_all_cookies()

页面等待

现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过长导致某个dom元素还没出来,但是代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。

为了避免这种元素定位困难而且会提高产生 ElementNotVisibleException 的概率。所以 Selenium 提供了两种等待方式,一种是隐式等待,一种是显式等待。

隐式等待是等待特定的时间,显式等待指定某个条件,然后设置最长等待时间。如果在这个时间还没有找到元素,那么便会抛出异常了。

显式等待

引入WebDriverWait

from selenium.webdriver.support.wait import WebDriverWait

WebDriverWait的API

WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)

说明:

  • driver:浏览器驱动

  • timeout:最长超时时间,默认以秒为单位

  • poll_frequency:检测的间隔步长,默认为0.5s

  • ignored_exceptions:超时后的抛出的异常信息,默认抛出NoSuchElementExeception异常。

WebDriverWait通常与until()或者until_not()方法结合使用:

# 调用该方法提供的驱动程序作为参数,直到返回值为True
WebDriverWait(driver,10).until(method,message="")
# 调用该方法提供的驱动程序作为参数,直到返回值为False
WebDriverWait(driver,10).until_not(method,message="")

可以自定义等待条件:

#设置等待
wait = WebDriverWait(driver,10,0.5)
#使用匿名函数
wait.until(lambda diver:driver.find_element_by_id('kw'))

WebDriverWait与expected_conditions方法结合使用:

from selenium.webdriver.common.by import By
# WebDriverWait 库,负责循环等待
from selenium.webdriver.support.wait import WebDriverWait
# expected_conditions 类,负责条件出发
from selenium.webdriver.support import expected_conditions as EC

# 页面一直循环,直到 id="myDynamicElement" 出现
wait = WebDriverWait(driver,10)
element = wait.until(EC.presence_of_element_located((By.ID,"myDynamicElement")))

如果不写步长参数,程序默认会 0.5s 调用一次来查看元素是否已经生成,如果本来元素就是存在的,那么会立即返回。

expected_conditions类提供的预期条件判断的方法如下表:

方法

说明

title_is

判断当前页面的 title 是否完全等于(==)预期字符串,返回布尔值

title_contains

判断当前页面的 title 是否包含预期字符串,返回布尔值

presence_of_element_located

判断某个元素是否被加到了 dom 树里,并不代表该元素一定可见

visibility_of_element_located

判断元素是否可见(可见代表元素非隐藏,并且元素宽和高都不等于 0)

visibility_of

同上一方法,只是上一方法参数为locator,这个方法参数是 定位后的元素

presence_of_all_elements_located

判断是否至少有 1 个元素存在于 dom 树中。举例:如果页面上有 n 个元素的 class 都是’wp’,那么只要有 1 个元素存在,这个方法就返回 True

text_to_be_present_in_element

判断某个元素中的 text 是否 包含 了预期的字符串

text_to_be_present_in_element_value

判断某个元素中的 value 属性是否包含 了预期的字符串

frame_to_be_available_and_switch_to_it

判断该 frame 是否可以 switch进去,如果可以的话,返回 True 并且 switch 进去,否则返回 False

invisibility_of_element_located

判断某个元素中是否不存在于dom树或不可见

element_to_be_clickable

判断某个元素中是否可见并且可点击

staleness_of

等某个元素从 dom 树中移除,注意,这个方法也是返回 True或 False

element_to_be_selected

判断某个元素是否被选中了,一般用在下拉列表

element_selection_state_to_be

判断某个元素的选中状态是否符合预期

element_located_selection_state_to_be

跟上面的方法作用一样,只是上面的方法传入定位到的 element,而这个方法传入 locator

alert_is_present

判断页面上是否存在 alert

隐式等待

隐式等待比较简单,就是简单地设置一个等待时间,单位为秒。

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

图像验证码识别

很多网站上都有图像验证码,这是自动化测试的一大难题,这里用ddddorc来识别网站的比较简单的图像验证码文字,但是一旦碰到识别准确率不高的情况下需要手动处理。

参考:⚡爬虫高级篇⚡五行代码识别验证码—— ddddocr(带带弟弟OCR)_肥学的博客-CSDN博客

安装

pip install ddddocr

引用

import ddddocr

使用

import ddddocr
import time
begin=time.time()
ocr = ddddocr.DdddOcr()

with open('test.png', 'rb') as f:
    img_bytes = f.read()
res = ocr.classification(img_bytes)
finish=time.time()
print("结果:")
print(res)
print("用时:%s 秒" % str(finish-begin))

Airtest-Selenium

简介

airtest-selenium库是基于selenium库的进一步封装,有如下几个特点:

  1. 对切换标签的界面进行了友好封装

  2. 支持图像识别功能

  3. 自动进行log记录(参考selenium-java的监听模式)

  4. 兼容selenium的原生api

注意:Airtest-Selenium暂时不兼容selenium4,需要将selenium版本更改为3.0的版本后才能使用,否则会报WebElement' object has no attribute '_w3c'的错误,可以在pycharm中将selenium修改为3.x的版本

安装

pip install airtest-selenium
pip install pynput

引用

# 引入selenium的webdriver模块
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from airtest.core.api import *
from airtest_selenium.proxy import WebChrome

初始化

需要把Chrome浏览器的驱动放在python的根目录上,具体下载在Selenium中说明。注意,要引用from airtest_selenium.proxy import WebChrome的接口

#创建一个实例,代码运行到这里,会打开一个chrome浏览器
driver = WebChrome()

api

  • driver.airtest_touch:airtest-selenium封装的图像点击

driver.airtest_touch(Template(......))
  • driver.assert_template:airtest-selenium封装的图像存在断言

driver.assert_template(Template(......), "请填写测试点")
  • snapshot:airtest-selenium封装的页面截图操作

driver.snapshot()
  • previous_tab:airtest-selnium封装的切换到上一个标签页的操作

driver.switch_to_previous_tab()
  • new_tab:airtest-selenium封装的切换到新打开标签页的操作

driver.switch_to_new_tab()

运行

python -m airtest run 

或者与selenium相同,在main方法中运行

Ubuntu运行selenium

selenium不仅仅能在windows上运行,也能在linux上运行,这里用Ubuntu去运行。

源自:Linux Ubuntu 下安装使用selenium 环境搭建-学习笔记-JerryCoding个人博客

安装chrome

sudo apt-get install libxss1 libappindicator1 libindicator7 # 安装依赖库
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb # 获取chrome安装包
sudo dpkg -i google-chrome*.deb # 开始安装
google-chrome --version # 查看版本

下载chromedriver

#执行如下命令(第一条用于获取最新版本号,第二条用于下载):
LATEST=$(wget -q -O - http://chromedriver.storage.googleapis.com/LATEST_RELEASE)
wget http://chromedriver.storage.googleapis.com/$LATEST/chromedriver_linux64.zip

# 解压
unzip chromedriver_linux64.zip

# 修改权限
chmod +x chromedriver

# 可以移动driver 省的指定位置
sudo mv chromedriver /usr/bin/

# 查看版本
./chromedriver --version

测试

from selenium import webdriver
# 如果没有将driver移动到 sudo mv chromedriver /usr/bin/ 要指定 driverpath
driverpath = ''       
driver = webdriver.Chrome(executable_path=driverpath)
driver.get("https://www.baidu.com/")
print(driver.title)

文章作者: Vsoapmac
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 soap的会员制餐厅
自动化测试 第三方库 个人分享 爬虫 框架
喜欢就支持一下吧