03. Appium元素定位于操作
2024年10月28日大约 11 分钟
03. Appium元素定位于操作
1. 元素定位
1. 定位单个元素
通过UiAutoMatorViewer可以获取到元素信息,appium提供根据这些 信息找到具体元素方法
定位方式
ID定位
- driver.find_element(by=AppiumBy.ID, value="resource-id属性值")
- driver.find_element_by_id(resource-id属性值)
class定位
- driver.find_element(by=AppiumBy.CLASS_NAME, value="class属性值")
- driver.find_element_by_class_name(class属性值)
xpath定位
- driver.find_element(by=AppiumBy.XPATH, value="//*[@class='android.widget.ImageButton']")
- driver.find_element_by_xpath(xpath表达式)
name定位
- driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="搜索设置")
- driver.find_element_by_accessibility_id(content-desc属性值)
# 在android中有些控件没有text属性,对于一些用户来说,无法理解这个控件是做什么的。 # 开启TalkBackandroid后,系统会自动使用人声朗读控件上android:contentDescription属性说指向的内容
注意:当定位到多个符合条件的元素时,默认返回第一个
演练
根据要求完成下面代码步骤 需求:打开手机《设置》应用,完成下面的步骤 ①.使用ID定位,定位“放大镜”按钮,并点击 ②.使用CLASS定位,定位“输入框”,输入“hello” ③.使用XPATH定位,定位“返回”,并点击 ④.使用NAME定位,定位“放大镜”按钮,并点击 ⑤.等待3s,关闭app
from time import sleep from appium import webdriver # 定义字典变量 from appium.webdriver.common.appiumby import AppiumBy desired_caps = {} # 字典追加启动参数 desired_caps["platformName"] = "Android" desired_caps["platformVersion"] = "7.1.1" desired_caps["deviceName"] = "127.0.0.1:52001" desired_caps["appPackage"] = "com.android.settings" desired_caps["appActivity"] = ".Settings" # 设置中文 desired_caps["unicodeKeyboard"] = True desired_caps["resetKeyboard"] = True # 获取driver driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps) sleep(1) print("使用id点击放大镜...") # 使用id -> 点击放大镜 # resource-id属性值 driver.find_element(by=AppiumBy.ID, value="com.android.settings:id/search").click() sleep(1) print("使用class输入搜索hello...") # 使用class 输入hell # class属性值 driver.find_element(by=AppiumBy.CLASS_NAME, value="android.widget.EditText").send_keys("hello") sleep(2) print("使用xpath点击返回...") # 点击返回 xpath表达式 driver.find_element(by=AppiumBy.XPATH, value="//*[@class='android.widget.ImageButton']").click() sleep(1) print("使用name点击搜索按钮...") # 使用name定位 content-desc属性值 driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="搜索设置").click() sleep(3) driver.quit()
2. 定位一组元素
要获取搜索到的商品的商品名称,一个一个的定位然后再获取文本吗?
定位方式
- ID定位一组
- driver.find_elements(by=AppiumBy.ID, value=resource-id属性值)
- driver.find_elements_by_id(resource-id属性值)
- class定位一组
- driver.find_elements(by=AppiumBy.CLASS_NAME, value=class属性值)
- driver.find_elements_by_class_name(class属性值)
- xpath定位一组
- driver.find_elements(by=AppiumBy.XPATH, value=xpath表达式)
- driver.find_elements_by_xpath(xpath表达式)
- name定位一组
- driver.find_elements(by=AppiumBy.ACCESSIBILITY_ID, value="搜索设置")
- driver.find_elements_by_accessibility_id(content-desc属性值)
- ID定位一组
注意:使用定位一组元素时,返回的数据是列表
演练
根据要求完成下面代码步骤 需求:打开手机《设置》应用,完成下面的步骤: ①.使用ID定位,获取所有 resource-id 为 ”com.android.settings:id/title“ 的元素,并打印其文 字内容 ②.使用CLASS定位,获取所有class 为 ”android.widget.TextView“ 的元素,并打印其文 字内容 ③.使用XPATH定位,获取所有包含 ”设“ 的元素,并打印其文字内容 ④.等待3s,关闭app
from time import sleep from appium import webdriver # 定义字典变量 from appium.webdriver.common.appiumby import AppiumBy desired_caps = {} # 字典追加启动参数 desired_caps["platformName"] = "Android" desired_caps["platformVersion"] = "7.1.1" desired_caps["deviceName"] = "127.0.0.1:52001" desired_caps["appPackage"] = "com.android.settings" desired_caps["appActivity"] = ".Settings" # 设置中文 desired_caps["unicodeKeyboard"] = True desired_caps["resetKeyboard"] = True # 获取driver driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps) sleep(1) # 1、获取所有id为:android:id/title els = driver.find_elements(by=AppiumBy.ID, value="android:id/title") for el in els: print("元素id为com.android.settings:id/title的为本内容有:", el.text) els = driver.find_elements(by=AppiumBy.CLASS_NAME, value="android.widget.TextView") for el in els: print("元素class为android.widget.TextView的为本内容有:", el.text) els = driver.find_elements(by=AppiumBy.XPATH, value="//*[contains(@text,'设')]") for el in els: print("文本包含'设'内容有:", el.text) sleep(3) driver.quit()
2. 元素操作
1. 模拟操作-点击、输入、清空
- 模拟点击
- element.click()
- 模拟输入
- element.send_keys(value)
- 模拟清空输入框内容
- element.clear()
- 注意
- 默认输入中文无效,但不会报错,需要在 ”前置代码“ 中增加两个参数:
- desired_caps["unicodeKeyboard"] = True
- desired_caps["resetKeyboard"] = True
- 默认输入中文无效,但不会报错,需要在 ”前置代码“ 中增加两个参数:
from time import sleep
from appium import webdriver
# 定义字典变量
from appium.webdriver.common.appiumby import AppiumBy
desired_caps = {}
# 字典追加启动参数
desired_caps["platformName"] = "Android"
desired_caps["platformVersion"] = "7.1.1"
desired_caps["deviceName"] = "127.0.0.1:52001"
desired_caps["appPackage"] = "com.android.settings"
desired_caps["appActivity"] = ".Settings"
# 设置支持中文输入
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
# 获取driver
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
sleep(1)
# 1、点击: 放大镜
driver.find_element(AppiumBy.XPATH, "//*[@resource-id='com.android.settings:id/search']").click()
# 2、输入: hello
el = driver.find_element(AppiumBy.XPATH, "//*[@resource-id='android:id/search_src_text']")
el.send_keys("hello")
# 3、2s 清空内容
sleep(2)
el.clear()
# 4、5s 输入你好
sleep(2)
el.send_keys("你好")
sleep(3)
driver.quit()
2. 获取元素信息
- 测试搜索商品结果的显示商品名称是否正确就需要获取文本
操作新闻顶部滑动时需要按住坐标进行滑动, 就需要根据获取频道区域 元素位置和大小来计算出滑动坐标!
获取文本
- element.text
获取位置
- element.location
获取大小
- element.size
演练
根据要求完成下面代码步骤 需求:打开手机《网易新闻》应用,完成下面的步骤: ①.获取第一条新闻标题信息并打印 ②.计算出模拟手指按住区域频道的起始和结束坐标点:
from time import sleep from appium import webdriver # 定义字典变量 from appium.webdriver.common.appiumby import AppiumBy desired_caps = {} # 字典追加启动参数 desired_caps["platformName"] = "Android" desired_caps["platformVersion"] = "7.1.2" desired_caps["deviceName"] = "127.0.0.1:52001" desired_caps["appPackage"] = "com.android.settings" desired_caps["appActivity"] = ".Settings" # 设置中文 desired_caps["unicodeKeyboard"] = True desired_caps["resetKeyboard"] = True # 获取driver driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps) sleep(1) driver.implicitly_wait(10) # 点击放大镜 driver.find_element(AppiumBy.ID, "com.android.settings:id/search").click() # 获取 菜单我的文本 text = driver.find_element(AppiumBy.XPATH, "//*[@resource-id='android:id/search_src_text']").text print("我的菜单,文本值为:", text) location = driver.find_element(AppiumBy.XPATH, "//*[@resource-id='android:id/search_src_text']").location print("位置:", location) size = driver.find_element(AppiumBy.XPATH, "//*[@resource-id='android:id/search_src_text']").size print("大小为:", size) x = location.get("x") + (size.get("width") / 2) y = location.get("y") + (size.get("height") / 2) print("触摸中心位置x:{} y:{}".format(x, y)) sleep(3) driver.quit()
3. 获取属性值信息
测试商品显示金额是否正确就需要获取属性值
获取属性值
element.get_attribute(属性名)
注意:获取属性值对应的属性名和实际 UIAutoMatorViewer 显式的不一定一致**(为了兼容android和iOS)**!!!!
- 获取resource-id > resourceId
- 获取content-desc > name
- 获取class > className
- 获取text > text
演练
根据要求完成下面代码步骤 需求:打开手机《设置》应用,完成下面的步骤: ①.获取所有 resource-id 为 ”com.android.settings:id/title“ 的元素 ②.使用 get_attribute 获取这些元素的 enabled、text、content-desc、resource-id、class的属性值
from time import sleep from appium import webdriver # 定义字典变量 from appium.webdriver.common.appiumby import AppiumBy desired_caps = {} # 字典追加启动参数 desired_caps["platformName"] = "Android" desired_caps["platformVersion"] = "7.1.2" desired_caps["deviceName"] = "127.0.0.1:52001" desired_caps["appPackage"] = "com.android.settings" desired_caps["appActivity"] = ".Settings" # 设置中文 desired_caps["unicodeKeyboard"] = True desired_caps["resetKeyboard"] = True # 获取driver driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps) sleep(1) driver.implicitly_wait(10) # 点击放大镜 els = driver.find_elements(AppiumBy.ID, "com.android.settings:id/dashboard_tile") for el in els: print("--" * 50) print("1、enabled属性值为:", el.get_attribute("enabled")) print("2、text属性值为:", el.get_attribute("text")) print("3、content-desc属性值为:", el.get_attribute("name")) print("4、resource-id属性值为:", el.get_attribute("resourceId")) print("5、class属性值为:", el.get_attribute("className")) print("--" * 50) sleep(3) driver.quit()
3. 滑动和拖拽
再做测试的时候,有些按钮是需要滑动几次屏幕后才能出现,此时我们需要使用代码来模拟手指的滑动
1. Swipe滑动
Swipe滑动:从一个坐标位置滑动到另一个坐标位置,只能是两个点之间的滑动
方法
- driver.swipe(start_x, start_y, end_x, end_y, duration=None)
- start_x: 起点X轴坐标
- start_y: 起点Y轴坐标
- end_x: 终点X轴坐标
- end_y: 终点Y轴坐标
- duration: 滑动这个操作一共持续的时间长度,单位:ms
- driver.swipe(start_x, start_y, end_x, end_y, duration=None)
如果起始坐标和结束坐标写死了,更换不同分辨率的手机后,是不是可滑动不了呢?
- 起始坐标和结束坐标通过获取滑动区域元素位置和大小来动态计算
注意:swipe适合多次滑动,duration时间越长惯性越大
演练
练习一:打开手机《设置》应用,完成下面的步骤: ①.模拟手指从(100, 2000),滑动到(100, 1000)的位置。
from time import sleep from appium import webdriver # 定义字典变量 desired_caps = {} # 字典追加启动参数 desired_caps["platformName"] = "Android" desired_caps["platformVersion"] = "7.1.2" desired_caps["deviceName"] = "127.0.0.1:52001" desired_caps["appPackage"] = "com.android.settings" desired_caps["appActivity"] = ".Settings" # 设置支持中文输入, 不设置输入中文没反应 desired_caps["unicodeKeyboard"] = True desired_caps["resetKeyboard"] = True # 获取driver driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps) sleep(1) # driver.implicitly_wait(10) """ 需求:从屏幕100,1000位置滑动到100,400位置 start_x: 起点X轴坐标 start_y: 起点Y轴坐标 end_x: 终点X轴坐标 end_y: 终点Y轴坐标 duration: 滑动这个操作一共持续的时间长度,单位:ms """ # 练习1 driver.swipe(start_x=100, start_y=1000, end_x=100, end_y=400, duration=1000) sleep(3) driver.swipe(start_x=200, start_y=1000, end_x=200, end_y=400, duration=3000)
练习二:打开手机《网易新闻》应用,完成下面的步骤: ①.模拟手机滑动频道,找到‘健康’频道,并点击
拓展: 获取应用包名
1. 使用adb 命令的弊端: 获取当前启动页面信息。 如果安卓应用不允许被三方调用,这此方法行不通 adb shell dumpsys window | findstr mCurrentFocus mCurrentFocus=Window{6c6b0eb u0 com.netease.newsreader.activity/com.netease.nr.phone.main.MainActivity} 2. 通过AAPT工具查看 - 位置:android-sdk目录\build-tools\版本\ - 命令: aapt dump badging xxxx.apk文件目录 - 关注: package: name= launchable-activity: name=
from time import sleep from appium import webdriver # 定义字典变量 from appium.webdriver.common.appiumby import AppiumBy desired_caps = {} # 字典追加启动参数 com.netease.newsreader.activity/com.netease.nr.phone.main.MainActivity desired_caps["platformName"] = "Android" desired_caps["platformVersion"] = "7.1.2" desired_caps["deviceName"] = "127.0.0.1:52001" desired_caps["appPackage"] = "com.netease.newsreader.activity" desired_caps["appActivity"] = "com.netease.nr.phone.main.MainActivity" # 设置中文 desired_caps["unicodeKeyboard"] = True desired_caps["resetKeyboard"] = True # 获取driver driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps) sleep(1) driver.implicitly_wait(10) """ 需求:从屏幕100,1000位置滑动到100,400位置 """ sleep(2) # 200,220 920,220 # driver.find_element(AppiumBy.XPATH, "//*[@text='同意并继续']").click() driver.find_element(AppiumBy.ID, 'com.netease.newsreader.activity:id/bkj').click() sleep(2) driver.find_element(AppiumBy.ID, 'com.android.packageinstaller:id/permission_allow_button').click() sleep(2) driver.find_element(AppiumBy.ID, 'com.android.packageinstaller:id/permission_allow_button').click() sleep(2) driver.find_element(AppiumBy.ID, 'com.android.packageinstaller:id/permission_allow_button').click() sleep(2) i = 0 # start_x: 起点X轴坐标 start_y: 起点Y轴坐标 end_x: 终点X轴坐标 end_y: 终点Y轴坐标 # duration: 滑动这个操作一共持续的时间长度,单位:ms while i <= 5: # 位置通过uiautomatorviewer查看 driver.swipe(628, 114, 200, 135) i += 1 driver.find_element(AppiumBy.XPATH, "//*[@text='健康']").click() sleep(3) driver.quit()
2. Scroll滑动
Scroll滑动:从一个元素滑动到另一个元素,直到页面自动停止
方法
- driver.scroll(origin_el, destination_el)
- origin_el:滑动开始的元素
- destination_el: 滑动结束的元素
- driver.scroll(origin_el, destination_el)
注意
- scroll滑动是两个元素之间的滑动只适合滑动一次的操作
- 惯性很大
swipe: 特点:精准滑动,基于两个坐标点滑动
scroll:特点:滚动有惯性存在,滚动时不按下第一个元素,针对两个元素进行操作
drag_and_drop: 拖拽,没惯性,按下开始元素拖拽到指定元素元素的位置,针对两个元素进行精准操作 【推荐】模拟器有差别,建议使用Genymotion Android 模拟器或真机进行调试
3. drag_and_drop拖拽
drag_and_drop:从一个元素滑动到另一个元素,第二个元素替代第一个元素原本屏幕上的位置
方法
- driver.drag_and_drop(origin_el, destination_el)
- origin_el:滑动开始的元素
- destination_el: 滑动结束的元素
- driver.drag_and_drop(origin_el, destination_el)
注意:
- scroll滑动是两个元素之间的滑动只适合滑动一次的操作
- 无惯性
import time
from appium import webdriver
# 定义字典变量
from appium.webdriver.common.appiumby import AppiumBy
desired_caps = {}
# 字典追加启动参数
desired_caps["platformName"] = "Android"
desired_caps["platformVersion"] = "7.1.1"
# desired_caps["deviceName"] = "127.0.0.1:52001"
desired_caps["deviceName"] = "emulator-5554"
desired_caps["appPackage"] = "com.android.settings"
desired_caps["appActivity"] = ".Settings"
# 设置支持中文输入, 不设置输入中文没反应
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
# 获取driver
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
# sleep(1)
# driver.implicitly_wait(10)
"""
需求:
1、从显示滑动到蓝牙
2、从显示拖拽到蓝牙
"""
# exe = driver.find_element_by_xpath("//*[@text='显示']")
show = driver.find_element(AppiumBy.XPATH, "//*[@text='更多']")
blooth = driver.find_element(AppiumBy.XPATH, "//*[@text='蓝牙']")
# 1、滚动 从一个元素滑动到另一个元素,直到页面自动停止
# scroll滑动是两个元素之间的滑动只适合滑动一次的操作
# 惯性很大, 如果duration设置为0相当于点击,duration参数,参数值越大,惯性越小
# driver.scroll(origin_el=show, destination_el=blooth, duration=0)
# driver.scroll(origin_el=show, destination_el=blooth, duration=100)
# driver.scroll(origin_el=show, destination_el=blooth, duration=2000)
# 2、拖拽
driver.drag_and_drop(show, blooth)
time.sleep(3)
# driver.quit()
# swipe: 特点:精准滑动,基于两个坐标点滑动
# scroll: 特点:滚动有惯性存在,滚动时不按下第一个元素,针对两个元素进行操作
# drag_and_drop:拖拽,没惯性,按下开始元素拖拽到指定元素元素的位置,针对两个元素进行精准操作 【推荐】
4. 小节
下边这些场景应用选择哪个滑动方式?
- 验证‘网易新闻’页面向下滑动是否能触发新的新闻的加载?
- scroll滑动或者swipe滑动
- 验证‘淘宝’查询商品结果中有没有预期商品名的商品?
- swipe滑动
- 验证‘网易新闻’显示新闻页面底部,新闻显示信息是否完整?
- drag_and_drop拖拽