Code de démarrage (pré-code)
# 导模块
from appium import webdriver
# 创建一个字典,包装相应的启动参数
desired_caps = dict()
# 需要连接的手机的平台(不限制大小写)
desired_caps['platformName'] = 'Android'
# 需要连接的手机的版本号(比如 9.2.1 的版可以填写9.2.1或9.2或9,以此类推)
desired_caps['platformVersion'] = '9'
# 需要连接的手机的设备号(andoird平台下,可以随便写,但是不能不写)
desired_caps['deviceName'] = '192.168.56.101:5555'
# 需要启动的程序的包名
desired_caps['appPackage'] = '启动的包名'
# 需要启动的程序的界面名
desired_caps['appActivity'] = '启动的界面名'
# 文本框输入中文时要用
desired_caps['unicodeKeyboard'] = True
desired_caps['resetKeyboard'] = True
# 连接appium服务器,获取driver
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
# 退出driver
driver.quit()
Processus de démarrage :
Remarque : Le démarrage d'appium démarre en fait un service utilisant le port 4723 sur cette machine
- Le code python accédera au serveur Appium local et obtiendra l'objet pilote
- Appium convertira la méthode appelée par notre objet pilote en une requête de publication et la soumettra au serveur appium
- Appium l'envoie au téléphone mobile via la demande de publication reçue, puis le téléphone mobile l'exécute
1. Démarrez d'autres applications dans le script
Scénario d'application : si une application doit passer à une autre application, vous pouvez utiliser cette API pour passer à l'application, tout comme nous passerons à l'application de paiement après avoir passé une commande via l'application de livraison de nourriture
méthode:
# 参数:
# appPackage:要打开的程序的包名
# appActivity:要打开的程序的界面名
driver.start_activity(appPackage, appActivity)
2. Obtenez le nom du package et le nom de l'interface de l'application
Scénario d'application : lorsque nous passons d'une application à une autre, si nous voulons afficher son nom de package, son nom d'interface ou afficher les informations correspondantes dans le rapport, nous pouvons appeler cette propriété pour l'obtenir.
méthode:
# 获取包名
driver.current_package
# 获取界面名
driver.current_activity
3. Fermez l'application et conduisez l'objet
Scénario d'application : Parfois, nous devons fermer une application avant d'ouvrir une nouvelle application
méthode:
# 关闭当前操作的app,不会关闭驱动对象
driver.close_app()
# 关闭驱动对象,同时关闭所有关联的app
driver.quit()
4. Installer et désinstaller et s'il faut installer l'application
Scénario d'application : certains logiciels du marché des applications peuvent avoir un bouton, si un certain programme est installé, il sera désinstallé, s'il n'est pas installé, il sera installé
méthode:
# 安装app
# 参数:
# app_path:apk路径
driver.install_app(app_path)
# 卸载app
# 参数:
# app_id:应用程序包名
driver.remove_app(app_id)
# 判断app是否已经安装
# 参数:
# app_id:应用程序包名
# 返回值:
# 布尔类型,True为安装,False为没有安装
driver.is_app_installed(app_id)
5. Mettez l'application en arrière-plan
Scénario d'application : les applications bancaires entreront en arrière-plan pendant un certain temps, et si elles reviennent au premier plan, la page entrera à nouveau le mot de passe. Si vous avez besoin de tester cette fonction automatiquement, vous pouvez utiliser cette API pour tester
méthode:
# app放置到后台一定时间后再回到前台,模拟热启动
# 参数:
# seconds:后台停留多少秒
driver.background_app(seconds)
Démarrage à chaud : signifie entrer en arrière-plan et revenir au premier plan. Le comportement de coupure de l'alimentation électrique en l'éteignant et en la rallumant peut être appelé "démarrage à froid".
6. Positionnement des éléments
Scénario d'application : Il est nécessaire d'obtenir des éléments par positionnement d'éléments, afin que l'ordinateur puisse nous aider à "faire fonctionner" cet élément
Acquisition de valeur d'attribut d'élément : peut être obtenue via l'outil uiautomatorviewer dans le répertoire Android SDK installé
Localisation d'une méthode d'élément :
- localiser un élément par identifiant
# 参数:
# id_value:元素的resource-id属性值
# 返回值:
# 定位到的单个元素
driver.find_element_by_id(id_value)
- Localiser un élément par class_name
# 参数:
# class_value:元素的class属性值
# 返回值:
# 定位到的单个元素
driver.find_element_by_class_name(class_value)
- localiser un élément par xpath
# 参数:
# xpath_value:定位元素的xpath表达式
# 返回值:
# 定位到的单个元素
driver.find_element_by_xpath(xpath_value)
Méthode de localisation d'un groupe d'éléments :
- Localiser un groupe d'éléments par identifiant
# 参数:
# id_value:元素的resource-id属性值
# 返回值:
# 列表,定位到的所有符合调价你的元素
driver.find_elements_by_id(id_value)
- Localiser un groupe d'éléments par class_name
# 参数:
# class_value:元素的class属性值
# 返回值:
# 列表,定位到的所有符合调价你的元素
driver.find_elements_by_class_name(class_value)
- Localisation d'un ensemble d'éléments via xpath
# 参数:
# xpath_value:定位元素的xpath表达式
# 返回值:
# 列表,定位到的所有符合调价你的元素
driver.find_elements_by_xpath(xpath_value)
point important:
1. Le positionnement des éléments est basé sur les éléments visibles affichés dans la plage d'écran actuelle.
2. Si vous utilisez la méthode find_element_by_xx, si vous transmettez une fonctionnalité qui n'existe pas, une erreur NoSuchElementException sera signalée.
3. Si vous utilisez la méthode find_elements_by_xx, si vous transmettez une fonctionnalité qui n'existe pas, aucune erreur ne sera signalée et une liste vide sera renvoyée.
7. Elément en attente
Scénario d'application : pour des raisons de vitesse du réseau, des demandes de traitement du serveur, des raisons de configuration de l'ordinateur, etc., l'élément que nous recherchons n'apparaît pas immédiatement. À ce stade, si nous le localisons directement, une erreur peut être signalée.
Classification : attente implicite et attente explicite
(1) Attente implicite
Périmètre d'action : opérations sur tous les éléments positionnés (valable globalement)
méthode:
# 参数:
# timeout:超时的时长,单位:秒
implicitly_wait(timeout)
(2) Affichage en attente
Champ d'action: l'opération pour un certain élément de positionnement (simple efficace)
méthode:
# 导入显示等待包
from selenium.webdriver.support.wait import WebDriverWait
# 参数:
# driver:驱动对象
# timeout:超时的时长,单位:秒
# poll_frequency:检测间隔时间,默认为0.5秒
# method:lambda查找元素表达式
# 返回值:
# 定位到的元素,如果没有定位到会抛出TimeoutException异常
element = WebDriverWait(driver, timeout, poll_frequency=0.5).until(method)
8. Cliquez sur l'élément
Scénario d'application : à utiliser lorsque vous devez cliquer sur un bouton
méthode:
# 对element按钮进行点击操作
element.click()
9. Entrez et effacez le contenu de la zone de saisie
Scénario d'application : utilisé lorsque la zone de saisie doit être saisie ou effacée
méthode:
# 对element输入框进行输入操作
# 参数:
# value:输入的内容
element.send_keys(value)
# 对element输入框进行输入操作
element.clear()
Points à noter : L'entrée chinoise par défaut n'est pas valide, mais aucune erreur ne sera signalée. Ces deux paramètres doivent être inclus dans le "pré-code"
desired_caps['unicodeKeyboard'] = True
desired_caps['resetKeyboard'] = True
10. Obtenir le contenu textuel de l'élément
Scénario d'application : utilisé lorsqu'il est nécessaire d'obtenir le contenu textuel de contrôles tels que des boutons, des zones de texte et des zones de saisie
méthode:
# 获取element控件的文本内容
# 返回值:
# 控件的文本内容
element.text
11. Obtenir la position et la taille de l'élément
Scénario d'application : à utiliser lorsque vous avez besoin d'obtenir la position et la taille de l'élément
méthode:
# 获取element的位置
# 返回值:
# 字典,x为元素的x坐标,y为元素的y坐标
element.location
# 获取element的大小
# 返回值:
# 字典,width为宽度,height为告诉
element.size
12. Obtenir la valeur d'attribut de l'élément
Scénario d'application : après avoir localisé un élément en fonction de ses caractéristiques, faire en sorte que le nom d'attribut de l'élément obtienne la valeur d'attribut correspondante
méthode:
# 获取element的属性值
# 参数:
# value:要获取的属性名
# 返回值:
# 根据属性名得到的属性值
element.get_attribute(value) # value:元素的属性
point important:
value='text' renvoie la valeur d'attribut du texte
value='name' renvoie la valeur de l'attribut content-desc/text
value='className' renvoie la valeur de l'attribut de classe, seule l'API=>18 peut la prendre en charge
value='resourceId' renvoie la valeur de l'attribut resource-id, seule l'API=>18 peut prendre en charge
13. Faites glisser et faites glisser les événements
Scénario d'application : certains boutons n'apparaîtront qu'après avoir fait glisser l'écran plusieurs fois. À ce stade, nous devons utiliser du code pour simuler le glissement des doigts.
Catégorie : événement de glissement par balayage, événement de défilement par glissement, événement de glissement par glisser-déposer
(1) événement de glissement de balayage
Concept : le glissement d'une position de coordonnées à une autre position de coordonnées ne peut être qu'un glissement entre deux points (l'inertie change en fonction du temps)
méthode:
# 参数:
# start_x: 起点X轴坐标
# start_y: 起点Y轴坐标
# end_x: 终点X轴坐标
# end_y: 终点Y轴坐标
# duration: 滑动这个操作一共持续的时间长度,单位:ms
driver.swipe(start_x, start_y, end_x, end_y, duration=None)
Pour une même distance, plus la durée est longue, plus l'inertie est faible
Lorsque la durée est la même, plus la distance de glissement du doigt est grande, plus la distance de glissement réelle est grande
(2) événement de glissement de défilement
Concept : Swipe d'un élément à l'autre jusqu'à l'arrêt automatique de la page (forte inertie)
méthode:
# 参数:
# origin_el: 滑动开始的元素
# destination_el: 滑动结束的元素
driver.scroll(origin_el, destination_el)
(3) événement de glisser drag_and_drop
Concept : glissez d'un élément à l'autre, le deuxième élément remplace la position d'origine sur l'écran du premier élément (pas d'inertie)
méthode:
# 参数:
# origin_el: 滑动开始的元素
# destination_el: 滑动结束的元素
driver.drag_and_drop(origin_el, destination_el)
14. Geste avancé TouchAction
Scénario d'application : TouchAction peut implémenter certaines opérations orientées vers les gestes, telles que glisser, appuyer longuement, faire glisser, etc. On peut combiner ces gestes de base en un geste relativement complexe. Par exemple, nous déverrouillons les téléphones portables ou certains logiciels d'application ont des méthodes de déverrouillage gestuel.
Étapes d'utilisation :
- 1. Créer un objet TouchAction
- 2. Appelez le geste que vous souhaitez effectuer à travers l'objet
- 3. Exécuter des actions via perform()
(1) Fonctionnement du robinet
Concept : Simuler un doigt appuyant sur un élément ou une coordonnée et le soulevant rapidement
méthode:
# 参数:
# element:元素
# x:x坐标
# y:y坐标
TouchAction(driver).tap(element=None, x=None, y=None).perform()
Remarque : Vous pouvez choisir l'un des éléments et coordonnées. Lors de la sélection des coordonnées, vous devez indiquer x=, y=, sinon il sera confondu avec l'élément
(2) Appuyez et soulevez l'opération
Concept : simulez que le doigt est pressé tout le temps et que le doigt simulé est levé. Peut être utilisé pour combiner des opérations de tapotement ou de pression longue
méthode:
# 模拟手指对元素或坐标的按下操作
# 参数:
# el:元素
# x:x坐标
# y:y坐标
TouchAction(driver).press(el=None, x=None, y=None).perform()
# 模拟手指对元素或坐标的抬起操作
TouchAction(driver).release().perform()
(3) En attente de fonctionnement
Concept : simuler l'attente du doigt, comme appuyer et attendre 5 secondes avant de soulever
méthode:
# 参数:
# ms:暂停的毫秒数
TouchAction(driver).wait(ms=0).perform()
(4) Appuyez longuement sur l'opération
Concept : Simuler l'appui long d'un doigt sur un élément ou une coordonnée. Par exemple, appuyez longuement sur un bouton pour faire apparaître un menu
méthode:
# 参数:
# el:元素
# x:x坐标
# y:y坐标
# duration:长按时间,毫秒
TouchAction(driver).long_press(el=None, x=None, y=None, duration=1000).perform()
(5) Fonctionnement mobile
Concept: simulez les opérations de mouvement des doigts, par exemple, le déverrouillage par geste doit d'abord être appuyé, puis déplacé
méthode:
# 参数:
# el:元素
# x:x坐标
# y:y坐标
TouchAction(driver).move_to(el=None, x=None, y=None).perform()
15. Obtenir la résolution du téléphone portable
Scénario d'application : Il est nécessaire de calculer des coordonnées de clic ou de glissement en fonction de la résolution d'écran de l'appareil actuel
méthode:
driver.get_window_size() # 返回值是字典{'height'= x, 'width'= x}
16. Obtenez des captures d'écran de téléphone portable
Scénario d'application : certaines opérations automatisées peuvent ne pas répondre, mais aucune erreur n'est signalée. À ce stade, nous pouvons enregistrer la situation clé et les captures d'écran après l'opération. Vous pouvez également trouver le problème en fonction de l'image plus tard
méthode:
# 参数:
# filename:指定路径下,指定格式的图片
get_screenshot_as_file(filename)
17. Obtenir et configurer un réseau mobile
Scénario d'application : lorsque les applications vidéo utilisent le trafic pour regarder des vidéos, la plupart d'entre elles invitent l'utilisateur à poursuivre la lecture. Nous devrons peut-être utiliser un formulaire automatisé pour déterminer s'il existe une invite correspondante. Il devrait y avoir une invite lorsque le trafic est utilisé, et il ne devrait y avoir aucune invite lorsque le trafic n'est pas utilisé.
méthode:
# 获取手机网络
driver.network_connection
# 设置手机网络
# 参数: # connectionType:网络类型
driver.set_network_connection(connectionType)
Comparatif type de réseau de téléphonie mobile : (trafic, WiFi, mode avion)
18. Envoyer la clé à l'appareil
Scénario d'application : simulez l'appui sur le "bouton de retour", le "bouton d'accueil", le "volume haut et bas", etc.
méthode:
# 参数:
# keycode:发送给设备的关键代码
# metastate:关于被发送的关键代码的元信息,一般为默认值
driver.press_keycode(keycode, metastate=None)
Touches téléphoniques couramment utilisées :
nom de la clé | nom de la clé | code clé |
KEYCODE_HOME | bouton Accueil | 3 |
KEYCODE_MENU | menu | 82 |
KEYCODE_BACK | touche de retour | 4 |
KEYCODE_VOLUME_UP | touche d'augmentation du volume | 24 |
KEYCODE_VOLUME_DOWN | touche volume bas | 25 |
Le code correspondant à la clé, vous pouvez rechercher le mot-clé "android keycode"
Par exemple : https://blog.csdn.net/feizhixuan46789/article/details/16801429
19. Activer et désactiver la barre de notification du téléphone
Scénario d'application : si vous souhaitez déterminer si le téléphone mobile a reçu un message via la barre de notification, vous devez d'abord utiliser la barre de notification du téléphone mobile
méthode:
# 打开手机通知栏
driver.open_notifications()
# 关闭手机通知栏
driver.press_keycode(4) # 直接返回就能关闭,没有专门的方法关闭