Appium 使用笔记
零、背景
公司最近有个爬虫的项目,先拿小红书下手,但是小红书很多内容 web 端没有,只能用 app 爬,于是了解到 Appium 这个强大的框架,即可以做自动化测试,也可以用来当自动化爬虫。
本文的代码只是一个简单的 spike,没有太多深入的实践。后续如果有深挖,我会来补充的。
一、介绍
Appium
实际上继承了 Selenium(一个流行的 web 浏览器自动化测试框架), 也是利用 Webdriver
来实现 App 的自动化测试。
1、其实 Appium 和 WebDriver 在技术上并不是“测试框架”,而是“自动化库”。
2、WebDriver 已成为自动化Web浏览器的事实标准,并且收录在W3C工作草案里。
Appium是跨平台的:它允许您使用相同的API针对多个平台(iOS,Android,Windows)编写测试。
但是底层,Appium 通过使用供应商提供的自动化框架来满足需求:
- iOS 9.3及以上版本:Apple的 XCUITest
- iOS 9.3及更低版本:Apple的 UIAutomation
- Android 4.2+:Google的 UiAutomator / UiAutomator2
- Android 2.3+:Google的 Instrumentation
- Windows:微软的 WinAppDriver
Appium是开源的。
二、Appium 架构
属于 C/S 架构,包括:
Appium Server
: 是一个用 Node.js 编写的公开的 REST API WEB 服务器。
Appium Client
: 有很多客户端库(Java,Ruby,Python,PHP,JavaScript 和 C#)。
三、安装
此章针对 mac 用户对 android 进行测试。
1、 安装 Appium Server
推荐安装:Appium Desktop ,包含 Appium Server + Appium Client(提供的是 UI 界面化的操作),还有丰富的调试功能。
2、安装 Appium Client
python 开发环境:pip3 install Appium-Python-Client
node.js 开发环境: npm install -g appium
3、安装 Android SDK
1、可以通过安装 android studio
来安装 Android SDK。
下载:https://developer.android.com/studio/index.html?hl=zh-cn
2、添加环境变量
在 ~/.bash_profile (我用的是 zsh,所以是 ~/.zprofile )里添加:
export ANDROID_HOME=/Users/xjnotxj/Library/Android/sdk
export PATH=${PATH}:${ANDROID_HOME}/tools
export PATH=${PATH}:${ANDROID_HOME}/platform-tools
4、验证安装
检验上述的安装是否完备,可以通过 appium-doctor 这个包:npm install -g appium-doctor
appium-doctor --android
# or for ios
appium-doctor --iod
四、使用
1、Appium Client 采用 UI 方式
以我的 三星 s9+ 手机为例。
1、手机用数据线连上电脑,同时打开 USB 调试。
2、启动 appium server,并 start 一个 session(如下图红色箭头)。
3、输入 desired_caps
配置,并点击 start session:
{
"platformName": "android",
"deviceName": "SM_G9650",
"appPackage": "com.tencent.mm",
"appActivity": "ui.LauncherUI",
"noReset": true
}
参数解释:
deviceName:
adb devices -l
命令返回值里的 model 值appPackage / appActivity :获取方法请看:https://www.cnblogs.com/fnng/p/7350900.html
推荐加上
noReset:true
:可以每次测试不重置应用(我的微信聊天记录就是这么没有的……)
4、点击录制按钮
5、使用界面化操作 app
6、结束录制后可支持导出各种编程语言的代码
此次录制的步骤如下:
1、启动小红书
2、点击主页瀑布流的第一个帖子
3、点击底部的喜欢按钮
导出的代码如下:
el3 = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.support.v4.widget.DrawerLayout/android.widget.LinearLayout/android.widget.RelativeLayout/android.support.v4.view.ViewPager/android.widget.LinearLayout/android.widget.FrameLayout/android.support.v4.view.ViewPager/android.widget.FrameLayout/android.view.ViewGroup/android.support.v7.widget.RecyclerView/android.widget.FrameLayout[1]/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.ImageView")
el3.click()
el4 = driver.find_element_by_id("com.xingin.xhs:id/b7f")
el4.click()
2、拓展 - Appium 三种等待元素的方法
Appium 里定位元素是经常的操作,但是有时元素的加载需要时间(如 Ajax 时受到网速的限制),为了避免在元素没有加载好的时候去定位,从而抛出 NoSuchElementException
的异常,下面介绍三种等待元素的方法。
(1) sleep
import time
# 等待10s
time.slee(10)
简单粗暴。
(2) 隐式等待
针对所有元素定义的等待时间。
# focus here
driver.implicitly_wait(10)
……
driver.find_element_by_xpath(…A…)
……
driver.find_element_by_xpath(…B…)
implicitly_wait()
只有一个参数,就是最长等待时间,期间会不断轮询。
implicitly_wait 适用于所有定位元素的函数。
(3) 显式等待
可以针对单个元素定义不同的等待方式。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Remote(server, desired_caps)
# focus here
wait = WebDriverWait(driver, 30)
temp = wait.until(EC.presence_of_element_located(
(By.ID, 'com.xingin.xhs:id/axk')))
temp.click()
1、WebDriverWait()
的参数有四个:
driver:浏览器驱动。
timeout:最长超时时间,默认以秒为单位。
poll_frequency:检测的间隔(步长)时间,默认为 0.5 S。
ignored_exceptions:超时后的异常信息,默认情况下抛 Nosuchelementexception 异常。
2、WebDriverWait() 可以调用 until
/ until_not
。前者是当参数为 True 时才触发,后者是当参数为 False 时触发。
3、expected_conditions
也就是 EC,提供了预期条件判断的方法,比如:
presence_of_element_located : 判断元素是否被加在 DOM 树里,并不代表该元素一定可见
visibility_of_element_located : 判断元素是否可见(可见代表元素非隐藏,并且元素的宽和高都不等于 0)
除此之外还有更多种:
3、Appium Client 采用编码方式
(1) 此次需求
1、打开小红书
2、点击顶部搜索栏,键入想要搜的用户名
3、点击搜出来的第一个用户,进入个人详情页
4、获取此人的 关注数 / 粉丝 / 获赞与收藏
5、获取此人发的所有帖子的 标题/封面/被喜欢数
(2) 重难点
需求1-4很简单,就是定位元素,然后操控元素和获取元素的 attribute 就好。
关于定位元素,优先用 id,没有 id 的时候退而求其次用 xpath。至于 id/xpath 的值,可以用 appium desktop 界面化的去查看,如下图:
重点是需求5,因为用户发的帖子是一个瀑布流,即:
1、内容很长,需要页面往下滑动
解决方案:设置一个 loop,然后一直调用swipe
滚动函数。
2、滑动的过程中会懒加载
解决方案:调用swipe
滚动函数的时候,最后一个参数 duration
值设的大一些,比如个把秒,这样可以让滑动变的较慢,从而边滑动边触发懒加载,让页面顺畅进行。
3、瀑布流的帖子高度不一,参差不齐,可能会取到重复帖子
解决方案:将错就错,就取冗余数据,但用比如 set 这种数据结构来避免数据重复。
4、如何判断内容取尽,滑到底部了?
解决方案:用一个土办法的方法,即始终记录上一次取的数据,跟当前取的数据做对比,如果完全一样,证明页面没变化,则退出 loop。
(3) 注意点
在需求5向下滑动帖子的过程中,有以下几个注意点:
1、每个帖子的 xpath 格式为:
/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.widget.FrameLayout[n
]/……
上面的n
取正整数(即从1开始)。
2、不管怎样向下滑动页面,n
的值不是累加的,而是根据当前显示的仅有帖子重新排列的,如下图。
3、且 appium 是可见即可爬的,所以下图①的帖子内容几乎都被遮住了,会取不到内容。
4、从下图看,一个页面最多只能显示 8 个帖子。
(4) 代码
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException
import time
server = 'http://localhost:4723/wd/hub'
desired_caps = {
"platformName": "android",
"deviceName": "SM_G9650",
"appPackage": "com.xingin.xhs",
"appActivity": "com.xingin.xhs.activity.SplashActivity",
"noReset": True # 可以每次测试不重置应用(我的微信聊天记录就是这么没有的……)
}
# 切换到 unicode 键盘,避免例如中文输入不了的问题
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
driver = webdriver.Remote(server, desired_caps)
driver.implicitly_wait(1)
wait = WebDriverWait(driver, 30)
start = time.time()
print("start")
# 1、目的一:进入个人资料详情页
# 点击搜索框
temp = wait.until(EC.presence_of_element_located(
(By.XPATH, '/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.support.v4.widget.DrawerLayout/android.widget.LinearLayout/android.widget.RelativeLayout/android.support.v4.view.ViewPager/android.widget.LinearLayout/android.widget.LinearLayout/android.widget.FrameLayout[2]/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout')))
temp.click()
# 输入 search text
temp = wait.until(EC.presence_of_element_located(
(By.ID, 'com.xingin.xhs:id/axk')))
temp.set_text("小蒋")
# 点击搜索按钮
temp = wait.until(EC.presence_of_element_located(
(By.ID, 'com.xingin.xhs:id/axn')))
temp.click()
# 切换到用户 tab
temp = wait.until(EC.presence_of_element_located(
(By.XPATH, '/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.view.ViewGroup/android.widget.LinearLayout/android.widget.HorizontalScrollView/android.widget.LinearLayout/android.support.v7.app.a.b[3]')))
temp.click()
# 所有的用户里选择第一个
temp = wait.until(EC.presence_of_element_located(
(By.XPATH, '/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.view.ViewGroup/android.view.ViewGroup/android.widget.FrameLayout/android.view.ViewGroup/android.widget.RelativeLayout[1]')))
temp.click()
# 2、目的二:搜刮想要的信息
# (1)获取用户详情页的总览信息
temp = wait.until(EC.presence_of_element_located(
(By.ID, 'com.xingin.xhs:id/fa')))
temp_n = temp.text
print("关注数:" + str(temp_n))
temp = wait.until(EC.presence_of_element_located(
(By.ID, 'com.xingin.xhs:id/a0h')))
temp_n = temp.text
print("粉丝:" + str(temp_n))
temp = wait.until(EC.presence_of_element_located(
(By.ID, 'com.xingin.xhs:id/ah6')))
temp_n = temp.text
print("获赞与收藏:" + str(temp_n))
# (2)获取此人所有发帖信息
# 定义滑动函数
def swipeDown(value):
# 获取屏幕的高
x = driver.get_window_size()['width']
# 获取屏幕宽
y = driver.get_window_size()['height']
# 滑动页面(最后一个参数设的比较大,防止下拉懒加载的时候打断原有滑动应该有的距离)
driver.swipe(1/2*x, 1/2*y, 1/2*x, value * y, 3000)
# 首先把页面往上拉一些(把总览信息收上去)
swipeDown(0.28)
# 获取用户所有发帖
per_n = 8 # 每次翻页后抓取个数(依据:一个页面最大显示贴子数的个数,包括了显示不全的)
result = set() # 存获取到的帖子(会有重复获取的情况,因此用 set 数据结构)
last_result = "" # 记录上一次翻页获取的数据(为了实现翻到页底退出循环的功能)
while True:
cur_result = "" # 记录当前翻页获取的数据(为了实现翻到页底退出循环的功能)
for i in range(1, per_n + 1):
print("正在获取当前页的第" + str(i) + "个帖子……")
# 获取 img
# 待写:因为普通办法行不通(找不到图片的 src),考虑用截图 api
# 获取 title
# 待写:因为普通办法行不通(很诡异,可见但不可得,元素的 text 属性值是空的),考虑用 OCR api
# 获取被 like 数
try:
temp = driver.find_element_by_xpath('/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.widget.FrameLayout['
+ str(i) +
']/android.widget.LinearLayout/android.widget.LinearLayout[2]/android.widget.RelativeLayout/android.widget.TextView')
like_n = temp.text
# save result (其实最好使用 titile 作为 set 的 key,但是因为获取不到 title,暂时拿 like 数将就下吧)
result.add(like_n)
cur_result = cur_result + str(like_n)
print("第" + str(i) + "个帖子的被 like 数" + " : " + str(like_n))
except NoSuchElementException as e:
# 找不到就不管了(找不到的原因是此帖显示不全)
pass
# 滑动翻页(系数太小已经不好计算了,所以分两次滑动吧)
swipeDown(0.16)
swipeDown(0.16)
# 判断是否滑到底
if(cur_result == last_result):
break
else:
last_result = cur_result
end = time.time()
print("end")
print("total time:")
print(end - start)
print("result:")
print(result)
print 结果:
关注数:283
粉丝:2.0 万
获赞与收藏:7071
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 71
正在获取当前页的第2个帖子……
第2个帖子的被 like 数 : 79
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 57
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 80
正在获取当前页的第5个帖子……
正在获取当前页的第6个帖子……
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 57
正在获取当前页的第2个帖子……
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 134
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 125
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 77
正在获取当前页的第6个帖子……
正在获取当前页的第7个帖子……
第7个帖子的被 like 数 : 128
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 125
正在获取当前页的第2个帖子……
第2个帖子的被 like 数 : 116
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 128
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 116
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 124
正在获取当前页的第6个帖子……
第6个帖子的被 like 数 : 111
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
正在获取当前页的第2个帖子……
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 164
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 170
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 140
正在获取当前页的第6个帖子……
第6个帖子的被 like 数 : 105
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 170
正在获取当前页的第2个帖子……
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 143
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 97
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 93
正在获取当前页的第6个帖子……
第6个帖子的被 like 数 : 171
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 93
正在获取当前页的第2个帖子……
第2个帖子的被 like 数 : 90
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 111
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 73
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 80
正在获取当前页的第6个帖子……
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 73
正在获取当前页的第2个帖子……
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 109
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 87
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 68
正在获取当前页的第6个帖子……
第6个帖子的被 like 数 : 141
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 68
正在获取当前页的第2个帖子……
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 138
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 174
正在获取当前页的第5个帖子……
正在获取当前页的第6个帖子……
第6个帖子的被 like 数 : 109
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 70
正在获取当前页的第2个帖子……
第2个帖子的被 like 数 : 142
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 76
正在获取当前页的第4个帖子……
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 115
正在获取当前页的第6个帖子……
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 81
正在获取当前页的第2个帖子……
第2个帖子的被 like 数 : 74
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 115
正在获取当前页的第4个帖子……
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 101
正在获取当前页的第6个帖子……
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 75
正在获取当前页的第2个帖子……
第2个帖子的被 like 数 : 270
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 131
正在获取当前页的第4个帖子……
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 132
正在获取当前页的第6个帖子……
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 128
正在获取当前页的第2个帖子……
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 109
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 107
正在获取当前页的第5个帖子……
正在获取当前页的第6个帖子……
第6个帖子的被 like 数 : 74
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 64
正在获取当前页的第2个帖子……
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 72
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 77
正在获取当前页的第5个帖子……
正在获取当前页的第6个帖子……
第6个帖子的被 like 数 : 60
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 72
正在获取当前页的第2个帖子……
第2个帖子的被 like 数 : 77
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 60
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 33
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 98
正在获取当前页的第6个帖子……
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
正在获取当前页的第1个帖子……
第1个帖子的被 like 数 : 72
正在获取当前页的第2个帖子……
第2个帖子的被 like 数 : 77
正在获取当前页的第3个帖子……
第3个帖子的被 like 数 : 60
正在获取当前页的第4个帖子……
第4个帖子的被 like 数 : 33
正在获取当前页的第5个帖子……
第5个帖子的被 like 数 : 98
正在获取当前页的第6个帖子……
正在获取当前页的第7个帖子……
正在获取当前页的第8个帖子……
end
total time:
177.27380394935608
result:
{'87 ', '128 ', '97 ', '138 ', '132 ', '81 ', '174 ', '134 ', '33 ', '107 ', '57 ', '80 ', '115 ', '170 ', '171 ', '64 ', '90 ', '60 ', '105 ', '140 ', '164 ', '98 ', '270 ', '125 ', '142 ', '75 ', '68 ', '93 ', '72 ', '131 ', '74 ', '143 ', '116 ', '124 ', '76 ', '77 ', '111 ', '109 ', '79 ', '101 ', '73 ', '70 ', '141 ', '71 '}
(5) 坑
1、搜索框不能输入中文
解决方案:切换到 unicode 键盘。
在desired_caps里加几行配置:
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
有的手机会出现诡异的问题,比如我的 三星 S9+,加了上面的配置后,输入中文的成功率是50%,即隔一次好一次,很规律,原因未知。
解决方案:在系统设置里强制把输入法切换成 unicode 键盘。
2、获取不到帖子的标题
其他的元素获得内容只要获取 text 这个 attrbute 就好了,但偏偏标题不行,这个违背了所看即所爬啊。原因未知。
解决方案:用 OCR 吧。
3、获取不到帖子的封面图
找不到任何关于图的信息。
解决方案:用 截图的 api 吧。
参考资料:
《python 3 网络爬虫开发实战》(主要)
《Selenium 2 自动化测试实战》(一点点)
Appium 使用笔记的更多相关文章
- Appium学习笔记(一)--安装与配置
移动自动化测试常用工具有两个:Appium和Robotium.正好最近自己开始负责客户端的工作,初来乍到需要熟悉下环境,正好学习新的东西. 移动自动化相对web来说,原理与操作过程是一样的,通过自动化 ...
- appium api笔记
打印上下文driver.contexts打印当前上下文driver.contextdriver.current_context切换上下文driver.switch_to.context('WEBVIE ...
- Appium学习笔记4_元素定位方法
Appium之元素定位,如果对Android上如何使用工具获取页面元素有问题的,请转战到这:http://www.cnblogs.com/taoSir/p/4816382.html. 下面主要是针对自 ...
- Appium学习笔记3_Genymotion模拟器安装
如果你已经配置好了安卓的运行环境,也配置好了自带的模拟器AVD,而且也launch了你的安卓模拟器,那么我相信你是不再愿意launch安卓模拟器第二次了,因为实在是太卡了(当然如果你电脑的配置够高,你 ...
- Appium学习笔记2_Android获取元素篇
在利用Appium做自动化测试时,最重要的一步就是获取对应的元素值,根据元素来对对象进行对应的操作,如果获得对象元素呢? Appium Server Console其实提供了一个界面对话框" ...
- appium学习笔记(环境安装配置,设备启动)
Android SDK下载及配置 下载地址 下载后解压缩,打开SDK Manager.exe,下载适当版本的Android包 配置环境变量:目录下的tools路径(含uiautomatorview ...
- Python3+Appium学习笔记09-元素定位android_uiautomator
appium是使用了uiautomator的框架的,所以uiautomator所带的定位方式.appium也是支持的 需要使用appium中find_element_by_android_uiauto ...
- Python3+Appium学习笔记08-元素定位
appium整合了不同的自动化测试驱动程序.而新版本appium desktop 中安卓是使用UI Automator2来作为驱动程序的.以前版本是使用UI Automator1或 Selendroi ...
- Python3+Appium学习笔记07-元素定位工具UI Automator Viewer
这篇主要说下如何使用UI Automator Viewer这个工具来定位元素.这个工具是sdk自带的.在sdk安装目录Tools目录下找到uiautomatorviewer.bat并启动它 如果启 ...
随机推荐
- 《Windows内核安全与驱动开发》 4.4 线程与事件
<Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 4.4 线程与事件 一.开辟一个线程,参数为(打印内容+打印次数),利用线程 ...
- 关于Python的随机数模块,你必须要掌握!
所谓七夕 前几天的文章这个七夕节,用Python为女友绘制一张爱心照片墙吧!收获了最近以来最高的浏览量,没枉费我熬到夜里3点赶出来的热点文章.有付出就总会有所回报,只是看这天来的早晚而已.七夕一个人看 ...
- 基于webpack实现多html页面开发框架五 开发环境配置 babel配置
一.解决什么问题 1.开发环境js.css不压缩,可在浏览器选中代码调试 2.开发环境运行http服务指向打包后的文件夹 3.babel输出浏览器兼容的js代码 二.需要 ...
- NSDateFormatter格式详细列表一览
转自:http://www.cnblogs.com/xinus/archive/2012/10/29/NSDateFormatter_samples.html 前言:iOS开发中NSDateForma ...
- native-base中Input,Textarea等组件在ios平台下不能输入中文
在上文react-native中TextInput在ios平台下不能输入中文已经解决. 但是在native-base中Input和Textarea都存在这样的问题.为了不要写多个组件,封装以下代码: ...
- http状态码_____ 204/206/200
HTTP的状态码有很多种,主要有五个大类 1xx(临时响应) 2xx(成功) 3xx(已重定向) 4xx(请求错误) 5xx(服务器错误) 每个大类还对应一些具体的分类.平时我们接触比较多的是200. ...
- 基于leaflet的标绘功能(一)--可调整的圆
标绘功能是指在电子地图上可以标注点.线.面.复杂多边形等图形.主要操作包括上图.调整(大小.方向.位置).网络存储等.根据具体的业务场景,也可以做到协同标绘等特色功能.其中,要求每个图形有若干关键点控 ...
- CSUOJ1811 Tree Intersection (启发式合并)
Bobo has a tree with n vertices numbered by 1,2,…,n and (n-1) edges. The i-th vertex has color c i, ...
- 合成语音 TTS
弄了一天的合成语音 感觉好难受,明明这么简单的事情非弄得要这么复杂.... 引入命名空间 或者 导入命名空间 代码: using System; using System.Collections.Ge ...
- tensorflow学习笔记——VGGNet
2014年,牛津大学计算机视觉组(Visual Geometry Group)和 Google DeepMind 公司的研究员一起研发了新的深度卷积神经网络:VGGNet ,并取得了ILSVRC201 ...