使用 Appium 抓取手机 app 微信朋友圈

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 的相关概念

  1. C/S 架构 
    Appium 的核心是一个 Web 服务器,它提供了一套 REST 的接口。它接收到客户端的连接、监听的命令,接着在移动设备上执行这些命令,然后将执行的结果放在 HTTP 响应中返还给客户端。
  2. Session 
    自动化总是在一个 session 的上下文中运行,客户端初始化一个和服务端交互的 session。客户端发送一个附有 desired capabilities 的 JSON 对象参数的 POST 请求 “/session” 给服务器,服务端就会开始一个自动话的 session,然后返回一个session ID,客户端拿到这个 ID 后就用这个 ID 发送后续的命令。
  3. Desired Capabilities 
    Desired Capabilities 是一些键值对。客户端将这些键值对发给服务端,告诉服务端我们想要启动怎样的自动化session。
  4. Appium server 
    Appium server 是用 nodejs 写的,我们可以源码编译或者从 NPM 直接安装。
  5. Appium 服务端 
    Appium 服务端有很多语言库 Java,Ruby,Python,PHP,JavaScript,C# 等,这些库实现了对 WebDriver 协议的扩展。使用 Appium 的时候,只需使用这些库代替常规的 WebDriver 库就可以了。
  6. Appium.app,Appium.exe 
    Appium 提供了 GUI 封装的 Appium server 下载,它封装了运行 Appium server 的所有依赖元素。而且这个封装包含了一个Inspector 工具,可以让使用者检查应用的界面元素层级。

2、Appium 快速开始

快速入门:https://appium.io/docs/zh/latest/quickstart/

主要内容

  1. 安装 Appium
  2. 安装 Appium 驱动及其依赖项 (下面将使用 UiAutomator2 driver 来操作安卓设备)。当在不同平台使用 Appium 驱动程序时,一般都需要安装该平台的开发人员工具链和 SDK。当指定在Android设备上使用时,需要安装 Android sdk。
  3. 用你选择的语言安装 Appium 客户端库(本指南包含以下选项 JavaScript、Python、Java、Ruby 和 .NET 的选项)。
  4. 使用示例应用程序编写并运行简单的 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 团队维护:

驱动驱动名称支持的平台支持的形式
ChromiumchromiummacOS, Windows, LinuxWeb
EspressoespressoAndroidNative
GeckogeckomacOS, Windows, Linux, AndroidWeb
Mac2mac2macOSNative
SafarisafarimacOS, iOSWeb
UiAutomator2uiautomator2AndroidNative, Hybrid, Web
WindowswindowsWindowsNative
XCUITestxcuitestiOSNative, Hybrid, Web

这些驱动程序不由Appium团队维护,可用于针对其他平台:

驱动驱动名称支持的平台支持的形式维护者
Flutter--source=npm appium-flutter-driveriOS, AndroidNativeCommunity
Flutter Integration--source=npm appium-flutter-integration-driveriOS, AndroidNativeCommunity / @AppiumTestDistribution
LG WebOS--source=npm appium-lg-webos-driverLG TVWebHeadSpin
Linux--source=npm @stdspa/appium-linux-driverLinuxNative@fantonglang
Roku--source=npm @headspinio/appium-roku-driverRokuNativeHeadSpin
Tizen--source=npm appium-tizen-driverAndroidNativeCommunity / Samsung
TizenTV--source=npm appium-tizen-tv-driverSamsung TVWebHeadSpin
Youi--source=npm appium-youiengine-driveriOS, Android, macOS, Linux, tvOSNativeCommunity / 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 的安装目录。它将包含 bininclude 和其他目录。

准备 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()

这段代码正在做以下事情:

  1. 定义一组“Capabilities”(参数),发送到Appium服务器,以便Appium知道你想要自动化的事物类型。
  2. 在内置的 Android 设置应用程序上启动 Appium 会话。
  3. 查找“Battery”列表项并点击它。
  4. 停顿片刻,纯粹是为了观察自动化视觉效果。。
  5. 结束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/

启动会话: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

进一步 探索

很好的指南和参考资料:

3、Appium 移动自动化测试

关键字:Appium  爬虫

Appium 移动自动化测试:https://www.cnblogs.com/fnng/p/4540731.html

主要包括以下几部分:

示例:爬取 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()

### 使用Appium进行微信小程序的自动化测试 #### 设备准备与配置 为了实现微信小程序的自动化测试,需先完成设备准备工作。这涉及将真机或模拟器通过USB调试模式连接至计算机,并确认设备成功识别。具体来说,可以通过命令`adb connect 127.0.0.1:21503`来链接逍遥模拟器,随后利用`adb devices`验证设备是否被正确识别[^1]。 #### 安装必要的软件包和支持库 对于环境搭建部分,除了确保Android SDK已安装外,还需特别注意ChromeDriver的位置及其兼容性问题。应将下载好的驱动放置于Appium安装路径下对应的子文件夹内(例如:`C:\Users\Administrator\AppData\node_modules\appium\node_modules\appium-chromedriver\chromedriver`)。此步骤至关重要,因为它直接影响到了后续能否顺利启动并控制微信内的Web视图组件[^2]。 #### 初始化WebDriver实例及参数设定 创建一个新的Session之前,要定义好Desired Capabilities对象,其中包含了诸如平台版本、设备型号以及应用包名等基本信息。针对微信小程序而言,还需要额外指定一些特定属性,如: ```json { "platformName": "Android", "deviceName": "emulator-5554", // 或者真实的设备ID "appPackage": "com.tencent.mm", "appActivity": ".ui.LauncherUI" } ``` 这段JSON片段用于告知Appium服务器即将操作的应用程序详情,从而建立有效的通信桥梁。 #### 处理WebView上下文切换 由于微信内部集成了多种类型的页面展示形式——既有基于Native UI构建的部分也有采用HTML/CSS/JavaScript渲染的内容区域;因此,在编写脚本过程中不可避免地会遇到跨层交互的需求。此时便要用到context管理功能,即借助API接口查询当前可用的浏览环境列表(`driver.contexts`),再从中选取目标项作为下一步动作执行的基础(`driver.switch_to.context(context)`)[^4]。 #### 应对特殊场景挑战 值得注意的是,某些情况下可能会碰到因权限限制而导致的功能缺失现象,比如尝试调用`set_clipboard_text()`函数向剪贴板写入数据却遭遇异常抛出的情况。这类难题往往源于底层架构设计差异所致,建议开发者仔细查阅官方文档寻找替代方案或是调整策略绕过障碍继续推进项目进展[^3]。 ```python from appium import webdriver desired_caps = { 'platformName': 'Android', 'deviceName': 'your_device_id', 'appPackage': 'com.tencent.mm', 'appActivity': '.ui.LauncherUI' } driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) contexts = driver.contexts print(f"Available contexts are {contexts}") if len(contexts) > 1: webview_context = [ctx for ctx in contexts if 'WEBVIEW' in ctx][0] driver.switch_to.context(webview_context) else: print("No WebView found.") # 进一步的操作逻辑... ```
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值