Python之UI自动化基础

Python之UI自动化

环境搭建

安装Selenium库

pip install -U selenium

准备浏览器驱动文件

因浏览器版本众多,我们只对开发常用的必备适配的浏览器Google的Chrome和Mozilla的Firefox浏览器进行讲解

我们只需要将我们下载好的驱动文件复制到我们python的安装根目录即可

Windows默认的python安装根目录:C:\Users\自己电脑的用户名\AppData\Local\Programs\Python\Python37

Chrome浏览器驱动下载

查看自己电脑安装Chrome浏览器版本进行下载

  • 下载地址:
    • 官方下载地址:https://sites.google.com/a/chromium.org/chromedriver/downloads
    • 国内镜像地址:https://registry.npmmirror.com/binary.html?path=chromedriver/
Firefox浏览器驱动下载

Firefox没有强制的版本对应,但是有驱动文件最低适配浏览器版本的限制,下载时应注意限制的最低版本

image-20191216170908599.png

  • 下载地址:https://github.com/mozilla/geckodriver/releases

使用selenium对浏览器进行操作

各种对浏览器的操作:https://www.frostysun.cn/archives/34.html

## 引入依赖的库
from selenium import webdriver

## 实例化Chrome方法打开一个chrome浏览器并将这个浏览器对象赋值给drive
drive = webdriver.Chrome()

## 使用drive调用get方法,打开一个网站
drive.get("https://www.baidu.com")

# 设置浏览器最大化
drive.maximize_window()

# 设置浏览器窗口的大小
drive.set_window_size(400,800)

# 回退
drive.back()

# 前进
drive.forward()

# 刷新
drive.refresh()

# 获取网页的title
print(drive.title)

# 获取当前网址
print(drive.current_url)

# 获取当前窗口的id
print(drive.current_window_handle)
## 结束会话
"""
为什么我们要关闭呢?
因为我们使用chromedrive程序去打开chrome浏览器
我们最终可能就仅仅是关闭了浏览器,并未关闭chromedrive驱动程序
我们可以在电脑的进程列表中查看到
此时我们需要调用quit方法进行结束进程
需要注意close方法和quit的区别,close是关闭标签页
"""
drive.quit()

HTML简介

WEB页面的组成

  • 一般WEB页面的组成是由HTML+CSS+JavaScript组成
    • HTML:页面的基本内容的展现
    • CSS:定义页面样式、颜色、布局、大小等等
    • JavaScript:可以进行前后端交互、页面操作的事件、动作、一些炫酷的动画等等

掌握内容

我们学习UI自动化,只需要了解简单的HTML标签以及JavaScript的一些DOM对象即可,针对性了解即可,不需要全量学习

掌握Chrome浏览器或者fFirefox浏览器的元素定位等等

熟悉HTML的常用标签

W3school地址:https://www.w3school.com.cn/tags/index.asp

标签释义
<a></a>超链接
<body></body>页面主体
<br/>换行
<button></button>按钮
<div></div>
<form></form>表单
<head></head>页面的头部信息
<html></html>定义HTML页面
<img>定义图片
<input>输入框
<script></script>定义JavaScript脚本
<select></select>下拉列表,和一起配合使用
<style></style>CSS样式
<table></table>表格
<title></title定义页面的标题

元素定位

元素定位的方式

元素的定位方式分为:ID定位、class定位、tagname(标签名)定位、name定位、链接定位、xpath定位、css定位

简单元素定位
## 引入依赖的库
from selenium import webdriver

## 实例化Chrome方法打开一个chrome浏览器并将这个浏览器对象赋值给drive
drive = webdriver.Chrome()

## 打开百度
drive.get("http://www.baidu.com")

"""
通过ID定位
"""
## 定位到百度的输入框
## 返回一个WebElement,也就是一个DOM元素
wele = drive.find_element_by_id("kw")

# 获取这个DOM元素中的一个属性
print(wele.get_attribute("maxlength"))


"""
通过class定位
"""
## 通过class定位的时候,如果class值有多个,我们只能选择其中一个进行定位
## 应为class属性的值可能不唯一,会导致找到多个元素,此方法会返回多个元素
wele = drive.find_elements_by_class_name("s_ipt")

## 此方法只返回找到的第一个元素
wele = drive.find_element_by_class_name("s_ipt")

## 打印获取到的DOM元素中的一个属性
print(wele.get_attribute("maxlength"))

"""
通过name定位
"""
## 返回一个
wele = drive.find_element_by_name("wd")

## 返回多个
wele = drive.find_elements_by_name("wd")

"""
通过标签名定位
"""

## 返回一个
wele = drive.find_element_by_tag_name("input")

## 返回多个
wele = drive.find_elements_by_tag_name("input")

"""
仅针对文字链接
"""
## 完全匹配
wele = drive.find_element_by_link_text("hao123")
wele = drive.find_elements_by_link_text("hao123")

## 模糊匹配
wele = drive.find_element_by_partial_link_text("hao")
wele = drive.find_elements_by_partial_link_text("hao")
复杂元素定位
xpath定位

元素的xpath定位我们可以在浏览器的F12使用ctrl+f调出查找,然后输入我们的xpath表达式进行验证

  • 绝对定位

    • 非常依赖于浏览器中元素的位置和顺序,在正常项目中尽量避免使用,开发的代码修改和数据的改变都可能导致之前的绝对定位在修改后失败

    • 可以在浏览器F12开发者模式选中需要定位的元素,然后右键 copy -> copy full xpath

      ## 编写,通过标签名称以及以及'下标'进行定位
      /html/body/div[2]/div[2]/div[5]/div[1]/div/form/span[1]
      
  • 相对定位

    • 很好的避免了上面绝对定位的很多弊端

    • 缺点就是相对于绝对定位编写稍显复杂

    • 最新的chrome浏览器然后右键 copy -> copy xpath 即可获取到当前标签的相对定位

      ## 编写
      ## //标签名称[@标签的元素名称="名称的值"]
      //input[@name="wd"]
      
      ## 逻辑与、逻辑或在此处是可以使用的,我们可以用多个元素的名称定位
      //标签名称[@标签的元素名称="名称的值" and @标签的元素名称="名称的值"]
      """
      层级定位
      """
      ## 根据上级来定位下级
      //div[@id="u1"]/a[@name="tj_login"]
      //*[@id="u1"]/a[7]  ## *代表全部
      """
      函数定位
      """
      ## text文本定位
      //*[@id="u1"]/a[text()="登录"]
      
      ## contains()包含函数定位
      //*[@id="u1"]/a[contains(@name,"login")]
      //*[@id="u1"]/a[contains(text(),"登录")]
      
      """
      轴定位
      """
      # 轴计算
      ## ancestor:祖先节点,包含父节点(常用)
      ## parent:父节点(常用)
      ## preceding:当前标签节点标签之前的所有节点
      ## preceding-sibling:当前节点元素节点标签之前的所有兄弟节点(常用)
      ## fillowing:当前元素节点标签之后的所有节点
      ## following-sibling:当前元素节点标签之后的所有兄弟节点(常用)
      
      ## 经常使用多个相同的类表格元素的定位
      /轴名称::节点名称
      ## 我们定位192.168.3.100地址下的一个元素
      //a[text()="资金周转"]/parent::td/following-sibling::td//span
      

image-20191224195058498.png

Selenium框架

等待操作

需求:

打开百度,点击登录,等待点击用户名按钮出现,进行点击

Ps:三种等待方式不冲突,可同时使用

强制等待

强制等待非常不推荐使用

## 引入依赖的库
from selenium import webdriver

import time

## 实例化Chrome方法打开一个chrome浏览器并将这个浏览器对象赋值给drive
drive = webdriver.Chrome()

## 打开百度
drive.get("http://www.baidu.com")
## 定位到登录按钮,并进行点击
drive.find_element_by_xpath('//*[@id="u1"]/a[7]').click()

## 强制等待,单位是秒
time.sleep(15)

## 点击用户名登录
drive.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__footerULoginBtn"]').click()
隐性等待

隐式等待较为机智,我们只需要设置最大等待时间即可,系统会自动去判定,如果元素出现,则自动停止等待,去操作元素,如超过等待时间还是没有出现,则出现NoSuchElementException(找不到定位元素)异常,

## 引入依赖的库
from selenium import webdriver

## 实例化Chrome方法打开一个chrome浏览器并将这个浏览器对象赋值给drive
drive = webdriver.Chrome()

## 打开百度
drive.get("http://www.baidu.com")
## 设置等待
## 需要注意的是这个等待是全局的,局限性源码已经交代,用于元素查找操作
## 单位是秒
drive.implicitly_wait(30)

## 定位到登录按钮,并进行点击
drive.find_element_by_xpath('//*[@id="u1"]/a[7]').click()

## 点击用户名登录
drive.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__footerULoginBtn"]').click()
显性等待

显性等待比隐性等待更加方便,需要明确告诉它等待什么,如果条件成立,则继续执行,否则就继续等待,直到超过最大等待时间抛出异常TimeoutException

WebDriverWait(drive,等待时长,轮循周期).until()/until_not()

drive:监控的内容

轮循周期:每隔多少时间进行一次检查,检查是否满足条件

显性等待中的EC(expected_conditions)模块常用方法
  • title_is(String title):判断当前页面的title是否精确等于预期
  • title_contains(String title):判断当前页面的title是否包含预期字符串
  • presence_of_element_located(By locator):判断某个元素是否被加到了dom树里,并不代表该元素一定可见
  • visibility_of_element_located(By locator):判断某个元素是否可见(代表元素非隐藏,元素的宽和高都不等于0)
  • invisibility_of_element_located(By locator):判断某个元素中是否不存在于dom树或不可见
  • text_to_be_present_in_element(By locator, String text):判断某个元素中的text是否包含了预期的字符串
  • text_to_be_present_in_element_value(By locator, String text):判断某个元素中的value属性是否包含了预期的字符串
  • element_to_be_clickable(By locator):判断某个元素中是否可见并且是enable(可用)的,这样的话才clickable(可点击)
  • element_to_be_selected(By locator):判断某个元素是否被选中了,一般用在下拉列表
  • alert_is_present():判断页面上是否存在alert
示例代码
## 引入依赖的库
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

import time

## 实例化Chrome方法打开一个chrome浏览器并将这个浏览器对象赋值给drive
drive = webdriver.Chrome()

## 打开百度
drive.get("http://www.baidu.com")
"""
WebDriverWait(drive,等待时长,轮循周期).until()/until_not()
"""
## 检查使用账户登录是否存在
## 此处传参我们使用元组的方式,我们需要传定位的方式,以及定位的表达式
## 定位方式我们可以用By下面定义的方式
# EC.visibility_of_element_located((By.ID,"TANGRAM__PSP_10__footerULoginBtn"))

## 设置显性等待,第三个参数有默认值,默认0.5秒
## 每0.5秒检查一次,元素是否存在,如果存在则结束等待,如果不存在则继续等待,超过20秒则超时并抛出异常
WebDriverWait(drive,20).until(EC.visibility_of_element_located((By.ID,"TANGRAM__PSP_10__footerULoginBtn")))

## 点击用户名登录
drive.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__footerULoginBtn"]').click()

iframe切换定位

如果直接定位iframe中的元素ID之类的,可能会导致定位失败报错,因为iframe中一般内嵌了另一个HTML页面,例如QQ音乐的登录弹出框

确定定位内容是否在iframe中可以在F12模式下的Element下的HTML路径中看到

如果要查找页面的iframe有多少个,可以直接用相对定位//iframe

传统切换
"""
查看源码了解参数,drive.switch_to.frame()方法可以有三种定位方式传参
1、通过页面中iframe的下标传参
    driver.switch_to.frame(1)
2、通过iframe的name属性
    driver.switch_to.frame('frame_name')
3、通过具有返回element的方法定位
    我们一般使用第三种
    driver.switch_to.frame(driver.find_elements_by_tag_name("iframe")[0])
"""
## 引入依赖的库
from selenium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
## 实例化Chrome方法打开一个chrome浏览器并将这个浏览器对象赋值给drive
drive = webdriver.Chrome()
drive.get("https://y.qq.com/")
## 设置切换iframe
drive.switch_to.frame(drive.find_element_by_xpath('//*[@id="frame_tips"]'))
## 设置等待时间2秒
time.sleep(2)
## 点击头像登录
drive.find_element_by_xpath('//*[@id="img_out_851146837"]')
使用显性等待的方式切换
## 在此处我们可以通过EC的显性等待判断是否是否存在,EC会帮我们自动切换到iframe,无需我们手动切换
WebDriverWait(drive,10).until(EC.frame_to_be_available_and_switch_to_it(drive.find_element_by_xpath('//*[@id="frame_tips"]')))

## 然后我们直接去操作对应的元素即可
## 点击头像登录
drive.find_element_by_xpath('//*[@id="img_out_851146837"]')
切出iframe窗口
## 切出iframe,回到顶层默认的HTML页面中
drive.switch_to.default_content()

## 切出iframe,切回父级
drive.switch_to.parent_frame()

窗口(页签)切换

切换窗口需要用到窗口的句柄,也就是ID

打开百度,搜索京东,并打开京东页面

传统切换
## 引入依赖的库
from selenium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

## 实例化Chrome方法打开一个chrome浏览器并将这个浏览器对象赋值给drive
drive = webdriver.Chrome()
drive.get("http://www.baidu.com")
## 显性等待,等待出现输入框
WebDriverWait(drive,10).until(EC.visibility_of_element_located((By.XPATH,'//*[@id="kw"]')))
## 输入京东商城
drive.find_element_by_xpath('//*[@id="kw"]').send_keys("京东商城")
## 点击百度一下按钮
drive.find_element_by_xpath('//*[@id="su"]').click()
## 等待搜索结果出现
WebDriverWait(drive,10).until(EC.visibility_of_element_located((By.XPATH,'//*[@id="m19g5x5s"]/div/h2/a[1]')))
## 点击搜索到的京东商城
drive.find_element_by_xpath('//*[@id="m19g5x5s"]/div/h2/a[1]').click()
## 添加等待时间,等待窗口打开
time.sleep(1)

## 返回是一个列表的形式
handles = drive.window_handles
## 一般新窗口是最新出现的,他的ID会在最后一个,直接调用切换方法切换即可
drive.switch_to.window(handles[-1])

## 显示当前当前所在窗口的句柄
print(drive.current_window_handle)

## 点击登录
WebDriverWait(drive,10).until(EC.visibility_of_element_located((By.XPATH,'//*[@id="ttbar-login"]/a[1]')))
drive.find_element_by_xpath('//*[@id="ttbar-login"]/a[1]').click()
使用显性等待切换
## 引入依赖的库
from selenium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

## 实例化Chrome方法打开一个chrome浏览器并将这个浏览器对象赋值给drive
drive = webdriver.Chrome()
drive.get("http://www.baidu.com")
## 显性等待,等待出现输入框
WebDriverWait(drive,10).until(EC.visibility_of_element_located((By.XPATH,'//*[@id="kw"]')))
## 输入京东商城
drive.find_element_by_xpath('//*[@id="kw"]').send_keys("京东商城")
## 点击百度一下按钮
drive.find_element_by_xpath('//*[@id="su"]').click()
## 等待搜索结果出现
WebDriverWait(drive,10).until(EC.visibility_of_element_located((By.XPATH,'//*[@id="m19g5x5s"]/div/h2/a[1]')))
## 获取窗口句柄
handles = drive.window_handles
## 点击搜索到的京东商城
drive.find_element_by_xpath('//*[@id="m19g5x5s"]/div/h2/a[1]').click()
## 显性等待京东商城打开
WebDriverWait(drive,10).until(EC.new_window_is_opened(handles))
## 获取当前的句柄
handles = drive.window_handles
## 切换到新的窗口
drive.switch_to.window(handles[-1])
## 显示当前当前所在窗口的句柄
print(drive.current_window_handle)
## 点击登录
WebDriverWait(drive,10).until(EC.visibility_of_element_located((By.XPATH,'//*[@id="ttbar-login"]/a[1]')))
drive.find_element_by_xpath('//*[@id="ttbar-login"]/a[1]').click()

alert弹窗

"""
alert弹框
"""
alert = drive.switch_to.alert
## 输入内容
alert.send_keys("")
## 同意,确定,OK
alert.accept()
## 不同意,否,cancel
alert.dismiss()
## 获取弹窗内容
print(alert.text)

鼠标操作

鼠标操作由selenium的actionchains来完成

存储鼠标操作,使用perform()来操作鼠标执行

"""
支持的操作:
	double_click:双击
	context_click:右键操作
	drag_and_drop:拖拽操作
	move_to_element 鼠标悬浮操作
"""
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains

## 实例化Chrome方法打开一个chrome浏览器并将这个浏览器对象赋值给drive
drive = webdriver.Chrome()
## 打开百度
drive.get("http://www.baidu.com")
##设置全局隐性等待
drive.implicitly_wait(30)
## 全屏当前窗口
drive.maximize_window()
## 先定位元素  //*[@id="u1"]//a[@name="tj_settingicon"]
ele = drive.find_element_by_xpath('//*[@id="u1"]//a[@name="tj_settingicon"]')
## 实例化ActionChains
ac = ActionChains(drive)
## 将要执行的操作添加到我们的执行列表
ac.move_to_element(ele)
## 调用执行方法进行执行
ac.perform()
"""
由于ActionChains类中大部分的操作的函数返回值为当前类的引用,我们可以将一个元素的多个鼠标操作直接写到一起,方便操作
源码中有部分示例可作参考
"""
## 鼠标悬浮设置按钮
ActionChains(drive).move_to_element(drive.find_element_by_xpath('//*[@id="u1"]//a[@name="tj_settingicon"]')).perform()
## 通过单击选择设置中的高级搜索按钮
ActionChains(drive).click(drive.find_element_by_xpath('//*[@id="wrapper"]//a[text()="高级搜索"]')).perform()
## 此处也可以调用以下方法来实现
drive.find_element_by_xpath('//*[@id="wrapper"]//a[text()="高级搜索"]').click()

下拉列表操作

下拉列表selenium框架提供的对应的select类操作

"""
选择下拉列表中的标签有以下三种方式:
	通过元素下标选择:select_by_index() 下标从0开始
	通过value属性的值来选择:select_by_value()
	通过下拉列表中展示的文本值来选择:select_by_visible_text()
"""
## 引入select选择的类
from selenium.webdriver.support.ui import Select

## 前置代码参考鼠标选择,我们使用高级搜索中的下拉列表来操作
## 将时间下拉框使用文本值来定位并选择到最近一年
Select(drive.find_element_by_xpath('//*[@id="adv-setting-4"]/select')).select_by_visible_text("最近一年")
## 将文档格式下拉框使用value来定位并选择到doc
Select(drive.find_element_by_xpath('//*[@id="adv-setting-5"]/select')).select_by_value('doc')

键盘操作

普通的键盘输入我们可以直接调用send_keys即可,但是一些组合键比如ctrl+a、ctrl+c等等一些组合键可能就没有办法输入了,selenium提供了keys类来对一些组合键进行操作

from selenium.webdriver.common.keys import Keys
"""
原理是在Keys类中将所有的特殊定义为常量,常量的值为C语言中的对应编码
"""
## ctrl+a
send_keys(Keys.CONTROL, 'a')
## 回车
Keys.ENTER

对浏览器页面的滚动操作

"""
scrollIntoView(false) 带有参数false则是滚动到底部,如果没有参数则是滚动到顶部
需要注意的是这个滚动是以元素为基准的
"""
drive.execute_script("arguments[0].scrollIntoView(false)",element)
## 滚动到页面最顶部
drive.execute_script("window.scrollTo(document.body.scrollHeight,0)")
## 滚动到页面最底部
drive.execute_script("window.scrollTo(0,document.body.scrollHeight)")

时间输入框的处理

"""
对于时间输入框的处理我们一般有以下两种方式
输入框中有readonly属性的
	我们可以使用js的dom对象将元素的readonly属性修改,以达到可以输入的目录,将我们的内容输入到我们的输入框中
	比如12306的官网,我们可以在console下执行以下代码就可以将输入框修改为可输入状态
	document.getElementById('train_date').readOnly=false
	或者可以将readOnly属性移除掉
	document.getElementById('train_date').removeAttribute('readOnly')
	然后使用dom对象给输入框重新赋值
	document.getElementById('train_date').value="2020-01-10"
"""
drive.execute_script("document.getElementById('train_date').readOnly=false;document.getElementById('train_date').value='2020-01-10';")
## 此处我们也可以调用DOM对象的点击去点击查询按钮
drive.execute_script('document.getElementById('search_one').click()')
## 也可以使用arguments[0]将定位到的元素传递给js脚本进行操作
element = drive.find_element_by_xpath('//*[@id="search_one"]')
drive.execute_script("arguments[0].click()",element)

上传文件

上传文件分为两种

​ 1、可以直接输入上传文件路径的,我们可以直接调用send_keys,将文件路径输入到输入框中

​ 2、直接是按钮,没有输入框的,我们可能需要用到第三方的python库,针对Windows或者macOS系统的弹出框进行文件选择操作

​ 可能用到的第三方库有Autolt、Python pywin32(可以识别对话框句柄,进行操作)

windows窗口的弹出框的定位也需要使用到一个软件WinSpy来定位,Windows元素的定位是全部绝对定位,没有相对定位

定位到相对的元素,然后使用pywin32包提供的类进行操作

import win32gui

import win32con

这部分内容网上有很多相关的教程,我们在实际项目中基本是使用提前封装好的方法直接调用的,需要注意的是不同浏览器打开的标题可能不一致

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import win32gui
import win32con

"""
需要注意的是国内安装pywin32极有可能安装失败,原因是因为国内被墙,会导致下载失败
可以找到安装的whl文件然后    pip install 文件名称   进行安装
"""
class UpdateFile():
    def update_file(self,filepath):
        ## 一级窗口定位
        update_window = win32gui.FindWindow("#32770","打开")
        ## 二级窗口定位
        comboxex32 = win32gui.FindWindowEx(update_window,0,"ComboBoxEx32",None)
        ## 三级窗口定位
        combox = win32gui.FindWindowEx(comboxex32,0,"ComboBox",None)
        ## 四级窗口,定位文本输入窗口
        edit = win32gui.FindWindowEx(combox,0,"Edit",None)
        ## 二级窗口,打开按钮
        button = win32gui.FindWindowEx(update_window,0,"Button","打开(&O)")

        ## 输入文件地址
        win32gui.SendMessage(edit,win32con.WM_SETTEXT,None,filepath)
        ## 点击打开按钮上传文件
        win32gui.SendMessage(update_window, win32con.WM_COMMAND, 1, button)

if __name__ == '__main__':
    UpdateFile().update_file("D:\\测试.txt")
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值