配置环境
1、安装client编程库:
自动化程序需要调用客户端库和 Appium Server 进行通信。
pip install appium-python-client
2、安装Appium Server:
appium下载地址:https://github.com/appium/appium-desktop
Appium Server 是用 nodejs 运行的,基于js开发出来的。Appium组织为了方便大家安装使用,制作了一个可执行程序 Appium Desktop,把 nodejs 运行环境、Appium Server 和一些工具打包在里面了,只需要简单的下载安装就可以了。
3、安装JDK:
官方下载比较麻烦,所以我这里提供一个链接:http://www.sousou88.com/spec/oraclejdk.html 搜索jdk8,下载win x64版本
安装好之后,还需要添加一个系统环境变量 JAVA_HOME ,值为jdk安装目录。
JAVA_HOME C:\Program Files\Java\jdk1.8.0_281
4、安装 Android SDK:
通过Android Studio来安装Android SDK,好比我们使用anaconda来安装Python一样,效率更高,更安全。https://developer.android.com/studio
对于安卓APP的自动化,Appium Server 是需要 Android SDK的。因为要用到里面的一些工具,比如 要执行命令设置手机、传送文件、安装应用、查看手机界面等。
安装后启动,会出现安装sdk的页面,进行安装即可(1.75G,可能需要点时间)。
安装完成!
安装完成之后,我们还需要给它添加系统环境变量 ANDROID_HOME ,值为sdk的目录。
ANDROID_HOME C:\Users\Administrator\AppData\Local\Android\Sdk
如果还是没找到可以试用everything,搜索 Android\Sdk 第一个就是你的目录了。(AppData目录一般是隐藏文件)
另外还需要添加 环境变量 PATH ,加入adb.exe 所在目录(platform-tools文件夹所在目录)
C:\Users\Administrator\AppData\Local\Android\Sdk\platform-tools
我这里的路径是 C:\Users\Administrator\AppData\Local\Android\Sdk\platform-tools
记得保存,并确定。之后,我们打开命令行窗口,输入 adb,看下是否添加成功。
显示这样,就说明添加成功。
5、连接手机
我们有两种方式,一种是使用安卓模拟器,一种是使用真机;
方式一、模拟器连接
设置模拟器:
打开模拟器,本人用的是夜神模拟器,设置如下(图文教程):
- 1)设置 - 关于平板电脑 - 版本号(不是Android版本)- 连续点击五次开启开发者模式;
- 2)返回后在设置里找到 开发者选项 - 打开 USB调试
- 3)把nox_adb程序添加到系统环境变量里
- 4} 确定
nox_adb D:\Program Files\Nox\bin
进入cmd后,输入adb devices,会显示如图,并且守护进程成功启动的说明。
注意:模拟器处于启动状态!
此时,我们进入模拟器目录(D:\Program Files\Nox\bin),在地址栏里输入 cmd,就可以直接打开小黑框并进入该路径。然后输入 nox_adb.exe connect 127.0.0.1:62001 进行连接。windows进入当前目录的终端的方法: 1、在此文件夹窗口内空白区域右键单击(需要同时按住Shift),从菜单中选择"在此处打开命令行窗口"的项; 2、在当前目录的地址栏里直接输入cmd,回车即可。
不同模拟器的链接方式: 夜神模拟器:adb connect 127.0.0.1:62001 逍遥安卓模拟器:adb connect 127.001:21503 天天模拟器:adb connect 127.0.0.1:6555 海马玩模拟器:adb connect 127.0.0.1:53001 网易MUMU模拟器:adb connect 127.0.0.1:7555
注意:powershell和命令提示符的用法不一样(多个引号),具体看下面两张图
先进盘符;接着cd进入目录;之后链接。
再次输入adb devices,如下图所示就表示成功连接了~(这里是我们之前添加了platform-tools目录到环境变量,如果没有加,需要cd进入目录后在执行)里面多的一行 emulator-5554 device 是我另外一个雷电模拟器,请忽视。
设置appium:
最后,我们打开 appium客户端,点击 Start Server ,点击搜索按钮
在 Desired Capabilities 中输入对应参数,之后点击 Start Session 即可(保持模拟器打开状态),其中 appPackage 和 appActivity 获取方式在下面
也可以使用右侧的JSON格式写入,我的参数如下:
{
"platformName": "Android",
"platformVersion": "7.1",
"deviceName": "xxx",
"appPackage": "com.taobao.idlefish",
"appActivity": "com.taobao.fleamarket.home.activity.MainActivity",
"unicodeKeyboard": true,
"resetKeyboard": true,
"noReset": true,
"newCommandTimeout": 6000,
"automationName": "UiAutomator2"
}
当你看下面的页面,就说明配置成功了 🎉 !
方式二、真机连接:
上述的软件环境都准备好以后,要自动化手机APP,需要:
- 在你运行程序的电脑上 用USB线 连接上你的安卓手机;
- 进入 手机设置 -> 关于手机 ,不断点击 版本号 菜单(7次以上);
- 退出到上级菜单,在开发者模式中,启动USB调试;
如果手机连接USB线后,手机界面弹出 类似 如下提示。
选择 允许USB调试。
连接好以后,打开命令行窗口, 执行 adb devices -l 命令来列出连接在电脑上的安卓设备。
如果输出类似如下的内容:
表示电脑上可以查看到 连接的设备,就可以运行自动化程序了。
有时候会报错 adb server version (31) doesn’t match this client (41); killing… 点击这里解决
上面的链接模拟器的时候,我们使用了 appium来启动app,不过我们通常使用的是Python进行操作。下面我们来个实例看下
appPackage和appActivity 获取方式:
首先确保你已经在模拟器打开并显示该APP,使用 terminal依次输入:(如图)
#方式一:
adb shell
dumpsys activity | grep mFocusedActivity
当然有时候后面的appActivity是点开头的
#方式二:
adb shell dumpsys activity activities
其中方式二显示的是当前所有在运行的任务栈,并可查看栈中所有的 Activity 的列表;我们找到 mFocusedActivity 表示当前运行的app程序。
结果: appPackage:com.taobao.idlefish appActivity:com.taobao.fleamarket.home.activity.MainActivity
定位元素
连接完成之后,我们就要去找元素,并对元素进行操作。,首先说下我们定位元素用到的工具:
使用的工具:
常用的查看工具是: Appium Desktop 中的 Appium Inspector 和 Android Sdk包中的 uiautomateviewer ;同时两种工具分别对应两种定位元素的方式(一一对应搭配使用)。
注意:两个软件不可以同时打开,否则会报错。
Appium Inspector(常用)
这是 appium 自带的元素查找器,有selenium基础的用这个上手快,不过没有下面的那个好用(有时候会遇到找不到元素),不过它有自己的优势,就是支持搜索验证(类似于F12之后,我们使用ctrl+f来验证元素是否唯一)
注意:有个问题,就是只要运行py后,再来寻找元素,就需要重启。
uiautomateviewer(高效)
使用everything 搜索 \Android\Sdk\tools\bin ,在bin目录下就可以找到 ,双击打开 uiautomateviewer.bat,页面如下图:
定位元素:
Selenium Web(常用)
# id # resource-id 属性 斜杠前面的是包名,可以省略
driver.find_element_by_id('search_bar_layout')
# class_name 类似web里面的tagname,一般为多个,所以用了elements
driver.find_elements_by_class_name('android.widget.RelativeLayout')
# accessibility_id # content-desc (描述)属性
driver.find_element_by_accessibility_id('衬衫')
# xpath 没有selenium里的可靠,经常变,不建议使用
driver.find_element_by_xpath('//ele1/ele2[@attr="value"]') #
上面的方法实际上的步骤是程序发送请求 - Appium server转化为代理程序 - 让uiautomator调用安卓的相应函数,其实我们可以跳过appium,直接使用uiautomator里的方法。下面我们看看如何使用,下面给出几个例子,更多的方法可以参考官方文档。
UI Automator API(高效)
官方文档:https://developer.android.google.cn/training/testing/ui-automator
主要有三大模块,查看器就是我们前面使用的查找元素的工具uiautomateviewer;设备状态是设备相关的,比如音量、返回菜单、通知栏等;我们重点查看 UI Automator API 里面的 UiSelector,即选择元素的方式(当然,这里是java语法)。
点进去就可以看到所有选取元素的方法汇总表,这里拿几个常见的举例:
code = 'new UiSelector().text("热门").className("android.widget.TextView")'
driver.find_element_by_android_uiautomator(code).click()
多种限制条件用点进行连接,比如上面我们用的text和classname。
除了根据文本text,还有
- textContains 根据文本包含什么字符串
- textStartsWith 根据文本以什么字符串开头
- textmartch 使用正则表达式 选择一些元素
- instance 是匹配的结果所有元素里面 的第几个元素
- index 则是其父元素的几个节点,类似xpath 里面的*[n]
- childSelector 可以选择后代元素
操作元素:
click、tap、send_keys、swipe、press_keycode
最常见的操作之一,使用 WebElement 对象的 click 方法, 示例代码就讲过,不再赘述。
WebElement 对象的 tap 方法和 click 类似,都是点击界面。但是最大的区别是, tap是 针对坐标(bounds的值) 而不是针对找到的元素。
它有两个参数,第一个是点击的坐标,类型是列表,最多可以有5个元素,代表5根手指点击5个坐标。第二个参数 表示tap点按屏幕后停留的时间。如果点按时间过长,就变成了长按操作了。
# 如果想点击中间区域,我们计算一下就可以了 (637-27)/2,(162-108)/2 就得到选择区域中间坐标
driver.tap([(306.5,27)],300) # 300代表停留时长,表示长按
swipe:前面4个参数是滑动起点和终点的x、y坐标。第5个参数duration是滑动从起点到终点坐标所耗费的时间。
driver.swipe(start_x=x, start_y=y1, end_x=x, end_y=y2, duration=800)
press_keycode:模拟按键动作,这里一般使用数字,如果不清楚数字代表什么,点我
from appium.webdriver.extensions.android.nativekey import AndroidKey #导入包
driver.press_keycode(66) # 输入回车键(66代表回车),确定搜索
Appium的 TouchAction 类提供了更多的手机操作方法,比如:长按、双击、移动等,更多资料,点我
from appium.webdriver.common.touch_action import TouchAction
# 下面就是一个长按的例子
actions = TouchAction(driver) # 初始化
actions.long_press(element) # 使用的方法
actions.perform() # 结尾必须加
driver.open_notifications() 打开通知栏,关闭的方式可以试用滑动,也可以使用返回按键。
adb命令:
官方文档:https://developer.android.google.cn/studio/command-line/adb#move
adb 全程 Android Debug Bridge,这个adb 使用非常广泛。它可以与 Android 手机设备进行通信,它可进行各种设备操作。
比如: 安装应用和调试应用,传输文件,甚至登录到手机设备上shell的进行访问,就像远程登录一样。这个adb 在 sdk的 platform-tools 目录下面, 请大家确保路径在path环境变量中。
Appium 对anroid的自动化就非常依赖这个adb工具。 执行自动化过程中,有很多内部操作,比如获取设备信息,传送文件到手机,安装apk,启动某些程序等,都是通常这个adb实现的。
adb devices -l # 查看链接的设备
adb shell ls /sdcard # 查看目录
adb push wv.apk /sdcard/wv.apk # 上传
adb pull /sdcard/new.txt # 下载
adb shell screencap /sdcard/screen.png # 截屏 截屏后可以使用adb pull下载下来
既然这是个命令,就可以使用 Python的 os.system() 或者 subprocess 来自动化调用它,完成我们的各种自动化需求。
比如,我们自动化过程中,可能需要截屏手机,并且下载到指定目录中,就可以在我们的Python程序中这样写
import os
os.system('adb shell screencap /sdcard/screen3.png && adb pull /sdcard/screen3.png')
更多adb命令,点我
Python 运行示例
首先要打开appium,点击 Start Server ,等待自动化程序给它发出指令(py脚本通过appium来控制模拟器)。
然后运行py文件,appium会自动在模拟器里安装一个程序 Appium Setting用来和模拟器连接,安装后会继续运行脚本,打开app程序,进行脚本里的程序。
闲鱼加了反爬,有些元素找不到,所以我用酷安APP来做实例演示
提示:元素找完了之后再运行py,因为py运行后就会导致报错,这时候就需要重启uiautomatorviewer。
酷安搜索
from appium import webdriver
from appium.webdriver.extensions.android.nativekey import AndroidKey
import time
desired_caps = {
'platformName': 'Android', # 被测手机是安卓
'platformVersion': '7.1.2', # 手机安卓版本
'deviceName': 'xxx', # 设备名,安卓手机可以随意填写
'automationName': 'Appium', # 指定引擎 UiAutomator2,默认 Appium
# 'app': r'D:\\OneDrive/software/apk/Cool.apk' # apk本地文件路径
'appPackage': 'com.coolapk.market', # 启动APP Package名称
'appActivity': '.view.main.MainActivity', # 启动Activity名称
'unicodeKeyboard': True, # 使用unicode输入法,需要输入中文时填True
'resetKeyboard': True, # 执行完程序恢复原来输入法
'noReset': True, # 不要重置App
'newCommandTimeout': 6000,
}
# 连接Appium Server,初始化driver 4723来自于appium的端口
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
time.sleep(3)
driver.tap([(189, 72)]) # 点击搜索框
time.sleep(1)
# Appium ----------------------------------------
driver.find_element_by_class_name(
"android.widget.EditText").send_keys("微信") # 定位并输入搜索内容
# UiAutomator2 -----------------------------------
code = 'new UiSelector().resourceId("com.coolapk.market:id/search_text")' # 定位元素
driver.find_element_by_android_uiautomator(code).send_keys('微信') # 操作元素
刷抖音(swipe)
from appium import webdriver
from appium.webdriver.extensions.android.nativekey import AndroidKey
import time
desired_caps = {
'platformName': 'Android', # 被测手机是安卓
'platformVersion': '7.1.2', # 手机安卓版本
'deviceName': 'xxx', # 设备名,安卓手机可以随意填写
'automationName': 'Appium', # 指定引擎 UiAutomator2,默认 Appium
# 'app': r'D:\\OneDrive/software/apk/Cool.apk' # apk本地文件路径
'appPackage': 'com.ss.android.ugc.aweme', # 启动APP Package名称
'appActivity': '.splash.SplashActivity', # 启动Activity名称
'unicodeKeyboard': True, # 使用unicode输入法,需要输入中文时填True
'resetKeyboard': True, # 执行完程序恢复原来输入法
'noReset': True, # 不要重置App
'newCommandTimeout': 6000,
}
# 连接Appium Server,初始化driver 4723来自于appium的端口
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
driver.implicitly_wait(5) # 隐式等待5秒
class Mobile_Action:
# 1、向上滑动
def swipe_up(self):
size = driver.get_window_size() # 获取手机分辨率
width = size['width'] # 屏幕的宽
height = size['height'] # 屏幕的高
x1 = width/2 # 滑动开始的x轴中心坐标
y1 = height/10*6 # 滑动起始的y轴坐标
y2 = height/10 # 向上滑动的y轴终点坐标
driver.swipe(x1, y1, x1, y2, 400) # 4秒的滑动时间
time.sleep(3) # 每个视频看3秒
if __name__ == "__main__":
douyin = Mobile_Action()
time.sleep(6) # 开屏广告时间
for i in range(5):
douyin.swipe_up()
难点主要在于元素的定位,有些元素是动态的,所以就要想其他方法去找。
常见报错:
Error obtaining Ul hierarchy
Reason: Error while obtaining UI hierarchy XML file com. android. ddmlib SyncException: Remote object doesn t exist
问题解决办法:
如果是真机,直接插拔USB,然后重新连接,一般都会好
如果是模拟器,在命令窗口中将adb kill掉,输入:adb kill-server,然后重新运行uiautomatorviewer