最近在使用Appium做爬虫功能,网上全是python + Appium的教程,Appium也支持Node.js开发,作为前端工程师使用Node.js + Appium实现了自动化爬虫功能。
零零散散折腾了小两天的时间,踩了一些小坑,把流程和坑点整理出来供大家参考,希望让大家少踩坑、快速实现功能。
我们先搞清楚几个概念,看Appium是如何实现自动操作设备的,结合图片从右往左看:
总结:用Java、Node.js作为客户端调用 Appium服务端接口,Appium通过驱动控制设备,实现自动化操作。
不再一一介绍每个依赖的安装步骤,网上搭建环境的文章很多,主要是如下两点功能:
adb 简介,可以通过数据线或WIFI实现电脑与手机的连接,手机需要打开开发者调试选项,连接成功后,可以通过adb命令操作手机、安装、调试应用。
例如微信:com.tencent.mm 是包名,.ui.launcherUI 是 appActivity,这些参数在后边开发自动化功能时使用。
有两种方式启动服务,一种是安装命令行工具,通过命令行启动;第二种是安装 AppiumDesktop GUI软件启动,任选其一即可,作为前端工程师,首选命令行。
// 安装命令行
$ npm i --location=global appium
// 安装驱动
$ appium driver install uiautomator2
// 启动服务
$ appium
坑点1 不同手机的ADB设置
Appium启动后,会在手机上自动安装3个App,这里有个坑,不同的手机系统开发者选型设置不同,可能会有不同的问题,亲测我的VIVO和OPPO机型,Vivo必须允许三个App为高耗电后台运行,OPPO开发者选项中需要需要开启禁止权限监控,否则无法自动安装App,其他同事出现了App总是重复安装的问题。
小Tips:通过 Appium + 手机品牌 去搜索问题,更高效。
appium inspector官方的GUI界面定位工具,可以通过参数启动App,并将App的画面和页面结构展示出来,以微信为例:填入我们获取到的appPackage 和 appActivity。
坑点2 启动参数务必增加 appium:noReset为true
这里有一个坑需要注意,必须设置appium:noReset参数为true,不然每次启动会清空你的App历史数据,我的微信数据被清理了 🙂。
点击Start Session按钮就可以看到页面的截图、结构和元素的信息了。
如果通过adb连接手机,并通过 appium inspector 成功获取到界面元素,那么恭喜你已经完成了80%的进展,剩下的就是通过Node.js + webdriver.io 开发自动化脚本,App自动跑起来了。
开发前这里我们要掌握webdriver.io的几个基本用法:
webdriver.io 的选择器和jquery的语法很类似,看一个Demo相信你就掌握了。
// 引入lib
const { remote } = require('webdriverio');
// 微信应用启动配置
const capabilities = {
platformName: 'Android',
'appium:automationName': 'UiAutomator2',
'appium:deviceName': 'Android',
'appium:appPackage': 'com.tencent.mm', // 包名
'appium:appActivity': '.ui.LauncherUI', // 启动页
"appium:noReset": true, // 不复位数据
"appium:unicodeKeyboard": false // 隐藏键盘
};
// Appium配置
const wdOpts = {
hostname: process.env.APPIUM_HOST || 'localhost',
port: parseInt(process.env.APPIUM_PORT, 10) || 4723,
logLevel: 'info',
capabilities,
};
// 入口
async function main() {
// 设备实例
const driver = await remote(wdOpts);
try {
// 通过Xpath获取元素
// 单选 类名 + text
const findBtn = await driver.$('//android.widget.TextView[@text="发现"]');
// 单选 类名 + resource-id
const myBtn = await driver.$('//android.widget.ImageView[@resource-id="com.tencent.mm:id/huj"]');
// 多选 + 类名 + resource-id
const commentList = await driver.$$('//android.widget.LinearLayout[@resource-id="com.tencent.mm:id/h1r"]');
// 获取元素 text 属性
const timeSel = await driver.$('//android.widget.ImageView[@resource-id="com.tencent.mm:id/huj"]');
const time = await timeSel.getAttribute('text')
// 点击元素
await findBtn.click()
// 向上滑动 开始坐标 + 滑动时间 + 结束坐标
await driver.touchAction([
{action: 'press', x: 379, y: 2098},
{action: 'wait', ms: '2000'},
{action: 'moveTo', x: 375, y: 606},
'release'
]);
// 暂停 1秒
await driver.pause(1000);
// 保存图片
const avatarSel = await item.$('//android.widget.ImageView[@resource-id="com.tencent.mm:id/a27"]');
await avatarSel.saveScreenshot('./avatar.png');
} finally {
await driver.pause(1000);
await driver.deleteSession();
}
}
main().catch(console.error);
坑点3 滑动操作加时间
webdriver.io的文档中关于滑动操作,并没有提示必须加滑动时间,但实际开发中不加滑动时间,在App上会变成点击 + 滑动操作,经常会出现类似长按的操纵,所以务必加上wait的参数。
坑点4 键盘会被隐藏
unicodeKeyboard设置为false会将你的手机输入法关掉,重新启动输入法应用就可以了,还没研究清楚unicodeKeyboard参数的意义,大家实践后可以补充下。
掌握选择器和操作语法后,前端工程师就能很快的实现自己的功能了,下边的截图是爬取我的微信视频号中的评论数据。
我们再回顾下:
采坑:
最后,爬虫有风险,大家不要做违法违规的事,我是前端工程师秦少卫,不到之处恳请斧正,欢迎大家点赞关注评论,我们一起成长。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。