最新消息:20210917 已从crifan.com换到crifan.org

【已解决】Mac中用uiautomator2自动操作安卓手机浏览器实现百度搜索

Mac crifan 398浏览 0评论
之前已经弄完了:
  • PC桌面端
    • Selenium
      • 【已解决】Mac中用Selenium自动操作浏览器实现百度搜索
    • puppeteer
      • 【已解决】Mac中用puppeteer自动操作浏览器实现百度搜索
    • Playwright
      • 【已解决】Mac中用playwright自动操作浏览器实现百度搜索
现在继续去弄:
  • 移动端
    • 安卓
      • uiautomator2
    • iOS
      • facebook-wda
先去看看 安卓的uiautomator2
此处安卓测试手机是:红米Note10X
之前已初始化过uiautomator2环境。
现在去搭建Mac环境,去写代码,调试,实现自动化百度搜索。
先去:
【已解决】Mac中初始化安卓手机红米Note10X的uiautomator2开发环境
接着去考虑,如何自动化百度搜索。
先要确定用哪个浏览器。
此处,去看了看,当前安卓手机中有多个浏览器:
一个小米自带的
一个QQ浏览器
其他还有:
  • Edge
  • UC浏览器
先要知道app的包名才行,后续才能操作,比如启动app
【已解决】搞清楚安卓手机中多款浏览器应用的包名
小米自带浏览器
包名是:com.android.browser
从包名看,感觉算是:安卓原生浏览器
此处决定用 小米自带浏览器去模拟百度搜索
然后就去写代码即可
参考自己教程
安卓自动化测试利器:uiautomator2
https://book.crifan.com/books/android_automation_uiautomator2/website/
APP · 安卓自动化测试利器:uiautomator2 (crifan.com)
openatx/uiautomator2: Android Uiautomator2 Python Wrapper (github.com)
启动app:
Browser_XiaomiBuiltin = "com.android.browser"


browserPackage = Browser_XiaomiBuiltin
# d.app_start(browserPackage)
d.app_start(browserPackage, stop=True)
即可启动浏览器app
继续打开页面:百度首页
【已解决】用uiautomator2操作安卓浏览器打开百度首页
然后再去加上确保页面加载了
去找必然出现的元素,去等待出现
Prop    Value
activity    .BrowserActivity
package    com.android.browser
className    android.widget.EditText
description    
text    百度一下
resourceId    com.android.browser:id/bq3
clickable    true
label    
x, y    160, 83
width    659
height    112
enabled    true
visible    
XPath    //*[@resource-id="com.android.browser:id/bq3"]
position     (0.275, 0.064) 点击
代码 d(resourceId="com.android.browser:id/bq3")
用代码:
# wait util baidu home loaded
d(text="百度一下", resourceId="com.android.browser:id/bq3").exists(timeout=10)
print("Baidu home loaded")
即可。
继续去:
【已解决】用uiautomator2给安卓浏览器中百度首页中输入文字并触发搜索
继续去:
【已解决】uiautomator2模拟安卓浏览器的百度搜索后去获取和解析搜索结果
【总结】
最终用代码:
# Function: uiautomator2 demo baidu search
# Author: Crifan Li
# Update: 2020409


import time
import uiautomator2 as u2


d = u2.connect() # connect to device
print("d.info=%s" % d.info)
# d.info={'currentPackageName': 'com.android.browser', 'displayHeight': 2201, 'displayRotation': 0, 'displaySizeDpX': 393, 'displaySizeDpY': 873, 'displayWidth': 1080, 'productName': 'atom', 'screenOn': True, 'sdkInt': 29, 'naturalOrientation': True}


################################################################################
# Launch browser
################################################################################
Browser_XiaomiBuiltin = "com.android.browser"
browserPackage = Browser_XiaomiBuiltin
# d.app_start(browserPackage)
d.app_start(browserPackage, stop=True)


# wait util browser launch complete -> appear 我的 tab
# MustShowTabName = "主页"
MustShowTabName = "我的"
# d(text=MustShowTabName).exists(timeout=10)
d(text=MustShowTabName, packageName=browserPackage).exists(timeout=10)
print("Browser homepage loaded")


################################################################################
# Open baidu homepage
################################################################################


# # open new window
# windowUiObj = d(resourceId="com.android.browser:id/dm")
# windowUiObj.click()


# # click add to new window
# addNewWindowUiObj = d(resourceId="com.android.browser:id/akr")
# addNewWindowUiObj.click()


# for debug
# curPageXml = d.dump_hierarchy(compressed=False, pretty=False)
# print("curPageXml=%s" % curPageXml)


# find input box inside address bar


# # Method 1: use driver pass in parameter
# inputUiObj = d(resourceId="com.android.browser:id/b4h", className="android.widget.TextView")
# # inputUiObj = d(resourceId="com.android.browser:id/b4h")
# print("type(inputUiObj)=%s" % type(inputUiObj)) # type(inputUiObj)=<class 'uiautomator2.session.UiObject'>
# print("inputUiObj=%s" % inputUiObj) # inputUiObj=<uiautomator2.session.UiObject object at 0x10a0bea00>
# inputUiObjectInfo = inputUiObj.info
# print("type(inputUiObjectInfo)=%s" % type(inputUiObjectInfo)) # type(inputUiObjectInfo)=<class 'dict'>
# print("inputUiObjectInfo=%s" % inputUiObjectInfo) # inputUiObjectInfo={'bounds': {'bottom': 172, 'left': 160, 'right': 797, 'top': 107}, 'childCount': 0, 'className': 'android.widget.TextView', 'contentDescription': '搜索框', 'packageName': 'com.android.browser', 'resourceName': 'com.android.browser:id/b4h', 'text': '', 'visibleBounds': {'bottom': 172, 'left': 160, 'right': 797, 'top': 107}, 'checkable': False, 'checked': False, 'clickable': True, 'enabled': True, 'focusable': False, 'focused': False, 'longClickable': False, 'scrollable': False, 'selected': False}
# isFoundInput = inputUiObj.exists # True


# # Method 2: use xpath
# inputXpathSelector = d.xpath("//android.widget.TextView[@resource-id='com.android.browser:id/b4h']")
# # inputXpathSelector = d.xpath("//*[@resource-id='com.android.browser:id/b4h']")
# print("type(inputXpathSelector)=%s" % type(inputXpathSelector)) # type(inputXpathSelector)=<class 'uiautomator2.xpath.XPathSelector'>
# inputXpathElem = inputXpathSelector.get()
# print("type(inputXpathElem)=%s" % type(inputXpathElem)) # type(inputXpathElem)=<class 'uiautomator2.xpath.XMLElement'>
# print("inputXpathElem=%s" % inputXpathElem) # inputXpathElem=<uiautomator2.xpath.XMLElement object at 0x108585d30>
# print("type(inputXpathElem.attrib)=%s" % type(inputXpathElem.attrib)) # type(inputXpathElem.attrib)=<class 'lxml.etree._Attrib'>
# print("inputXpathElem.attrib=%s" % inputXpathElem.attrib) # inputXpathElem.attrib={'index': '1', 'text': '', 'resource-id': 'com.android.browser:id/b4h', 'package': 'com.android.browser', 'content-desc': '搜索框', 'checkable': 'false', 'checked': 'false', 'clickable': 'true', 'enabled': 'true', 'focusable': 'false', 'focused': 'false', 'scrollable': 'false', 'long-clickable': 'false', 'password': 'false', 'selected': 'false', 'visible-to-user': 'true', 'bounds': '[160,107][797,172]'}
# isFoundInput = inputXpathSelector.exists # True


# trigger into input page


# Method 1
inputUiObj = d(resourceId="com.android.browser:id/b4h", className="android.widget.TextView")
inputUiObj.click()
print("Clicked search box")


# # Method 2
# inputXpathSelector = d.xpath("//android.widget.TextView[@resource-id='com.android.browser:id/b4h']")
# inputXpathSelector.click()


# input baidu homr url
BaiduHomeUrl = "https://www.baidu.com/"
searchUiObj = d(resourceId="com.android.browser:id/bq3", className="android.widget.EditText")
searchUiObj.set_text(BaiduHomeUrl)
print("Inputed baidu homepage url: %s" % BaiduHomeUrl)


# trigger jump to baidu home
EnterKey = "enter"
d.press(EnterKey)
print("Emulated press key %s" % EnterKey)


# wait util baidu home loaded
d(text="百度一下", resourceId="com.android.browser:id/bq3").exists(timeout=10)
print("Baidu home loaded")


################################################################################
# Input text
################################################################################
searchStr = "crifan"


baiduSearchKeywordUiObj = d(resourceId="index-kw", className="android.widget.EditText")
baiduSearchKeywordUiObj.set_text(searchStr)
print("Inputed baidu search text %s" % searchStr)


################################################################################
# Trigger baidu search
################################################################################


# # Method 1: press key
# TriggerSearchKey = "enter" # work
# # TriggerSearchKey = "search" # not work
# # TriggerSearchKey = "go" # not work
# # TriggerSearchKey = "done" # not work
# d.press(TriggerSearchKey)
# print("Emulated press key %s" % TriggerSearchKey)


# Method 2: find 百度一下 button then click
baiduSearchButtonUiObj = d(resourceId="index-bn", className="android.widget.Button")
baiduSearchButtonUiObj.click()
print("Clicked baidu search button")


################################################################################
# Extract search result content
################################################################################


# Special: for fixbug of get page xml is not latest, so using following code to refresh to get latest page source xml
d.service("uiautomator").stop()
d.service("uiautomator").start()
# time.sleep(1)


# for debug
# get page source xml
# curPageXml = d.dump_hierarchy(compressed=False, pretty=False)
# print("curPageXml=%s" % curPageXml)
# with open("baidu_search_%s_result_pageSource_reloaded.xml" % searchStr, "w") as fp:
#     fp.write(curPageXml)


d(resourceId="results").exists(timeout=10)


# Note: following syntax can NOT find elements
# resultsSelector = d.xpath("//*[@resource-id='results']")
# titleButtonSelectorList = resultsSelector.xpath("//android.widget.Button[@clickable='true']").all()
# titleButtonSelectorList = resultsSelector.xpath(".//android.widget.Button[@clickable='true']").all()


# Xpath chain search can find elements
titleButtonElementList = d.xpath("//*[@resource-id='results']//android.widget.Button[@clickable='true']").all()
titleButtonNum = len(titleButtonElementList)
print("Found %s search result title" % titleButtonNum)


# descriptionElementList = d.xpath("//*[@resource-id='results']/android.view.View[1]/android.view.View[1]/android.view.View[2]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]").all()
descriptionElementList = d.xpath("//*[@resource-id='results']/android.view.View/android.view.View[1]/android.view.View[2]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]/android.view.View[1]").all()
descriptionNum = len(descriptionElementList)
print("Found %s description" % descriptionNum)


# # sourceWebsiteElementList = d.xpath('//*[@resource-id="results"]/android.view.View/android.view.View[1]/android.view.View[2]/android.view.View[1]').all()
# sourceWebsiteElementList = d.xpath('//*[@resource-id="results"]/android.view.View/android.view.View[1]/android.view.View[2]/android.view.View[2]').all()
# sourceWebsiteNum = len(sourceWebsiteElementList)
# print("Found %s source website" % sourceWebsiteNum)


for curIdx, eachTitleButtonElement in enumerate(titleButtonElementList):
    curNum = curIdx + 1
    print("%s  [%d/%d] %s" % ("-"*20, curNum, titleButtonNum, "-"*20))
    # eachTitleButtonElemAttrib = eachTitleButtonElement.attrib
    # print("title attrib: %s" % eachTitleButtonElemAttrib)
    # curTitle = eachTitleButtonElemAttrib["text"]
    curTitle = eachTitleButtonElement.text
    print("title=%s" % curTitle)


    curDescriptionElem = descriptionElementList[curIdx]
    curDescription = curDescriptionElem.text
    print("description=%s" % curDescription)


    # curSourceWebsiteElem = sourceWebsiteElementList[curIdx]
    # curSourceWebsite = curSourceWebsiteElem.text
    # print("curSourceWebsite=%s" % curSourceWebsite)


print()
实现了:
打开安卓中浏览器,进入首页
输入百度首页地址,进入百度首页
给输入框中输入crifan,并触发搜索
等待页面加载完毕
(由于手机屏幕有限,当前页面只显示了3个搜索结果)
获取并解析每一条的标题title和description描述
并打印输出
输出是:
d.info={'currentPackageName': 'com.android.browser', 'displayHeight': 2201, 'displayRotation': 0, 'displaySizeDpX': 393, 'displaySizeDpY': 873, 'displayWidth': 1080, 'productName': 'atom', 'screenOn': True, 'sdkInt': 29, 'naturalOrientation': True}
Browser homepage loaded
Clicked search box
Inputed baidu homepage url: https://www.baidu.com/
Emulated press key enter
Baidu home loaded
Inputed baidu search text crifan
Clicked baidu search button
[D 210409 23:03:10 __init__:764] restart-uiautomator since "UiAutomation not connected"
[D 210409 23:03:11 __init__:817] Device: Redmi, orga4pmzee4ts47t
[D 210409 23:03:11 __init__:823] stop app: com.github.uiautomator
[D 210409 23:03:11 __init__:827] kill process(ps): uiautomator
[D 210409 23:03:11 __init__:840] uiautomator-v2 is starting ... left: 40.0s
[D 210409 23:03:12 __init__:840] uiautomator-v2 is starting ... left: 39.0s
[D 210409 23:03:13 __init__:840] uiautomator-v2 is starting ... left: 38.0s
[D 210409 23:03:14 __init__:840] uiautomator-v2 is starting ... left: 36.9s
[D 210409 23:03:15 __init__:840] uiautomator-v2 is starting ... left: 35.9s
[D 210409 23:03:16 __init__:840] uiautomator-v2 is starting ... left: 34.9s
[D 210409 23:03:17 __init__:840] uiautomator-v2 is starting ... left: 33.8s
[I 210409 23:03:17 __init__:784] uiautomator back to normal
Found 3 search result title
Found 3 description
--------------------  [1/3] --------------------
title=在路上on the way - 走别人没走过的路,让别人有路可走
description=crifan 4周前 (03-09) 177浏览 0评论 google 收录查询谷歌收录查询,如何让Google收录网站 – 云...
--------------------  [2/3] --------------------
title=crifan简介 - crifan的专栏 - CSDN博客 - crifan
description=2020年2月15日crifan简介 各种计算机语言简介和总结 v1.0 08-03 本文主要介绍了各种计算机语言的分类和关系,以及记录了笔者对其中部分语言,如Word VBA,Excel...
--------------------  [3/3] --------------------
title=crifan - Bing 词典 - 必应
description=crifan网络目录;下午;我个人 网络释义 1. 目录 如何实现Linux下的U盘驱动 v0.4 -... ... Specification 规范 crifan 目录 Mass Storage ...
效果:
【后记20210417】
没过几天,发现 浏览器的输入框的id变了:
从之前的:
com.android.browser:id/b4h
变成:
com.android.browser:id/b4w
导致之前代码:
inputUiObj = d(resourceId="com.android.browser:id/b4h", className="android.widget.TextView")
报错。
所以去改为:
inputUiObj = d(resourceId="com.android.browser:id/b4w", className="android.widget.TextView")
即可。

转载请注明:在路上 » 【已解决】Mac中用uiautomator2自动操作安卓手机浏览器实现百度搜索

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
92 queries in 0.176 seconds, using 23.38MB memory