UI自动化常见问题处理总结

八大元素定位方式

单数定位方法,遇到多个值,默认取第一个。也可以加索引取其他值,索引从1开始

driver.find_element_by_id()
driver.find_element_by_name()
driver.find_element_by_class_name()
find_element_by_link_text()
driver.find_element_by_partail_link_text()
driver.find_element_by_xpath()
driver.find_element_by_css_slecter()

复数定位,返回的是一个list。和上述方法相同,只是把element改为elements
如:driver.find_elements_by_xpath()
其他书写方式
在做web自动化时,往往是需要封装脚本的。上述的方法不利于封装,并且后期将不再维护了。

# 导入By类
from selenium.webdriver.common.by import By
# 以下三种写法是相等的
driver.find_element_by_id('kw')
driver.find_element('id','kw')
driver.find_element(By.ID,'kw') # 需要先导入By类

三种等待方式

我们在做web自动化时,经常会遇到因为加载慢而出现元素未找到的情况,这种情况只需要加一个等待就好。
等待有三种方式:强制等待、隐式等待和显式等待

sleep():强制等待,设置固定休眠时间

执行sleep()后线程休眠的时间,如设置3秒,则必须等待3秒再继续下面的代码。

import time

# 强制等待3秒钟
time.sleep(3)

implicitly_wait():隐式等待,设置的全局等待,只需要设置一次

对页面中所有的元素设置加载时间,如设置10秒,如果在1秒的时候找到元素则继续,不需要等到10秒后再继续流程。如果超过10秒未找到则抛出异常。
注:隐式等待只对查找元素生效,对于页面中是否包含某个文本,元素是否可以点击是不生效的

from selenium import webdriver
    
driver = webdriver.Chrome()
driver.implicitly_wait(10)  # 设置隐式等待,最长等待时间是10秒

WebDriverWait():显式等待,是针对某个元素设置的等待时间

在设置的时间内,默认每隔一段时间检测一次是否满足条件,满足条件则继续执行下面的代码,超过时间就抛出异常。默认检测频率是0.5秒,默认抛出异常NoSuchElementException。
显式等待使用时需要加上条件配合使用,比如等待某个元素可见、等待某个元素可点击、等待某个元素是否包含某个文本等等,因此需要导入两个模块
以下是最常用的几种条件:

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait   # 导入显示等待模
from selenium.webdriver.support import expected_conditions   # 导入条件模块

driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
# 实例化一个WebDriverWait,最长等待时间为10秒,默认0.5秒检测一次,这里设置为0.2秒。
#wait = WebDriverWait(driver, timeout=10, poll_frequency=0.2)
wait = WebDriverWait(driver, 10, 0.2) # 简写
locator = ['id', 'kw']
# 等待某个元素加载
elem = wait.until(expected_conditions.presence_of_element_located(locator))
# 等待元素可见
elem = wait.until(expected_conditions.visibility_of_element_located(locator))
# 等待元素可以被点击
elem = wait.until(expected_conditions.element_to_be_clickable(locator))
elem.send_keys('上海')
elem.submit()
# 等待页面标题中含有“上海”
wait.until(expected_conditions.title_contains('上海'))

iframe标签切换

提供 iframe 的标识:index, name, iframe, Webelement
如果想定位iframe标签下的元素,不能直接查找,需要先切换到该iframe标签下才能进行定位。如图,要定位select需要先切换到iframe下
[图片上传失败...(image-9dd793-1629275203459)]

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get('https://www.w3school.com.cn/tiy/t.asp?f=html_select')
# 通过 WebElement 切换
iframe = driver.find_element('id', 'iframeResult')
driver.switch_to.frame(iframe)

# 通过 name 属性切换
driver.switch_to.frame('iframeResult')

# 通过索引切换
driver.switch_to.frame(0)

#切换后就可以找到select元素了
elem = driver.find_element('xpath', '//select')
print(elem)

# 退回主页面
driver.switch_to.default_content()

# 退回父级iframe
driver.switch_to.parent_frame()

alert弹窗处理

现在的网页一般是css或js实现弹窗效果,可以使用常用的元素定位方法来操作。如果遇到了alert弹窗,怎么处理呢?
其实很简单,只需要使用switch_to.alert方法就可以切换到弹窗,然后使用text/accept/dismiss/ send_keys等方法进行操作。

# 切换到alert弹窗,没有括号,也不需要传参数,全局只有一个
my_alert = driver.switch_to.alert
# 返回alert弹框中的文字信息
print(my_alert.text)
# 确定,接收弹窗
my_alert.accept()
# 取消,关闭弹窗
my_alert.dismiss()
# 向弹窗发送文字
my_alert.send_keys('哈哈哈')

window窗口切换

在web自动化时,如果遇到点击链接在新窗口打开,而我们要操作新窗口就要用到切换窗口了。比如,百度搜索“京东”,点击京东官网

  • 切换窗口用到的是switch_to.window(),它需要传入目标窗口的句柄
  • 句柄可以理解为窗口的id,在浏览器中是唯一的
  • 切换窗口的步骤:打开新窗口--> 获取当前浏览器所有句柄--> 选择最后一个句柄,因为新窗口都是放在最后的
from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10)
# 打开百度,定位输入框,输入“京东”,点击搜索
driver.get("http://www.baidu.com")
elem = driver.find_element('id', 'kw') 
elem.send_keys('京东') 
driver.find_element('id', 'su').click()
# 查找京东,点击
driver.find_element('xpath',"//h2[@class='c-font-big']").click()
# 等待新页面出现
time.sleep(2)
#获取所有句柄
handle = driver.window_handles
#切换到最后一个句柄
driver.switch_to.window(handle[-1])

鼠标操作

selenium给我们提供了一个ActionChains类来处理鼠标的操作,比如悬浮、移动、拖拽、右击等。使用前需要先导入,先来看一个百度“设置”的示例

from selenium import webdriver
from selenium.webdriver import ActionChains
import time

driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get('http://www.baidu.com')
driver.maximize_window()
# 实例化一个ActionChains,可全局使用
ac = ActionChains(driver)
# 找到”设置“元素
setting = driver.find_element('xpath', "//span[text()='设置']")
# 鼠标悬停, move_to_element
ac.move_to_element(setting).perform()
time.sleep(2)
# 找到高级搜索
adv_setting = driver.find_element('xpath', "//a[text()='高级搜索']")
adv_setting.click()  # 也可以用 ac.click(adv_setting).perform() 方法

鼠标操作的所有方法,后面都需要执行perform()操作才会生效
所有的鼠标操作可以连在一次,最后再一次性释放操作,称为“链式调用”,比如

ac.move_to_element(setting).click(adv_setting).drag_and_drop().context_click().perform()

鼠标操作常见的方法:

perform()  # 执行链中的所有动作
ac.click(elem).perform()  #单击
ac.double_click(elem).perform()  # 双击
ac.context_click(elem).perform()  #右击
ac.move_to_element(elem).perform()  #鼠标移动到elem,悬停
ac.drag_and_drop(elem1, elem2).perform()  #elem1拖拽到elem2然后松开

键盘操作

selenium提供了比较完整的键盘操作,在使用的模拟键盘操作之前需要导入。先来看一个百度搜索的示例

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()
driver.implicitly_wait(10)

# 定位百度搜索框,输入搜索词“python“,分别用三种方法来实现搜索
driver.get('http://www.baidu.com')
input_el = driver.find_element('id', 'kw')
input_el.send_keys('python')

# 方法一,定位“搜索”元素,点击
driver.find_element('id', 'su').click()

# 方法二,form表单下可以用submit() 提交进行搜索
input_el.submit()

# 方法三,敲回车键
input_el.send_keys(Keys.ENTER)

# 方法四,ActionChains 和 Keys 组合使用,传入鼠标操作
ac = ActionChains(driver)
ac.send_keys(Keys.ENTER).perform()

在keys类中,定义了非常多的按键操作,并且按键是可以组合操作的,比如Ctrl+C等。按键操作往往是结合元素来操作的,例如百度搜索实例的方法三。这些操作都是需要使用send_keys()来发送的。以下内容是在实际上会常用到的

from selenium.webdriver.common.keys import Keys
send_keys(Keys.CONTROL,'a')  # 全选(Ctrl+A)
send_keys(Keys.CONTROL,'c')  # 复制(Ctrl+C)
send_keys(Keys.CONTROL,'x')  # 剪切(Ctrl+X)
send_keys(Keys.CONTROL,'v')  # 粘贴(Ctrl+V)
send_keys(Keys.ENTER)# 回车键
send_keys(Keys.BACK_SPACE) # 删除键
send_keys(Keys.SPACE) # 空格键
send_keys(Keys.TAB)  # 制表键
send_keys(Keys.ESCAPE)  # 回退键
send_keys(Keys.F5)  # 刷新键

Select下拉框

from selenium import webdriver
from selenium.webdriver.support.select import Select

driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get('url')

# 方法一:直接定位选项的元素进行点击
driver.find_element('xpath', "ele").click()

# 方法二,先找到select元素,再把元素对象传入Select类进行实例化
s = driver.find_element('id', "ele")
s_obj = Select(s)
# 以下分别通过value属性值、text文本和索引进行选择
s_obj.select_by_value('value')
s_obj.select_by_visible_text('text')
s_obj.select_by_index(1)

js脚本

修改12306官网的出发日期

import time
from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get('https://www.12306.cn/index/')
# 执行 js 语句写上日期(修改value值),js可以多个语句写在一起,分号隔开,按顺序执行
time.sleep(5)
js_code = "let input = document.getElementById('train_date');input.readOnly = false;input.value = '2021-03-11';"
driver.execute_script(js_code)
time.sleep(5)

上面查找元素用的是js,我们也可以js和python混用,使用python来查找元素

import time
from selenium import webdriver

driver = webdriver.Chrome()
input_elem = driver.find_element('id', 'train_date')
time.sleep(2)
# 准备 js 代码
js_code = "arguments[0].readOnly = false; arguments[0].value = '2021-03-22';"
driver.execute_script(js_code, input_elem)

time.sleep(3)

arguments可以理解为python里面的占位符,如果还有参数,可以继续使用arguments[1]、arguments[2]来占位

窗口滚动

窗口滚动selenium是无法实现的,所以这里是借助的js代码来操作滚动条。在python中,执行js代码用的是
driver.execute_script(js_code)
窗口滚动最常用的是滚动到可视范围内,下面是12306上的小示例

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10)

driver.get('https://www.12306.cn/index/')
# 找到需要定位的元素
el = driver.find_element('xpath', "//h2[contains(text(),'友情链接')]")
# 方法一,将元素滚动到可视范围之内
el.location_once_scrolled_into_view()
# 方法二,和方法一效果相同
driver.execute_script("arguments[0].scrollIntoView();", el)
# 将元素向下滚动200个像素(y坐标)
driver.execute_script('window.scrollBy(0,200);')
# 向右滚动200个像素(x坐标)
driver.execute_script('window.scrollBy(200,0);')
# 将窗口滚动到底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 设置窗口大小
driver.set_window_size(800, 700)

文件上传

我们在使用python做web自动化的过程中,经常会遇到文件上传的操作。对于文件上传存在input输入框情况,可以直接定位input元素,使用send_keys(filepath)方法实现。对于没有input输入框的文件上传,则需要借助第三方工具,在上传文件时打开系统窗口。以下是两个上传文件操作比较简单的工具

  • windows系统:pywinauto库
    安装:pip install pywinauto
    导入:from pywinauto.keyboard import send_keys
  • mac/Linux/window通用:pyautogui 跨平台
    python3.8环境:先安装依赖 pip install pillow==6.2.2,再安装 pip install pyautogui
    非python3.8环境:直接 pip install pyautogui
    导入:import pyautogui

input元素使用send_keys()方法

from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.implicitly_wait(10)
URL = 'https://xxxx/kk-form/fs/fm/form/161519068236342881d3774ec5428571/fill'
driver.get(URL)
# 获取上传组件的元素
f = driver.find_element('xpath', "(//input[@class='van-uploader__input'])[1]")
# 使用send_keys直接发送文件路径即可
f.send_keys(r'/Users/lili/Documents/weixin.jpeg')
time.sleep(5)
driver.quit()

非input元素,window方法:使用pywinauto库

from pywinauto.keyboard import send_keys
from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.implicitly_wait(10)
URL = 'https://xxxx/kk-form/fs/fm/form/161519068236342881d3774ec5428571/fill'
driver.get(URL)
f = driver.find_element('xpath', "(//input[@class='van-uploader__input'])[1]")
# 触发点击事件,让系统的弹框弹出来
f.click()
# 等待,因为弹框弹出来需要时间
time.sleep(1)
# 这里是pywinauto 的send_keys 方法
send_keys(r'/Users/lili/Documents/weixin.jpeg')
# 使用return提交
send_keys('{VK_RETURN}')

非input元素,mac/Linux/window的通用方法:pyautogui库

from selenium import webdriver
import pyautogui
import time

driver = webdriver.Chrome()
driver.implicitly_wait(10)
URL = 'https://xxxx/kk-form/fs/fm/form/161519068236342881d3774ec5428571/fill'
driver.get(URL)
f = driver.find_element('xpath', "(//input[@class='van-uploader__input'])[1]")
# 触发点击事件,让系统的弹框弹出来
f.click()
time.sleep(1)
# 写入路径
pyautogui.write(r'/Users/lili/Documents/weixin.jpeg')
# 敲回车:相当于点击【打开】按钮,需要敲2次,避免失败
pyautogui.press('enter', 2)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容