记忆碎片之python爬虫APP数据爬取之UI Automator Viewer和Appium双剑合璧(五)

第一步:配置JDK环境
# 配置jdk环境
# https://www.oracle.com/java/technologies/javase-jdk8-downloads.html
# 查看是否安装成功 java, java -version, javac 三个命令可分别测试
# 在安装前新建文件夹d: java/jdk|jre Java下面两个文件夹,安装时会让自定义两次安装路径,第一次在jdk,第二次是jre
# 根据图片上的配置,配置本地的系统环境变量
# 如果配置成功,经过测试会输出很多数据,否则红色报错提示

在这里插入图片描述
注意:如果是Windows10系统,图片上面的分号是换行的意思
在这里插入图片描述

第二步:配置SDK环境
# SDK 软件开发工具包。是软件开发工程师用于为特定的软件包、软件框架、硬件平台
# 操作系统等建立应用软件的开发工具集合
# http://tools.android-studio.org/index.php/sdk sdk下载
# 配置sdk环境变量
# 启动sdk_manager并配置国内代理,然后重新加载,我这里加载国内源失败,就用原来的,速度还行2.7M/s左右,得下载20G左右

在这里插入图片描述
在这里插入图片描述
更新各种依赖
在这里插入图片描述
下图为安装的项目类别
在这里插入图片描述

第三步:初识adb工具
# adb是一个通用命令行工具,其允许您与模拟器实例或连接的安卓设备进行通信
# 它可以为各种设备操作提供便利,如安装和调试应用
# 启动adb服务,端口是它自动绑定的,adb是SDK下面的工具,同时也在环境变量,注意就算adb添加到了系统环境变量,如果电脑重新启动,就需要到D:\sdk\platform-tools目录

# 启动powershell 然后重新运行下面的adb 启动命令,这个时候cmd才可以使用adb命令
C:\Users\AA>adb start-server
* daemon not running; starting now at tcp:5037
* daemon started successfully
"""

"""
模拟器配置:设置-关于平板电脑-快速点击版本号(会提示进入开发者模式)-返回上一步点击开发者选项-允许USB调试并确定
现在就可以使用adb命令行工具对模拟器手机等设备进行操作了
"""
"""
# adb devices 查看连接的设备
C:\Users\AA>adb devices
adb server version (36) doesn't match this client (41); killing...
* daemon started successfully
List of devices attached
这里的报错说的是adb服务用的是36版本,模拟器是41,不匹配造成的报错
这个时候就需要匹配版本

复制D:\sdk\platform-tools下面的三个文件
分别是:adb.exe   AdbWinApi.dll    AdbWinUsbApi.dll
切换到夜神模拟器所在目录D:\yeshen\Nox\bin里面也有上述三个文件夹
这个时候先把这三个同名文件备份到一个新建的自定义文件夹,然后把三个文件进行替换操作,
夜神模拟器下面有个nox_adb.exe的文件,也需要先备份
然后把adb.exe复制一份,重命名为nox_adb.exe
这样就能统一版本了

C:\Users\AA>adb devices
List of devices attached

需要重启安卓模拟器,结果如下
C:\Users\AA>adb devices
List of devices attached
127.0.0.1:62001 device 
如果有第二台模拟器就是 +1 如:127.0.0.1:62002 device 

adb -s 127.0.0.1:62001 shell 进入手机安卓操作系统的底层
ls可以查看文件目录
# 模拟器和真机的区别
root@shamu:/ # ls  安卓模拟器的是#,#号代表有root权限
root@leshi:/ $ ls  真实手机的是$,$符号表示没有root权限
exit退出shell交互
"""

"""
adb命令行工具安装APK应用
adb -s 127.0.0.1:62001 install 文件名.apk   回车开始安装
卸载的时候需要使用包名,如何查看包名?
进入底层系统之后, cd /data/app 回车 之后ls,就可以看到包名了例如:
root@shamu:/data/app # ls
com.douguo.recipe-1
com.ss.android.ugc.aweme-1
-1前面的字母就是每一个APP对应的包名
exit回车退出shell
输入 adb -s 127.0.0.1:62001 uninstall 包名 回车之后如果卸载成功会显示Success
"""
"""
如果adb devices没有显示连接到什么设备,但是夜神模拟器已经打开了,这个时候要主动去连接该设备,获取名称属性
adb.connect 127.0.0.1:62001,然后在请求adb devices,发现这台设备已经连接上了
"""
"""
adb shell pm list package 会列出当前模拟器里面所有的包名
如何把本地文件传到夜神模拟器安卓系统里面
命令是adb push 本地文件路径 夜神模拟器文件存放位置,如下:
C:\Users\AA>adb push D:\java\ce.txt /sdcard
D:\java\ce.txt: 1 file pushed, 0 skipped. 0.0 MB/s (20 bytes in 0.082s) # 执行成功

如何把夜神模拟器里面文件下载到本机
命令是 adb pull 夜神模拟器文件位置 本机存放位置,如下
C:\Users\AA>adb pull /sdcard//ce.txt D:\java\   注意:不能pull磁盘根目录,要放文件夹下面
/sdcard//ce.txt: 1 file pulled, 0 skipped. 0.0 MB/s (20 bytes in 0.006s)

在cmd中使用adb命令截图
                        截图命令     存放位置
C:\Users\AA>adb shell screencap /sdcard/test.png
再把截图存到本地文件夹里面
C:\Users\AA>adb pull /sdcard/test.png D:\java\
/sdcard/test.png: 1 file pulled, 0 skipped. 1.7 MB/s (56500 bytes in 0.031s)
"""
第四步:sdk下uiautomatorviewer工具使用
"""
sdk下uiautomatorviewer工具使用
它是安卓4.3发布的时候发布的测试工具,是用来做UI测试的
也就是普通的手工测试,点击每个控件元素,看看输出的结果是否符合预期,比如:登录界面
分别输入正确和错误的用户名密码,然后点击登录按钮看看能否登录以及是否有错误提示等
工具的组成:
    uiaotumatorviewer   是一个图形界面工具,用来扫描和分析应用的UI控件,存放在tools目录
                        D:\sdk\tools目录下的uiautomatorviewer.bat这个文件,双击启动,最小化黑框
                        启动真机或模拟器,并开启开发者选项-USB调试,在模拟器中开启一个APP应用,https://bang.kaoyan.com/
                        这里用到的APP是考研帮,启动APP之后,点击帐号密码登录,并停留在该页面
                        在uiautomatorviewer中的左上角工具栏里面点击第二个工具,也就是生成当前APP应用的快照device screenshot
                        点击该按钮之后,工具开始解析APP的UI控件,之后在UI Automator Viewer 左侧窗口显示模拟器厘米的APP界面
                        点击控件,可以在右侧下方窗口看见该控件的属性,可以利用这些属性来定位控件,模拟点击等操作
                        https://github.com/lazytestteam/lazyuiautomatorviewer下载升级包,执行替换文件操作,拥有xpath定位
                        被替换文件在D:\sdk\tools\lib下面
    uiautomator 是一个测试的Java库,包含了创建UI测试的各种API和执行自动化测试的引擎
    
"""

升级包是因为它本身是没有xpath功能的,升级后就有了
在这里插入图片描述

第五步:初识Appium工具
"""
appium自动化工具
它是一个开源测试自动化框架,可用于原生、混合和移动web应用程序测试
它使用webdriver协议驱动ios、android应用程序
跨平台,支持多种语言
"""
"""
client运行的是自动化的脚本,调用的是webdriver API,
appium server接收的是client发送过来的命令,把这些命令转换成uiautomator认识的命令
再由uiautomator在设备上执行自动化

appium server主要监听从appium client发送过来的命令,把命令发送给bootstrap.jar(安卓)|js(ios)进行执行
然后通过TCP server返回给client进行应答
bootstrap.jar(安卓上的一个应用程序,扮演了一个TCP服务器的角色)
在appium server和bootstrap.jar在通信时,会建立TCP协议,来发送命令和反馈信息,bootstrap.jar负责运行接收的命令
"""

在这里插入图片描述
在这里插入图片描述
上图就是appium服务器的启动界面

"""
启动桌面appium的快捷方式
Host 如果是0.0.0.0 说明appium监听当前系统的所有网卡
port默认是4723
启动appium服务器之后,在右上角有一个暂停按钮,点击暂停之后会有一个X关闭按钮,点击该按钮则关闭appium服务

advanced是高级设置
presets存储advanced的配置做为预设值
"""
"""
启动appium之后,右上角有一个放大镜按钮,Start Inspector Session,点击之后打开一个新的窗口
Automatic Server 指的是本地的appium服务器
Custom Server 指定的远程服务器上面的apppium服务器
"""

在这里插入图片描述
最主要的是右上角的放大镜按钮,点击之后弹出下图窗口
在这里插入图片描述
在这里一般需要配置的是Desired Capabilities下面的内容,例如:
在这里插入图片描述
点击右下角的Save as按钮,名个名字保存数据,数据就在旁边
在这里插入图片描述

# desired capabilites一般如下格式的数据
desired_caps = {}
desired_caps["platformName"] = "Android"
desired_caps["platformVersion"] = "4.4.2"
desired_caps["deviceName"] = "127.0.0.1:62001"
desired_caps["appPackage"] = "注意这里是填写包名,不是文件名"
desired_caps["appActivity"] = "com.jingdong.app.app.mall.MainFrameActivity"  # 和网页概念类似
desired_caps["noReset"] = False  # 有的APP启动有广告,默认为False,设置为true时,以后启动过滤广告
desired_caps["appWaitPackage"] = "SplashActivity"  # 用于等待启动的安卓Activity名称
"""
如何查看appPackage和appActivity对应的值呢?
在D:\sdk\build-tools\29.0.3目录下面有一个aapt.exe文件,在当前目录启动cmd,输入下面的命令
第一种方式: \aapt.exe dump badging D:\sdk\build-tools\kaoyanbang_3.5.7beta1.275.apk
    会出现很多文件名称package: name='com.tal.kaoyan' versionCode='107' versionName='3.5.7beta1' compileSdkVersion='29' compileSdkVersionCodename='10'
                      launchable-activity: name='com.tal.kaoyan.ui.activity.SplashActivity'  label='' icon=''
第二种方式:在powershell中运行相面这行命令,注意,如果是从cmd切换到这个目录的,要用find,不然会报错
    .\aapt dump badging D:\sdk\build-tools\kaoyanbang_3.5.7beta1.275.apk | findstr "launchable-activity"
第三种方式:是使用adb shell
    root@shamu:/ # logcat | grep cmp= 回车,然后启动APP应用,cmd窗口就会出现下面的输出结果,cmp就是包名和Activity
    {flg=0x10000000 cmp=com.tal.kaoyan/com.kaoyan.kylogin.ui.login.LoginActivity (has extras)}
"""
"""
当配置上面的字典之后,在appium的中保存刚刚的配置信息,切换到保存的标签,点击start session启动按钮
等待之后,就会发现模拟器启动了这个APP应用,并且appium刚才的界面变成了和ui automator viewer相似的界面,可以查看APP控件信息
在工具栏里面有一个类似眼睛的按钮,它具有录制功能,在对左侧空间操作时,它会把操作转换成相应的代码,仅做参考
# 注意:如果启动了appium正在查看控件信息,启动UI automator viewer是会报错,原因是端口冲突,同时只能启动一个工具
"""

点击start session启动按钮
在这里插入图片描述
由于appium提供的xpath太长,它是从根开始编辑的xpath,所以仅做参考,xpath从UI automator viewer获取

第六步:Python脚本实现自动化
# 目标:登录app,点击按钮,对立面的信息进行滑动操作
# 工具:模拟器  uiautomatorviewer python
# 注意uiautomatorviewer用于获取xpath,在运行程序时要关闭,同时需要启动appium服务器
import time
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait  # 等待某个UI的控件
from selenium.common.exceptions import NoSuchElementException, TimeoutException

# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple Appium-Python-Client
cap = {
    "platformName": "Android",
    "platformVersion": "5.1.1",
    "deviceName": "127.0.0.1:62001",
    "appPackage": "com.tal.kaoyan",
    "appActivity": "com.tal.kaoyan.ui.activity.SplashActivity",
    "noReset": True
}

# 注意:运行之前要先启动appium服务,The server is running
driver = webdriver.Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=cap)


# 获取列表也的长宽
def get_size():
    x = driver.get_window_size()["width"]
    y = driver.get_window_size()["height"]
    return x, y


# 启动界面的同意按钮 //android.widget.TextView[@resource-id='com.tal.kaoyan:id/tip_commit']
try:
    # 等待三秒,一直等到 xpath定位的元素,如果等到就点击,如果没有就执行下面的pass
    if WebDriverWait(driver, 20).until(lambda x: x.find_element_by_xpath(
            "//android.widget.TextView[@resource-id='com.tal.kaoyan:id/tip_commit']")):
        driver.find_element_by_xpath("//android.widget.TextView[@resource-id='com.tal.kaoyan:id/tip_commit']").click()
except NoSuchElementException:
    print("没有定位到《同意》按钮...")
    pass
# 右上角有一个同意按钮//android.widget.TextView[@resource-id='com.tal.kaoyan:id/tv_skip']
try:
    if WebDriverWait(driver, 20).until(
            lambda x: x.find_element_by_xpath("//android.widget.TextView[@resource-id='com.tal.kaoyan:id/tv_skip']")):
        driver.find_element_by_xpath("//android.widget.TextView[@resource-id='com.tal.kaoyan:id/tv_skip']").click()
except NoSuchElementException:
    print("没有定位到《跳过》按钮...")
    pass
# 密码登录按钮,用于切换非手机号登录 //android.widget.TextView[@resource-id='com.tal.kaoyan:id/login_code_touname']
try:
    if WebDriverWait(driver, 20).until(
            lambda x: x.find_element_by_xpath(
                "//android.widget.TextView[@resource-id='com.tal.kaoyan:id/login_code_touname']")):
        driver.find_element_by_xpath(
            "//android.widget.TextView[@resource-id='com.tal.kaoyan:id/login_code_touname']").click()
except NoSuchElementException:
    print("没有定位到《密码登录》按钮...")
    pass
# 手机号/用户名/通行证 输入框 //android.widget.EditText[@resource-id='com.tal.kaoyan:id/login_email_edittext']
# 密码 输入框 //android.widget.EditText[@resource-id='com.tal.kaoyan:id/login_password_edittext']
# 登录 按钮  //android.widget.TextView[@resource-id='com.tal.kaoyan:id/login_login_btn']

try:
    if WebDriverWait(driver, 20).until(
            lambda x: x.find_element_by_xpath(
                "//android.widget.EditText[@resource-id='com.tal.kaoyan:id/login_email_edittext']")):
        driver.find_element_by_xpath(
            "//android.widget.EditText[@resource-id='com.tal.kaoyan:id/login_email_edittext']").send_keys("用户名")
        time.sleep(0.5)
        driver.find_element_by_xpath(
            "//android.widget.EditText[@resource-id='com.tal.kaoyan:id/login_password_edittext']").send_keys(
            "密码")
        time.sleep(0.5)
        driver.find_element_by_xpath(
            "//android.widget.TextView[@resource-id='com.tal.kaoyan:id/login_login_btn']").click()
except NoSuchElementException:
    print("没有定位到《用户名》输入框...")
    pass
# 点击研讯按钮 //android.view.View[@resource-id='com.tal.kaoyan:id/date_fix']/android.widget.LinearLayout[4]/android.widget.RelativeLayout[1]/android.widget.ImageView[1]
try:
    if WebDriverWait(driver, 30).until(
            lambda x: x.find_element_by_xpath(
                "//android.view.View[@resource-id='com.tal.kaoyan:id/date_fix']/android.widget.LinearLayout[4]/android.widget.RelativeLayout[1]/android.widget.ImageView[1]")):
        driver.find_element_by_xpath(
            "//android.view.View[@resource-id='com.tal.kaoyan:id/date_fix']/android.widget.LinearLayout[4]/android.widget.RelativeLayout[1]/android.widget.ImageView[1]").click()
        size = get_size()  # 屏幕的左上角为(0,0)
        x1 = int(size[0] * 0.5)  # 鼠标横向居中
        y1 = int(size[1] * 0.75)  # 鼠标从屏幕底下向上滑的起始位置
        y2 = int(size[1] * 0.25)  # 鼠标滑动结束的位置
        driver.swipe(x1, y1, x1, y2)  # 滑动操作
        while True:
            driver.swipe(x1, y1, x1, y2)
            time.sleep(0.5)
except NoSuchElementException:
    print("没有定位到《研讯》按钮...")
    pass

无敌免责声明:本文仅用于学习,切勿恶意攻击该APP应用,更不可用于商业盈利,程序并没有获取任何数据,仅仅是自动化而已,密码我已经更改了,嘿嘿!!!

发布了46 篇原创文章 · 获赞 7 · 访问量 4621

猜你喜欢

转载自blog.csdn.net/Python_DJ/article/details/105515186