Appium自动化操作手机端软件-Damai-Ticket-Grab-Tutorial-2024
一、缘起
有很多朋友来找我弄演唱会的票,于是来看看。
大麦网站不允许在Web端进行购买,这意味着之前的那种Selenium的方式应该是无法操作了。
在Github上找到了一个项目,是支持小程序抢票的,这是一个新的领域,我们开始学习学习。
大麦App抢票:大麦App抢票
Appium手机自动化的原理:Appium原理与安装
二、先说说环境
看了App部分的Readme,依赖的软件有Node环境,Npm,Android Sdk,Appium,UiAutomator2驱动。
为了做到稍微的知其然知其所以然,我还是想先看看这些东西的作用,而不是无脑的安装。
因为今天在打Pikachu靶场的时候遇到了目录遍历,需要用Dirbuster这个工具,想起来之前写的一篇非常详细的工具说明,看完那叫一个清晰明朗,给了我用心做技术博客一些鼓励。

1、Node环境
摘自node.js官网的解释。
# Run JavaScript Everywhere
Node.js® is a free, open-source, cross-platform JavaScript runtime environment that lets developers create servers, web apps, command line tools and scripts.
Node.js®是一个免费、开源、跨平台的JavaScript运行时环境,允许开发人员创建服务器、web应用程序、命令行工具和脚本。
这里有一些名词,我们暂时不对免费,开源,跨平台这些简单名词进行解释。
好吧还是解释一下,免费就是不要钱,开源就是开放源代码,就像大家分享在Github上的抢票脚本,你是可以看到脚本的运行逻辑的,源码可下载可修改。还有一些软件是闭源的,会把代码实现的逻辑隐藏起来。
参考这个网站的一段解释来说明什么是开源:开源指南
“开源”是什么意思?
当一个项目被开源,这意味着任何人都可以出于任何目的查看,使用,修改和分发你的项目。 这些权限通过开源许可强制实施。
开源是强大的,因为它降低了事物被采纳的障碍,使得我们的想法可以被迅速传播。
接下来我们通过一个例子了解它的工作原理。想象你的朋友组织了一场聚餐,而你带去了一个樱桃派。
每个人都尝了那个派(使用)
派的味道棒极了!大家请你分享它的配方(view)
一个叫 Alex 的朋友是个糕点师,他建议少放点糖(modify)
一个叫 Lisa 的朋友想要用它作为下周的晚餐(distribute)
相比之下,一个闭源过程就像去一家餐厅订购一个樱桃派。你必须为了吃饼支付费用,餐厅恐怕不会给你他们的食谱。如果你准确地复制了他们的馅饼,并以你自己的名义出售,餐厅可以对你采取措施。
跨平台指的是它可以在不同系统(Windows,Linux,MacOs)不同架构(x86,x64)上运行。而不用为每个平台都编写一个不同的代码。
Javascript是一门编程语言,多用于前端,和html,css并称前端三剑客,而node.js就是来运行Javascript的一个环境。当然,Javascript还可以运行在浏览器端,当我们用F12打开开发者工具时就能够在浏览器的控制台运行Javascript。
那为什么需要一个Node呢?Node是用来在服务器端运行Javascript的,这样开发者可以不用学习常规的Php或Jsp,同样可以编写后端(服务端)的代码,而是只需要在服务器上安装Node.js环境即可,这对于我们来说是方便的。如果世界上有一种语言又快又好,那么大家都不用学Java,Python或者其他乱起八糟的了,可是事实却不是这样...
关于Node的介绍:Node
在ReadMe中要求Node的版本是18.0.0,这里只在官网找到18.20.4的版本。
Node18.20.4:预编译安装包下载页
那么Node.js包含了Npm,Npm又是什么鬼?
2、Npm包管理?
Npm 是 Node.js 的标准包管理器。
Npm简介:Npm包管理
什么是包,什么又是包管理?
假设我要做一个蛋糕,我需要去沃尔玛里面买相关的食材,比如牛奶,鸡蛋,面粉等等。
我当然可以自己养一头牛自己生产牛奶,自己再养一只鸡自己弄鸡蛋。但是没必要,超市里已经有,我直接拿来用不就很好吗?
假设我现在要开发一个抢票软件,需要识别图片验证码登录,我当然也可以自己写,但是在世界的某个角落,肯定有人已经写好了这个功能,那么他就会将这些代码打包(假设他打包之后命名为pic_read)上传到相关的包管理器的仓库中,我只需要去仓库里下载他写好的这个包,就可以使用图片验证码的这个功能了。
所以,对于我的抢票软件来说,pic_read就是我这个程序的依赖软件,想要运行我的程序,就必须要下载这个依赖才行。
关于Linux的包管理:什么是包管理器?
什么是Pip和Npm包管理器:Npm和Pip
在Node.Js中已经集成了Npm包管理,因为我们的抢票脚本很可能也需要利用网上面别人写好的代码包,所以Npm就能够为我们提供一个很好的下载平台。
顺便提一句,Npm的性质类似于Python的Pip,这一点在上面分享的文章中也有讲述。
在这里我们使用Npm包是为了安装一个名为Appium的东西,这又是啥?
3、Appiuim
我就喜欢这种把官网做的赏心悦目的工程组,是我们学习的好榜样啊。
Appiuim官方网站:Appium
从官网简短的描述中我们可以知道,Appium是一个实现Ui自动化的生态系统,那么同学又要问了,什么是Ui自动化?
欢迎来到 Appium 文档!Appium 是一个开源项目和相关软件的生态系统,旨在促进许多应用程序平台的 UI 自动化,包括移动(iOS、Android、Tizen)、浏览器(Chrome、Firefox、Safari)、桌面(macOS、Windows)、电视(Roku、tvOS、Android TV、三星)等!
正如主页上提到的,Appium 旨在支持许多不同平台(移动、Web、桌面等)的 UI 自动化。不仅如此,它还旨在支持以不同语言(JS、Java、Python 等)编写的自动化代码。将所有这些功能组合到一个程序中是一项非常艰巨的任务,如果不是不可能的话!
Ui也就是(User Interface),可以简单理解为我们的图形化界面这些东西,我们使用的Windows系统,浏览器,App都是Ui的产物。
与之对应的是命令行界面,就是我们可以通过敲代码来完成日常的所有操作,在Linux系统上用的比较多。
Ui的好处就是所见即所得,用户不需要学习复杂的代码操作,就可以为新建一个文档,为其重命名。但是它的缺点就是无法直接编写代码操作这些Ui软件,于是就出现了Ui自动化,它能够以代码的形式定位Ui元素,实现自动化操作。就像我们的抢票脚本一样。
在Web也就是浏览器端,我使用Selenium+Js来进行Ui自动化(看官网简介好像Appium也可以用来进行Web的Ui自动化),它可以通过判断页面的Dom元素来完成按钮点击,文字输入这些操作。
但是在手机上的App端,就需要用到Appium这样的生态系统了。
什么是Ui自动化:Ui自动化简介
Appium是如何工作的,在简单理解了其官网文章之后,给出一点看法。
appium是一个运行在node.js上的服务器,它本身不提供自动化操作android手机或者ios手机的功能。
它通过安装对应的驱动程序来实现对应平台上的ui自动化,比如想在ios上做自动化,安装XCUITest,想在android手机上实现自动化,安装UiAutomator2
于是,一个运行在Node.js环境下,并且带有UiAutomator2驱动的Appium服务就启动起来了,它应该是一个http服务,之类的,这个服务器需要连接到你想要执行自动化操作的设备上,所有的自动化操作都由这个服务器来执行。
正如它提到的,它支持用不同语言(JS、Java、Python 等)编写自动化代码,对于我这种只会Python的人来说简直太好了,于是我们下载Appium的客户端,在上面用Python(或者任何你会的语言)编写好自动化程序的执行脚本,然后将指令发送给服务器,服务器在你想执行自动化操作的设备上执行之后,将结果再返回给客户端。
理解了Appium的工作原理,我们再来看看Android sdk,这是什么东西,我猜测是因为我们需要在Android设备上执行自动化操作,所以需要安装这个东东。
关于Appium的详细介绍:Appium的详细介绍
4、Android Sdk
简单说就是Android Software Development Kit,安卓软件开发套件。
其中的Adb,Android Debugging Bridge调试桥接套件,可以让我们在Pc端控制安卓手机,记得之前在小程序抓包的时候也有用到过这个,反正用电脑自动化操作手机大概都要下载Sdk。
由于Android是基于Java开发的,所以使用Sdk需要先安装Java的Jdk(Java Development Kit)。
关于什么是Android Sdk:Android Sdk
5、UiAutomator2
最后再来说说这个在Android手机上实现自动化的框架。
关于什么是Ui Automator2,摘抄自网络,侵删。
UI Automator 是 Google 提供的测试框架,允许您自动与 Android 应用程序的用户界面进行交互。它对于测试涉及多个应用之间交互的方案特别有用。在我们的例子中,我们将使用它来测试两个 Android 应用程序之间的交互。
其实我们可以直接使用UiAutomator来进行安卓手机的自动化操作,但遗憾的是UiAutomator2只支持Java语言,所以我们使用Appium+Uiautomator2的方式来用Python语言运行自动化代码。
在查询过程中还发现有大神使用Python来驱动UiAutomator2的:深度探索 Uiautomator2(ATX)原理(附含源码解析)
关于Appium和UiAutomator之间的关系:自动化测试框架对比(UIAutomator、Appium)
6、安装环境
铺垫的知识学的差不多了,来安装把。
(一)、Node.Js
Node.Js:Node.Js18.20.4
Node.Js安装教程:2024Node.Js安装
(二)、Android-Sdk
Android-Sdk不是一个软件,而是包含了很多开发工具的软件包,需要安装Sdk管理工具,然后下载对应的Sdk软件包。

现如今安装Android-Sdk,有两种方式,一种是下载Android Studio使用其中的Sdk管理器来下载。
另外一种只需要下载Sdkmanager就可以了,于是我选第二种。
Sdkmanager下载地址:Windows-Sdk
下载完成后解压需要将文件夹目录改成这样,不然的话会报一个版本错误。
┌ android-sdk
│ ├ cmdline-tools
│ │ ├ latest
│ │ │ ├ bin
│ │ │ ├ lib
│ │ │ ├ NOTICE.txt
│ │ │ ├ source.properties

之后按照下面文章中的方法下载"platform-tools" "platforms;android-30" "build-tools;30.0.3"这几个软件,还有模拟器和镜像啥的,下载好之后这些工具就会出现再Android-Sdk这个目录下,不然原本只会有cmdline-tools。
使用Android Sdkmanager安装Android Sdk:在不安装Studio的情况下安装Sdk
然后再按照这个文章配置环境变量。
什么是环境变量:Linux环境变量解析
配置Sdk环境变量:Sdk环境变量配置


Path环境变量配置。

配置好之后应该可以随意打开一个cmd使用adb(Android Debug Bridge)软件,用于Pc端和安卓手机端之间的调试

其他参考文章...
另一篇使用Android Sdkmanager安装Android Sdk:使用Sdkmanager安装Sdk
不是写给初学者看的:官网对Sdkmanager的介绍
(三)、Npm安装Appium
然后通过npm下载,一开始记得换上国内的镜像源。不然下载会很慢。
什么是镜像源?就好像长沙有茶颜悦色,但是你跑长沙买就很慢,于是在你家小区楼下也开了一家一摸一样的,这样就快了。
Npm的默认软件仓库是在国外的服务器上的,国人下载很不方便,于是一些大公司就把这个仓库复制一份到国内来,于是就有了阿里源,腾讯源之类的,这些东东在国内的服务器上,方便我们的下载。
Npm镜像源配置:Npm镜像源
然后按照安装Appium,并且为其配置环境变量。
给Appium配置环境变量:Npm安装Appium
好像又不用配置环境变量,直接安装就行,但是我在Powershell环境下和Cmd环境下运行同样的命令结果却不同。
npm install -g appium #安装Appium
appium -v #查看安装是否成功

(四)、安装Uiautomator2
appium driver install uiautomator2 #安装Uiautomator2
appium driver list #检查是否成功安装

(五)、Appium-Python-Client
在Pycharm中安装Appium-Python-Client是非常简单的,不懂可以自己查查,就不细讲了。

(六)、特别声明
我发现使用模拟器来操作会无法购票,会不停的让你做滑动验证码,可能是服务器识别到了某些特征,暂时我们先不管它。
解决方式是使用真机,打开开发者模式,以及Usb调试。
三、看看代码
环境大差不差的准备好了,接下来下载了代码看看怎么运行。
这个代码里面没有交代怎么运行和配置App端的东东。
我摸索了一下大概是这样。
1、让代码先跑起来
首先要下载一个安卓模拟器(当然你也可以用真实机),然后开启开发者模式,在Pc端打开命令行,输入Adb(Android Debug Bridge,之前安装Android Sdk的时候下载好了的,已经配置到环境变量中的了。)
我下载的是Mumu模拟器,由于在虚拟机里面使用,一开始提示了没有开启Vt(Virtual Technology),我们需要在虚拟机设置中勾选一下,如果是物理机一般不需要弄,我的主板上默认是开了的。

现在我需要在Mumu的多开器上看一下模拟器使用的端口号,然后使用Adb连接上安卓模拟器,确保Pc端和手机端是可以联通的。

顺便开启一下模拟器的Root模式,不知道会不会影响我们的操作。

然后打开命令行提示窗口,使用adb来连接上我们的安卓模拟器。

然后在Appium运行一下,会看到Appium_Server运行在4723端口,这个好像是默认的。

在Config文件中配置一下。

之后就可以运行一下damai_app脚本,记得需要在模拟器上安装大麦App软件。
大概运行起来的样子是这样,还有很多Bug要自己改改,比如在面临弹窗的时候会识别不到元素之类种种。

2、看看代码如何运行
我们看到报错的信息。
首先是说没有找到这个元素,但是,如何在App上面定位元素啊?我不知道啊?

没关系,大哥我爱学,查。
(一)、如何在App定位元素
(1)、Uiautomator
上网查查人家说用Android Sdk中自带的小工具Uiautomator来定位。

我试着打开一下,发现Java版本不匹配,人家说要下Jdk1.8的版本才能用这个工具。

于是去Oracle官网安装一下。
Jdk1.8:下载地址

由于我不想改环境变量,太麻烦了,一会换一个版本的,我上网找到了一种方法在Bat脚本的开头为它设置我Jdk1.8的文件位置,这样运行这个脚本时就会配置一个临时的Java环境。
rem Set Jdk to 1.8
set JAVA_HOME=C:\Program Files (x86)\Java\jdk-1.8
set java_exe="%JAVA_HOME%"/bin/java.exe

保存后,再打开就可以了。
由于我们已经连接上了Adb,它可以自动识别到模拟器上的手机屏幕,并且获得对应的元素节点。

当我们切换界面后,要重新点击小按钮来刷新元素的获取。
Uiautomator View使用教程:View使用教程
(2)、Uiautomator-魔改版
这个原生的小工具有一个缺点,无法定位xpath,我在Github上找了一个魔改版。
可定位Xpath的Uiautomatorview:github地址
安装的教程在网址上有。奶奶滴,安装之后发现这个魔改版本根本不好用,避雷!很多App界面它是无法识别到控件的(原生的Viewer有些也会出现这个问题,但是是可解决的,通过打开手机开发者模式或者重启Adb,Appium,Viewer之类的,感兴趣自己查)。

(3)、Appium Inspector(好用啊!)
于是咱们又找到了一个靠谱的软件,Appium Inspector,这个是官方开发的,还不错。
下载地址:Appium Inspector
安装教程:Appium Inspector
需要添加的配置单元。
{
"platformName": "Android",
"appium:automationName": "UiAutomator2"
}


(二)、检查代码逻辑
(1)、加载配置文件-Config.py
开篇第一行代码,这个Conifg是从config.py文件中导入的,它是用来加载抢票相关配置信息,以及appium的连接配置信息的。
# 加载配置信息
config = Config.load_config()

Json格式的配置文件。

(2)、设置Appium的启动参数
各个参数的详细说明文档:Appium官方
官方的根本不会看,看这篇吧:各个参数解释
[一]、获取安卓版本
在手机上的设置--关于手机里一般有。

[二]、设备名称
这一栏不用修改,随便填,对于安卓系统来说目前没用。

[三]、获取包名
查看app的包名,在Pc端输入下列命令,然后打开对应的App,比如说大麦,就会出现包名啦。
adb shell am monitor

[四]、设置Activity
查了很多资料,不太理解appactivity的作用,像是说作为判断软件从不同入口进入的依据,比如是从桌面打开的软件,又或者是从别的页面跳转过来的,以此依据展示不同的界面?
询问Ai后它说我的想法是对的,它说当从通知栏,浏览器,桌面,这些不同地方打开同一个软件时,该软件的反应是不一样的,那么标识该软件从哪里打开,有没有开机动画之类的,就是Activity来标识。
我们在这随便填应该也不影响,我发现在Appium的Inspector中可以看到当前的Activity。
比如我先切换到设置在切换回大麦。

和我从主屏幕打开大麦。

(3)、连接Appium Server
接下来Python Client需要连接Appium Server给它发指令了
driver = webdriver.Remote(config.server_url, options=device_app_info)
(4)、定位元素
历经千辛万苦,终于来到定位元素的时候了。如何定位元素前面也说了,用Appium Inspector这个软件。

它这的代码逻辑很简单,就是不断的去找各个控件,点击,下一步这样。
关键在于识别控件的快慢,还有异常的处理。
下面是逻辑大概的讲解。


以上所有的实现都是通过识别控件的Xpath,然后发送点击,或者输入文字,来完成。
现在还有关键的问题,就是等待时间的优化,由于网络延迟的问题,每个控件的加载并不一定非常快,这时候元素还没加载出来,我们就使用find_Element来寻找元素的话会出现找不到元素,然后报错的情况。
所以为了避免这种情况,Selenium提供一些等待的方式。脚本中默认使用的是隐式等待,为了加快脚本的速度,我还想寻找更好的方式。
并且其中的一些代码逻辑做的也不太完善,我们来丰富一下
(三)、脚本优化
在网络上看了一个论坛,给出了一些方案。
主流有三种
1、appium模拟人操作
2、Hook技术
3、分析App发送的请求,逆向其加密的参数,重放请求
第2,3种都需要很多时间重新学习,我暂时没有拌饭实现。
于是又看了一看如何优化Appium的执行速度。
感觉没有什么可优化的,这个技术栈的天花板比较矮。
然后我想要判断按钮上的文字,但是没有找到获取元素的文本。

这个脚本优化暂时还没有什么办法做,就先告一段落吧。
Else、备忘录
1、Chocolatey
目标:了解Chocolatey,使用其来安装一个环境。
安装Node.js时勾选了一个chocolatey,简单查了一下是一个Windows的包管理器,类似于debian上的apt和red hat上的rpm,它使用Powershell来安装软件,自动配置环境变量,非常方便。
参考文章:用Chocolate安装Java
2、Powershell
之前一直在用命令行执行,新系统上Powershell似乎更强大。
目标:了解Powershell能做些什么。

浙公网安备 33010602011771号