Appium 官网:https://appium.io/docs/zh/latest/intro/
文档:https://github.com/appium/appium/blob/master/README.md
1、Appium 简介
Appium 简介:https://appium.io/docs/zh/latest/intro/
Appium 是一个跨平台工具(支持许多不同平台:iOS、Android、Web、桌面)的 UI 自动化。还支持不同语言(JS、Java、Python 等)编写自动化代码。
- 移动 原生 应用:是指那些用 iOS 或者 android sdk 写的应用(Application简称app)
- 移动 web 应用:是指那些使用移动浏览器访问的应用,appium 支持 iOS 的 safari 和 android 上的 chrome;
- 混合 应用:是指原生代码封装在网页视图(原生代码和 web 内容交互)。
Appium 实际上分为四个部分:
- Appium Core - 定义核心 API
- 驱动程序 - 实现与特定平台的连接
- 客户端 - 以特定语言实现 Appium 的 API
- 插件 - 更改或扩展 Appium 的核心功能
为了开始使用 Appium 自动化,你需要:
- 安装 Appium 本身
- 为你的目标平台安装驱动程序
- 为你的目标编程语言安装客户端库
- (可选)安装一个或多个插件
如果想了解有关 Appium 运作方式的更多详细信息,可以查看:
要了解 Appium 的起源,可以查看 Appium项目历史。
Appium 的相关概念
- C/S 架构
Appium 的核心是一个 Web 服务器,它提供了一套 REST 的接口。它接收到客户端的连接、监听的命令,接着在移动设备上执行这些命令,然后将执行的结果放在 HTTP 响应中返还给客户端。 - Session
自动化总是在一个 session 的上下文中运行,客户端初始化一个和服务端交互的 session。客户端发送一个附有 desired capabilities 的 JSON 对象参数的 POST 请求 “/session” 给服务器,服务端就会开始一个自动话的 session,然后返回一个session ID,客户端拿到这个 ID 后就用这个 ID 发送后续的命令。 - Desired Capabilities
Desired Capabilities 是一些键值对。客户端将这些键值对发给服务端,告诉服务端我们想要启动怎样的自动化session。 - Appium server
Appium server 是用 nodejs 写的,我们可以源码编译或者从 NPM 直接安装。 - Appium 服务端
Appium 服务端有很多语言库 Java,Ruby,Python,PHP,JavaScript,C# 等,这些库实现了对 WebDriver 协议的扩展。使用 Appium 的时候,只需使用这些库代替常规的 WebDriver 库就可以了。 - Appium.app,Appium.exe
Appium 提供了 GUI 封装的 Appium server 下载,它封装了运行 Appium server 的所有依赖元素。而且这个封装包含了一个Inspector 工具,可以让使用者检查应用的界面元素层级。
2、Appium 快速开始
快速入门:https://appium.io/docs/zh/latest/quickstart/
主要内容
- 安装 Appium
- 安装 Appium 驱动及其依赖项 (下面将使用 UiAutomator2 driver 来操作安卓设备)。当在不同平台使用 Appium 驱动程序时,一般都需要安装该平台的开发人员工具链和 SDK。当指定在Android设备上使用时,需要安装 Android sdk。
- 用你选择的语言安装 Appium 客户端库(本指南包含以下选项 JavaScript、Python、Java、Ruby 和 .NET 的选项)。
- 使用示例应用程序编写并运行简单的 Appium 自动化脚本
安装 Appium
Appium 本身相对轻量级,并且没有大量的磁盘空间或RAM要求。 只要 Node.js 可用即可,所以安装之前需要先安装 nodejs:https://nodejs.org/zh-cn/download/package-manager 。安装完 nodejs 后,即可使用 nodejs 自带的 npm 进行安装
全局安装 Appium:npm install -g appium
npm config set proxy http://127.0.0.1:7890
npm config set https-proxy http://127.0.0.1:7890启动 Appium,命令行执行:appium
将会启动 Appium 服务器进程,该进程加载所有已安装的 Appium 驱动程序,并且 开始等待来自客户端连接(例如测试自动化脚本)的新会话请求。 由于服务器进程独立于其客户端,因此必须在 尝试启动新会话。启动服务器时,控制台日志将列出客户端可用的所有有效 URL 连接到此服务器。
一旦客户端请求新会话,Appium 服务器进程将开始记录有关 此会话,直到其终止。如果遇到 Appium 的问题 测试,可以随时查看服务器日志以获取更多详细信息。
安装 Appium 驱动
如果没有驱动,你几乎无法使用 Appium,驱动是允许 Appium 自动化特定平台的接口。不同平台的 Appium驱动程序 都需要安装对应平台的开发人员工具链和SDK。为了协助满足驱动程序的要求,每个官方驱动程序都会配备 Appium Doctor 工具,该工具用于验证当前配置是否已满足驱动程序的所有要求。 可以在命令行使用文档中了解更多关于如何使用这个工具的信息。所以,要使用 Appium 做任何有用的事情之前,至少需要安装一个驱动程序,否则 Appium 将不知道如何自动化任何事情。Appium 驱动程序和插件 生态系统。
上面步骤中 Appium 已安装并运行,但是它没有与任何驱动程序捆绑在一起,所以它还不能自动化任何事情。接下来将为 Android 设置自动化,所以需要安装 UiAutomator2 驱动程序。
这些驱动程序目前由 Appium 团队维护:
驱动 | 驱动名称 | 支持的平台 | 支持的形式 |
---|---|---|---|
Chromium | chromium | macOS, Windows, Linux | Web |
Espresso | espresso | Android | Native |
Gecko | gecko | macOS, Windows, Linux, Android | Web |
Mac2 | mac2 | macOS | Native |
Safari | safari | macOS, iOS | Web |
UiAutomator2 | uiautomator2 | Android | Native, Hybrid, Web |
Windows | windows | Windows | Native |
XCUITest | xcuitest | iOS | Native, Hybrid, Web |
这些驱动程序不由Appium团队维护,可用于针对其他平台:
驱动 | 驱动名称 | 支持的平台 | 支持的形式 | 维护者 |
---|---|---|---|---|
Flutter | --source=npm appium-flutter-driver | iOS, Android | Native | Community |
Flutter Integration | --source=npm appium-flutter-integration-driver | iOS, Android | Native | Community / @AppiumTestDistribution |
LG WebOS | --source=npm appium-lg-webos-driver | LG TV | Web | HeadSpin |
Linux | --source=npm @stdspa/appium-linux-driver | Linux | Native | @fantonglang |
Roku | --source=npm @headspinio/appium-roku-driver | Roku | Native | HeadSpin |
Tizen | --source=npm appium-tizen-driver | Android | Native | Community / Samsung |
TizenTV | --source=npm appium-tizen-tv-driver | Samsung TV | Web | HeadSpin |
Youi | --source=npm appium-youiengine-driver | iOS, Android, macOS, Linux, tvOS | Native | Community / You.i |
如果没有驱动程序,就无法使用Appium。单击每个驱动程序的链接,查看该驱动程序的具体安装说明和文档。使用命令安装驱动程序:appium driver install <驱动名称> 。要了解有关驱动的更多信息,请查看驱动简介。由于 UiAutomator2 驱动是由核心 Appium 团队维护的,它有一个官方的驱动名称,你可以通过 Appium 扩展 CLI 轻松安装。在安装之前,请确保您的 Appium 服务器没有运行(如果正在运行,请使用 Ctrl-C 退出它)。然后运行以下命令:appium driver install uiautomator2
验证是否安装成功:appium driver doctor uiautomator2
带 X 号的是没有满足的条件,满足后即可验证安装成功。根据提示信息进行修复。
从 github 下载 bundletool.jar,将其重命名为 bundletool.jar,然后在 android sdk 目录下,创建一个子目录 bundle-tool,把 bundletool.jar 放在这个子目录下,在系统环境变量 PATH 中添加bundletool.jar 存放路径 (如:D:\android-sdk\bundle-tools):%ANDROID_HOME%\bundle-tool 系统环境变量 PATHEXT :.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW;.JAR
PATHEXT
是一个环境变量,它定义了可执行文件的扩展名列表。通过这个变量,系统可以识别哪些扩展名的文件可以被当作可执行文件直接运行(比如在命令提示符或脚本中)。这些扩展名表示:
- .COM、.EXE:二进制可执行程序。
- .BAT、.CMD:批处理脚本文件。
- .VBS、.JS 等:脚本文件(如 VBScript 或 JScript)。
- .MSC:管理控制台文件。
再次执行命令,验证是否安装成功,可以看到已经安装成功。
修复后再次启动 Appium 服务器(运行 appium ),可以看到新安装的 driver 列为 available
Android 自动化
Android 开发工具包
- 设置 Android SDK 要求的最简单方法是下载 Android Studio。 我们需要使用其 SDK 管理器 (设置 -> 语言和框架 -> Android SDK) 来下载以下项目:
Android SDK 平台(选择我们想要自动化的任何 Android 平台,例如,API 级别 30)
Android SDK 平台工具 - 设置
ANDROID_HOME
环境变量,指向安装 Android SDK 的目录。通常可以在 Android Studio 的 SDK 管理器中找到这个目录的路径。它将包含platform-tools
和其他目录。
Java JDK
- 安装 Java JDK(对于最新的 Android API 级别,需要 JDK 9,否则需要 JDK 8)。可以从 Oracle 或 Adoptium 下载。 确保下载的是 JDK 而不是 JRE。
- 设置
JAVA_HOME
环境变量,指向 JDK 的安装目录。它将包含bin
、include
和其他目录。
准备 Android 设备
- 如果使用模拟器,使用 Android Studio 创建并启动一个 Android 虚拟设备 (AVD)。 你可能需要下载你想要创建的模拟器的 API 级别的系统镜像。使用 Android Studio 中的 AVD 创建向导通常是完成所有这些操作的最简单方式。
- 如果使用真实设备,应该为开发设置并启用 USB 调试。
- 连接模拟器或设备后,你可以运行
adb devices
(通过位于$ANDROID_HOME/platform-tools/adb
的二进制文件)来验证你的设备是否显示为已连接。一旦你的设备在adb
中显示为已连接,并且你已验证环境变量设置正确,你就可以开始了
编写 Python 测试
完成 Android 设置并安装 UiAutomator2 驱动程序后,就可以编写代码进行自动化测试了。
Appium Python 客户端是 Python 中的官方 Appium 客户端,可通过 pypi 在 Appium-Python-Client 包名称下获得。它继承自 Selenium Python 绑定,因此安装 Appium Python 客户端包括 selenium 绑定。安装:pip install Appium-Python-Client
unittest 应用程序:此示例使用 Python 的内置模块,但您可以使用所需的任何 Python 测试框架。Appium Python 客户端会自动添加供应商前缀。
import unittest
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
capabilities = dict(
platformName='Android',
automationName='uiautomator2',
deviceName='Android',
appPackage='com.android.settings',
appActivity='.Settings',
language='en',
locale='US'
)
appium_server_url = 'http://localhost:4723'
class TestAppium(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Remote(appium_server_url, options=UiAutomator2Options().load_capabilities(capabilities))
def tearDown(self) -> None:
if self.driver:
self.driver.quit()
def test_find_battery(self) -> None:
el = self.driver.find_element(by=AppiumBy.XPATH, value='//*[@text="Battery"]')
el.click()
if __name__ == '__main__':
unittest.main()
这段代码正在做以下事情:
- 定义一组“Capabilities”(参数),发送到Appium服务器,以便Appium知道你想要自动化的事物类型。
- 在内置的 Android 设置应用程序上启动 Appium 会话。
- 查找“Battery”列表项并点击它。
- 停顿片刻,纯粹是为了观察自动化视觉效果。。
- 结束Appium会话。
使用 Appium Inspector
Appium Inspector ( https://github.com/appium/appium-inspector ) 可以对应用程序进行可视化检查探测并定位元素,是编写 Appium 测试的必备工具。
常用识别元素的工具
- uiautomator:Android SDK 自带的一个工具,在 tools 目录下。
两分钟搞懂 UiAutomator 自动化测试框架:https://zhuanlan.zhihu.com/p/128058291
安装 uiautomator2:pip install -U uiautomator2
测试是否安装成功: uiautomator2 --help
UI Inspector 是独立与uiautomator2之外的一个项目,用于查看图层结构的。属于旧版项目weditor 的重构版本。
安装 UI Inspector:pip install uiautodev
启动UI Inspector:uiauto.dev
浏览器打开 https://uiauto.dev 查看当前设备的界面结构。 - monitor:Android SDK 自带的工具,在 tools 目录下。monitor 其实还是调用 uiautomator。( https://developer.android.google.cn/studio/profile/monitor?hl=zh-cn ) 对于Android Studio 3.2及更高版本,Android Device Monitor工具已经被重构并集成到了新版的Android Profiler中。这意味着,你需要通过Android Profiler来访问Android Device Monitor的功能。以下是解决步骤:
打开 Android Studio 并加载你的项目。
在顶部菜单栏选择“View”,然后选择“Tool Windows”。
在弹出的下拉菜单中,找到并点击“Android Profiler”。
在Android Profiler窗口的左侧,你会看到一个设备列表,这里列出了所有连接的Android设备。选择你想要监控的设备。
在Android Profiler窗口的顶部,你会看到一个新的按钮,叫做“Device Monitor”。点击这个按钮。
在弹出的新窗口中,你就可以看到Android Device Monitor的所有功能了。你可以在这里进行日志收集、模拟网络状况、模拟地理位置等操作。
需要注意的是,虽然 Android Device Monitor 的功能现在被整合到了Android Profiler中,但是一些老版本的工具,如 DDMS(Dalvik Debug Monitor Server)和 Hierarchy Viewer,仍然可以单独安装和配置。如果需要使用这些工具,可以在Android Studio的SDK Manager中进行安装。 - Appium Inspector:Appium 自带的一个功能,反应速度有点慢。推荐 UI Inspector,或者老版本的 monitor (ddms)。
Appium Inspector 文档:https://appium.github.io/appium-inspector/latest/
- Inspector 概述、基础知识:https://appium.github.io/appium-inspector/latest/overview/
- 快速入门:https://appium.github.io/appium-inspector/latest/quickstart/
启动会话:https://appium.github.io/appium-inspector/latest/quickstart/starting-a-session/
配置如下 ( Session Builder:https://appium.github.io/appium-inspector/latest/session-builder/ )
{
"platformName": "Android",
"appium:automationName": "uiAutomator2",
"appium:appPackage": "com.android.settings",
"appium:appActivity": "com.android.settings.Settings"
}
- 服务器详细信息保持不变, Inspector 将尝试连接到本地 Appium 服务器在其默认端口上
- 会话功能设置为使用 UiAutomator2 驱动程序,以及 Android 系统设置应用程序
添加完配置后,点击 start session 即可连接到 Android 手机,并打开 Session Inspector 屏幕:
Session Inspector:https://appium.github.io/appium-inspector/latest/session-inspector/
菜单栏的参考:https://appium.github.io/appium-inspector/latest/menu-bar/
使用示例:appium 元素定位方法:https://www.cnblogs.com/graybird/p/11312025.html
进一步 探索
很好的指南和参考资料:
- 在 生态系统 页面: 浏览可用的驱动程序, 客户端, 插件, 和工具
- 管理Appium驱动程序与插件
- 能力
- 设置
3、Appium 移动自动化测试
关键字:Appium 爬虫
Appium 移动自动化测试:https://www.cnblogs.com/fnng/p/4540731.html
主要包括以下几部分:
- appium新手入门(1) —— appium介绍
- appium新手入门(2) —— 安装 Android SDK
- appium新手入门(3) —— 安装 appium Server
- appium新手入门(4) —— java-client安装与测试
- appium新手入门(5) —— python-client安装与测试
- appium新手入门(6) —— appium-desktop
- appium新手入门(7) —— Desired Capabilities
- appium新手入门(8) —— 定位控件
- appium新手入门(9) —— appium API 之应用操作
- appium新手入门(10)—— appium API 之上下文操作
- appium新手入门(11)—— appium API 之键盘操作
- appium新手入门(12)—— appium API 之 TouchAction 操作
- appium新手入门(13)—— appium API 之其他操作
示例:爬取 APP 数据
利用 Appium+Python+Android 设备爬取APP数据:https://blog.youkuaiyun.com/LLKET/article/details/104940895
示例:python 对接 Appium
注意:代码运行时要保证手机不黑屏
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
PLATFORM='Android'
deviceName='HUAWEI_P7_L09'
app_package='com.tencent.mm'
app_activity='.ui.LauncherUI'
driver_server='http://127.0.0.1:4723/wd/hub'
class Moments():
def __init__(self):
self.desired_caps={
'platformName':PLATFORM,
'deviceName':deviceName,
'appPackage':app_package,
'appActivity':app_activity
}
self.driver=webdriver.Remote(driver_server, self.desired_caps)
self.wait=WebDriverWait(self.driver,300)
def login(self):
print('正在登陆中——————')
def main(self):
self.login()
M = Moments()
M.main()
如果出现 urllib.error.URLError: urlopen error [WinError 10061] 由于目标计算机积极拒绝,无法连接。看看打开 appium 没有,打开后再运行上面的代码就没有问题,手机会自动转到微信的登陆界面。( ***************** 注:deviceName 要改成自己的 手机 或者 模拟器 ***************** )
打开微信后,我们要模拟点击登陆按钮,首先要定位到登陆元素,这个跟 selenium 的用法类似,
方式 1:使用 Appium Inspector 定位元素
打开 appium 用前面的方式连接微信,定位微信的 "登录" 按钮。( 我使用 appium 选择元素的功能没有定位到登录按钮。。 )
其他 app 按钮定位:
但是使用 uiautomator 或者 monitor 却可以定位到,参看 方式 2
方式 2:使用 uiautomator 或者 monitor
uiautomator 或者 monitor :Android SDK 自带的工具。monitor 在 tools 目录下,uiautomator 在 tools\bin 目录下。
下图中,要先点击图中的按钮,才会出现手机上的画面,图中我已经定位到登陆按钮,可以在右边看到属性resource-id,以及clickable=True,确实是可以点击的,为什么要这样确认下呢,因为有的你以为可以点击的元素,也许你定位没有定好,比如说你定位到登陆外更大的一个框,它是不可点击的
使用 monitor 打开结果截图:
示例代码:
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
PLATFORM = 'Android'
deviceName = 'HUAWEI_P7_L09'
app_package = 'com.tencent.mm'
app_activity = '.ui.LauncherUI'
driver_server = 'http://127.0.0.1:4723/wd/hub'
class Moments():
def __init__(self):
self.desired_caps={
'platformName': PLATFORM,
'deviceName': deviceName,
'appPackage': app_package,
'appActivity': app_activity
}
self.driver = webdriver.Remote(driver_server, self.desired_caps)
self.wait = WebDriverWait(self.driver, 300)
def login(self):
print('点击登陆按钮——————')
login = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/f34')))
login.click()
def main(self):
self.login()
M = Moments()
M.main()
运行后就会跳出登陆界面,
接下来就都是定位元素与点击元素的事情:
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
PLATFORM = 'Android'
deviceName = 'HUAWEI_P7_L09'
app_package = 'com.tencent.mm'
app_activity = '.ui.LauncherUI'
driver_server = 'http://127.0.0.1:4723/wd/hub'
class Moments():
def __init__(self):
self.desired_caps = {
'platformName': PLATFORM,
'deviceName': deviceName,
'appPackage': app_package,
'appActivity': app_activity
}
self.driver = webdriver.Remote(driver_server, self.desired_caps)
self.wait = WebDriverWait(self.driver, 300)
def login(self):
print('点击登陆按钮——————')
login = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/f34')))
login.click()
# 输入手机号
phone = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/hz')))
phone_num = input('请输入手机号')
phone.send_keys(phone_num)
print('点击下一步中')
button = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/alr')))
button.click()
pass_w = input('请输入密码:')
password = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/hz')))
password.send_keys(pass_w)
login = self.driver.find_element_by_id('com.tencent.mm:id/alr')
login.click()
# 提示 叉掉
tip = self.wait.until(EC.element_to_be_clickable((By.ID, 'com.tencent.mm:id/an2')))
tip.click()
def main(self):
self.login()
M = Moments()
M.main()
现在已经进入到微信了,我们需要先定位到微信下面的 发现->朋友圈
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
PLATFORM = 'Android'
deviceName = 'HUAWEI_P7_L09'
app_package = 'com.tencent.mm'
app_activity = '.ui.LauncherUI'
driver_server = 'http://127.0.0.1:4723/wd/hub'
class Moments():
def __init__(self):
self.desired_caps = {
'platformName': PLATFORM,
'deviceName': deviceName,
'appPackage': app_package,
'appActivity': app_activity
}
self.driver = webdriver.Remote(driver_server, self.desired_caps)
self.wait = WebDriverWait(self.driver, 300)
def login(self):
print('点击登陆按钮——————')
login = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/f34')))
login.click()
# 输入手机号
phone = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/hz')))
phone_num = input('请输入手机号')
phone.send_keys(phone_num)
print('点击下一步中')
button = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/alr')))
button.click()
pass_w = input('请输入密码:')
password = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/hz')))
password.send_keys(pass_w)
login = self.driver.find_element_by_id('com.tencent.mm:id/alr')
login.click()
# 提示 叉掉
tip = self.wait.until(EC.element_to_be_clickable((By.ID, 'com.tencent.mm:id/an2')))
tip.click()
def enter(self):
print('点击发现——')
tab = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@resource-id="com.tencent.mm:id/cdh"]/..')))
print('已经找到发现按钮')
time.sleep(6)
tab.click()
# self.wait.until(EC.text_to_be_present_in_element((By.ID,'com.tencent.mm:id/cdj'),'发现'))
print('点击朋友圈')
friends = self.wait.until(EC.presence_of_element_located(
(By.XPATH, '//*[@resource-id="android:id/list"]/*[@class="android.widget.LinearLayout"][1]')))
friends.click()
def main(self):
self.login()
self.enter()
M = Moments()
M.main()
都是些元素定位,多用几次就会了。接下来我们可以提取数据了
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
import pymongo
PLATFORM = 'Android'
deviceName = 'HUAWEI_P7_L09'
app_package = 'com.tencent.mm'
app_activity = '.ui.LauncherUI'
driver_server = 'http://127.0.0.1:4723/wd/hub'
class Moments():
def __init__(self):
self.desired_caps = {
'platformName': PLATFORM,
'deviceName': deviceName,
'appPackage': app_package,
'appActivity': app_activity
}
self.driver = webdriver.Remote(driver_server, self.desired_caps)
self.wait = WebDriverWait(self.driver, 300)
self.client = pymongo.MongoClient()
self.db = self.client.weixin
self.collection = self.db.weixin
def login(self):
print('点击登陆按钮——————')
login = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/f34')))
login.click()
# 输入手机号
phone = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/hz')))
phone_num = input('请输入手机号:')
phone.send_keys(phone_num)
print('点击下一步中')
button = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/alr')))
button.click()
pass_w = input('请输入密码:')
password = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/hz')))
password.send_keys(pass_w)
login = self.driver.find_element_by_id('com.tencent.mm:id/alr')
login.click()
# 提示 叉掉
tip = self.wait.until(EC.element_to_be_clickable((By.ID, 'com.tencent.mm:id/an2')))
tip.click()
def enter(self):
print('点击发现——')
tab = self.wait.until(EC.element_to_be_clickable((By.XPATH, '//*[@resource-id="com.tencent.mm:id/cdh"]/..')))
print('已经找到发现按钮')
time.sleep(6)
tab.click()
# self.wait.until(EC.text_to_be_present_in_element((By.ID,'com.tencent.mm:id/cdj'),'发现'))
print('点击朋友圈')
friends = self.wait.until(EC.presence_of_element_located(
(By.XPATH, '//*[@resource-id="android:id/list"]/*[@class="android.widget.LinearLayout"][1]')))
friends.click()
def crawl(self):
while True:
items = self.wait.until(EC.presence_of_all_elements_located(
(By.XPATH, '//*[@resource-id="com.tencent.mm:id/dja"]//*[@class="android.widget.FrameLayout"]')))
self.driver.swipe(300, 1000, 300, 300)
for item in items:
try:
nickname = item.find_element_by_id('com.tencent.mm:id/as6').get_attribute('text')
print(nickname)
content = item.find_element_by_id('com.tencent.mm:id/dkf').get_attribute('text')
print(content)
data = {'nickname': nickname, 'content': content}
self.collection.update({'nickname': nickname, 'content': content}, {'$set': data}, True)
except BaseException as e:
print(e)
def main(self):
self.login()
self.enter()
self.crawl()
M = Moments()
M.main()
driver.swipe() 是从点 A 滑动到点 B,driver.swipe(300,1000,300,300)是从点(300,1000)滑动到(300,300)
self.collection.update({'nickname':nickname,'content':content},{'$set':data},True)
首先根据昵称和正文来查询,如果信息不存在,则插入数据,否则更新数据,关键点是第三个参数True,这可以实现存在即更新,不存在即插入的代码,用着感觉很舒服呢
使用 appium 直接打开微信 ---> 发现 ---> 朋友圈 ---> 打印昵称和文字内容
示例代码:( 代码中 xpath 是用过 appium 的 Start Recording 自动生成的。。。 )
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
PLATFORM = 'Android'
deviceName = 'MI_6X'
app_package = 'com.tencent.mm'
app_activity = '.ui.LauncherUI'
driver_server = 'http://127.0.0.1:4723/wd/hub'
class Moments(object):
def __init__(self):
self.desired_caps = {
'platformName': PLATFORM,
'deviceName': deviceName,
# 'appPackage': app_package,
# 'appActivity': app_activity
}
self.driver = webdriver.Remote(driver_server, self.desired_caps)
self.wait = WebDriverWait(self.driver, 300)
def login(self):
# print('正在登陆中........')
# btn_login = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/f34')))
# btn_login.click()
# btn_change = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/d0h')))
# btn_change.click()
#
# phone_num = input('输入微信账号:')
# edittext_username = self.wait.until(EC.visibility_of_all_elements_located((By.ID, 'com.tencent.mm:id/bem')))
# edittext_username[0].send_keys(phone_num)
#
# password = input('输入微信密码:')
# edittext = self.wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'android.widget.EditText')))
# edittext[1].send_keys(password)
#
# btn = self.wait.until(EC.presence_of_element_located((By.ID, 'com.tencent.mm:id/d0a')))
# btn.click()
el1 = self.driver.find_element_by_xpath('//android.widget.ImageView[@content-desc="微信"]')
el1.click()
el1 = self.driver.find_element_by_xpath(
"//android.widget.FrameLayout[@content-desc=\"当前所在页面,与的聊天\"]/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.LinearLayout/android.widget.RelativeLayout[3]/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.ImageView[1]")
el1.click()
time.sleep(2)
el2 = self.driver.find_element_by_xpath(
"//android.widget.FrameLayout[@content-desc=\"当前所在页面,与的聊天\"]/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.FrameLayout/com.tencent.mm.ui.mogic.WxViewPager/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.ListView/android.widget.LinearLayout[1]/android.widget.LinearLayout/android.widget.LinearLayout[1]/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.TextView")
el2.click()
time.sleep(2)
while True:
items = self.wait.until(EC.presence_of_all_elements_located(
(By.XPATH, '//*[@class="android.widget.LinearLayout"]//*[@resource-id="com.tencent.mm:id/fpv"]')))
self.driver.swipe(300, 1000, 300, 300)
for item in items:
try:
nickname = item.find_element_by_id('com.tencent.mm:id/e3x').get_attribute('text')
print(nickname)
content = item.find_element_by_id('com.tencent.mm:id/b_e').get_attribute('text')
print(content)
data = {'nickname': nickname, 'content': content}
# self.collection.update({'nickname': nickname, 'content': content}, {'$set': data}, True)
except BaseException as e:
print(e)
def main(self):
self.login()
if __name__ == '__main__':
M = Moments()
M.main()