当前位置: 首页 > news >正文

手机群控爬取实战

准备工作

准备多部手机,或者模拟器然后将它们于与电脑连接,然后通过 adb 命令查看连接状态

模拟器设置链接: 写文章-CSDN创作中心

安装一个库: pip install adbutils

测试是否链接

输入 adb devices 

如果结果中的第二列显示的不是 device 则有可能手机没设置好

或者 结束 adb 进程  adb kill-server

重新输入  adb devices  尝试几次

群控

群控,其实就是同时控制,具体到实现上就是新建多个进程,让它们同时执行一个逻辑,第一步为了能访问到已连接的多部手机, 我们使用 adbutils  命令替代 adb  命令

import adbutilsadb = adbutils.AdbClient(host="127.0.0.1", port=5037)
print(adb.device_list())

[AdbDevice(serial=127.0.0.1:62001), AdbDevice(serial=127.0.0.1:7555), AdbDevice(serial=emulator-5554)]

可以看到这里返回了一个列表, 列表中的每个元素都是 AdbDevice 对象, 这个 AdbDevice 对象包含一个 serial 属性, 代表设备序列号, 这和运行 adb devices 命令获取的结果一致

群控实战

新建一个类 Controller (这是对上一节内容的封装)初始化一些内容

class Controller(object):def __init__(self, device_name, package_name, apk_path, need_reinstall=False):self.device_name = device_nameself.package_name = package_nameself.apk_path = apk_pathself.need_reinstall = need_reinstall

对于群控,需要批量实现一些操作, 包括初始化设备和安装 apk 安装包等。所以这里在构造方法中声明了 4 个参数

device_name : 刚才使用 adb devices 命令获取的各个设备的序列名称

package_name : 包名

apk_path:  安装包文件路径,这个参数是为安装所用的, 因为很多手机可能没有安装过安装包,所以用该参数来指定安装包的路径

need_reinstall : 是否需要重装安装包,因为有时候不需要重装,所以预留该参数来控制是否需要重装

然后添加一些常用的初始化方法

注意: 这里在 __init__ 中新加了两个初始化内容

from airtest.core.api import *
from poco.drivers.android.uiautomation import  AndroidUiautomationPococlass Controller(object):def __init__(self, device_uri, device_name, package_name, apk_path, need_reinstall=False, need_restart=False):self.device_uri = device_uriself.device_name = device_nameself.package_name = package_nameself.apk_path = apk_pathself.need_reinstall = need_reinstallself.need_restart = need_restartdef connect_device(self):self.device = connect_device(self.device_uri)def install_app(self):if self.device.check_app(self.package_name) and not self.need_reinstall:return self.device.uninstall_app(self.package_name)self.device.install_app(self.apk_path)def start_app(self):if self.need_restart:self.device.stop_app(self.package_name)self.device.start_app(self.package_name)def init_device(self):self.connect_device()self.poco = AndroidUiautomationPoco(self.device)self.window_width, self.window_height = self.poco.get_screen_size()self.install_app()self.start_app()

下面介绍一下添加的几个方法

connect_device : 里面直接调用了 Airtest 的 connect_device 方法,需要传入一个参数 device_uri  ,会返回一个 device 对象, 这里其实是 airtest.core.android.android.Anfroid 对象,并将该对象赋值给全局变量 device

install_app : 里面使用 device 变量的 check_app 方法检查 App 有没有安装,使用 need_reinstall 方法检查是否需要重装 App,  只有在 App 已经安装切不需要重装的时候才不做任何操作。在其他情况下,则需要重装这个 App 。先使用 uninstall_app 卸载 App, 在通过 install_app 安装。

start_app : 里面使用 need_restart 判断是否需要重启 App , 如果需要,就先停止 app 再启用, 否则直接启用

init_device : 这是一个初始化方法,里面先调用 connect_device 方法链接了设备,接着将 device 对象传给 AndroidUiatomationPoco 构造了一个 poco 对象,然后获取了一些基础参数,例如 window 屏幕的宽高, 最后调用 install_app 和 start_app 方法完成了 App 的安装和启动。

到这里其实我们就能控制手机安装和重启 app 了, 下面继续往 Controller 类中添加两个方法

def scroll_up(self):self.device.swipe((self.window_width * 0.5, self.window_height * 0.8),(self.window_width * 0.5, self.window_height * 0.3), duration=1)def run(self):for _ in range(10):self.scroll_up()

添加的方法一个是 scroll_up , 里面调用了 device 对象的 swipe 方法,另一个是 run , 里面调用了10 次上滑操作。 下面在实现一个总调用方法

scrape-app5.apk 的下载地址 : https://app5.scrape.center

PACKAGE_NAME = 'com.goldze.mvvmhabit'
APK_PATH = 'scrape-app5.apk'def run(device_uri):controller = Controller(device_uri=device_uri, package_name=PACKAGE_NAME,apk_path=APK_PATH, need_reinstall=False,need_restart=True)controller.init_device()controller.run()

注意这里的 scrape-app5.apk 需要下载下来,和当前代码放在同一个文件夹下,这样安装 apk 的时候才能找到对应的安装包。最后完善一下群控的逻辑调用即可

from multiprocessing import Processif __name__ == '__main__':processes = []adb = adbutils.AdbClient(host='127.0.0.1', port=5037)for device in adb.device_list():device_name = device.serialdevice_uri = f'Android:///{device_name}'p = Process(target=run, args=[device_uri])processes.append(p)p.start()for p in processes:p.join()

这里我们就是使用了多进程实现了手机群控, 一个爬取进程对应一个 Process 进程, 声明进程的时候直接指定目标方法为 run , 参数就设置为 设备的连接字符串,格式为 Android:///{device_name} , 例如  Android:///emulator-5554

在本节案例中,由于我们链接了三部手机,所以就新建了三个进程,它们同时执行数据爬取操作,运行代码后可以发现三部手机同时运行着爬取流程

关于爬取数据的流程代码

写文章-CSDN创作中心

最后需要,自己手动将两个方法进行整理才能最终实现爬取

关于商业级群控系统参考: https://setup.scrape.center/multi-control  

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 数据结构与算法--插入排序与选择排序
  • Upload-Lab第11关:如何巧妙使用双写绕过黑名单验证
  • 大模型智能体可以用来实现哪些需求?
  • 防火墙技术与地址转换
  • 服务器主要有什么用途?什么情况下需要服务器?
  • xss GAME (xss漏洞攻击1-8)
  • 一套完整的NVR方案与部分NVR录像机GUI源码剖析
  • HTTPS 详解
  • 内网安全:跨域攻击
  • CVE-2024-34982 LyLme Spage六零导航页 任意文件上传漏洞漏洞分析
  • 【初阶数据结构题目】34. 冒泡排序
  • 【LeetCode】433.最小基因变化
  • Git 命令常用
  • linux之prometheus+grafana
  • 报错解决——苹果电脑mac装windows10,总是提示“启动转换”安装失败:拷贝Windows安装文件时出错
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • Git初体验
  • webgl (原生)基础入门指南【一】
  • windows-nginx-https-本地配置
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 创建一种深思熟虑的文化
  • 力扣(LeetCode)357
  • 模型微调
  • 让你的分享飞起来——极光推出社会化分享组件
  • 深入浏览器事件循环的本质
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 我看到的前端
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 源码安装memcached和php memcache扩展
  • 如何在招聘中考核.NET架构师
  • # 数仓建模:如何构建主题宽表模型?
  • #QT(智能家居界面-界面切换)
  • $ git push -u origin master 推送到远程库出错
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (6) 深入探索Python-Pandas库的核心数据结构:DataFrame全面解析
  • (BFS)hdoj2377-Bus Pass
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (分享)自己整理的一些简单awk实用语句
  • (原創) 未来三学期想要修的课 (日記)
  • (转)3D模板阴影原理
  • (转)nsfocus-绿盟科技笔试题目
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • .Net 高效开发之不可错过的实用工具
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • .NetCore 如何动态路由
  • .Net的C#语言取月份数值对应的MonthName值
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • /dev/sda2 is mounted; will not make a filesystem here!
  • ?.的用法
  • [000-01-018].第3节:Linux环境下ElasticSearch环境搭建
  • [20160807][系统设计的三次迭代]
  • [APIO2012] 派遣 dispatching