最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python使用Appium實現(xiàn)自動化操作手機入門教學

 更新時間:2025年10月26日 13:50:06   作者:閑人編程  
Appium作為一個開源的移動應用自動化測試框架,支持多種編程語言,包括Python、Java、Ruby等,本文將詳細介紹如何使用Python和Appium來操作手機,需要的可以了解下

1. 引言

在當今移動互聯(lián)網(wǎng)時代,手機應用已經(jīng)成為人們?nèi)粘I钪胁豢苫蛉钡囊徊糠帧kS著移動應用的快速發(fā)展,自動化測試和手機操作的需求也日益增長。Appium作為一個開源的移動應用自動化測試框架,能夠幫助我們實現(xiàn)這一目標。

Appium支持多種編程語言,包括Python、Java、Ruby等,并可以同時測試Android和iOS平臺的應用。它采用WebDriver協(xié)議,使得我們可以使用熟悉的Selenium WebDriver API來編寫移動應用的自動化腳本。

本文將詳細介紹如何使用Python和Appium來操作手機,從環(huán)境搭建到實際腳本編寫,幫助讀者快速掌握這一實用技能。

2. 環(huán)境準備

在開始使用Appium之前,我們需要完成一系列的環(huán)境配置工作。以下是詳細的步驟:

2.1 安裝Node.js和NPM

Appium服務器是基于Node.js開發(fā)的,因此首先需要安裝Node.js??梢詮腘ode.js官網(wǎng)下載并安裝最新版本。

安裝完成后,可以通過以下命令驗證安裝是否成功:

node --version
npm --version

2.2 安裝Appium

通過NPM全局安裝Appium:

npm install -g appium

安裝完成后,可以通過以下命令啟動Appium服務器:

appium

2.3 安裝Appium Python客戶端

使用pip安裝Appium的Python客戶端庫:

pip install Appium-Python-Client

2.4 安裝和配置Android SDK

對于Android設備,需要安裝Android SDK并配置環(huán)境變量:

  • 下載Android Studio或獨立SDK工具
  • 設置ANDROID_HOME環(huán)境變量
  • 將platform-tools和tools目錄添加到PATH環(huán)境變量中

2.5 安裝Java Development Kit (JDK)

Appium需要Java環(huán)境支持,請安裝JDK 8或更高版本。

3. Appium基礎概念

3.1 Appium架構

Appium采用客戶端-服務器架構:

Appium服務器:接收來自客戶端的命令,并將其轉換為移動設備可以理解的原生命令

Appium客戶端:各種編程語言的客戶端庫,用于發(fā)送命令到Appium服務器

3.2 Desired Capabilities

Desired Capabilities是一組鍵值對,用于告訴Appium服務器我們想要啟動怎樣的會話。常見的Capabilities包括:

  • platformName:平臺名稱(Android或iOS)
  • platformVersion:平臺版本
  • deviceName:設備名稱
  • appPackage:應用包名
  • appActivity:應用活動名

3.3 元素定位策略

Appium支持多種元素定位策略:

  • ID定位
  • Class Name定位
  • XPath定位
  • Accessibility ID定位
  • Android UI Automator定位

4. 編寫第一個Appium腳本

下面我們將編寫一個簡單的Appium腳本,用于打開手機上的計算器應用并進行簡單的計算操作。

4.1 導入必要的庫

from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from appium.options.android import UiAutomator2Options
import time
import unittest

4.2 配置Desired Capabilities

def setup_driver():
    # 配置Appium選項
    options = UiAutomator2Options()
    
    # 設置設備基本信息
    options.platform_name = 'Android'
    options.platform_version = '12'  # 根據(jù)你的設備版本修改
    options.device_name = 'Android Emulator'
    options.automation_name = 'UiAutomator2'
    
    # 設置應用信息
    options.app_package = 'com.android.calculator2'
    options.app_activity = 'com.android.calculator2.Calculator'
    
    # 其他設置
    options.no_reset = True  # 不重置應用狀態(tài)
    
    # 連接Appium服務器
    driver = webdriver.Remote('http://localhost:4723', options=options)
    
    return driver

4.3 實現(xiàn)計算器操作

def calculator_operations(driver):
    """執(zhí)行計算器操作"""
    try:
        # 等待計算器加載完成
        time.sleep(2)
        
        # 定位數(shù)字按鈕和操作符
        # 注意:不同設備上的計算器應用可能具有不同的元素ID
        # 這里使用的是Android原生計算器的元素ID
        
        # 點擊數(shù)字 7
        btn_7 = driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/digit_7')
        btn_7.click()
        
        # 點擊加號
        btn_plus = driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/op_add')
        btn_plus.click()
        
        # 點擊數(shù)字 8
        btn_8 = driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/digit_8')
        btn_8.click()
        
        # 點擊等號
        btn_equals = driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/eq')
        btn_equals.click()
        
        # 獲取結果
        result = driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/result')
        calculated_result = result.text
        
        print(f"計算結果: 7 + 8 = {calculated_result}")
        
        # 驗證結果是否正確
        expected_result = '15'
        if calculated_result == expected_result:
            print("測試通過!計算結果正確。")
        else:
            print(f"測試失?。∑谕Y果: {expected_result}, 實際結果: {calculated_result}")
            
        return calculated_result
        
    except Exception as e:
        print(f"操作過程中出現(xiàn)錯誤: {str(e)}")
        return None

4.4 完整的測試類

class CalculatorTest(unittest.TestCase):
    """計算器測試類"""
    
    def setUp(self):
        """測試前置設置"""
        self.driver = setup_driver()
        self.driver.implicitly_wait(10)  # 設置隱式等待時間
        
    def tearDown(self):
        """測試后置清理"""
        if self.driver:
            self.driver.quit()
            
    def test_addition_operation(self):
        """測試加法運算"""
        result = calculator_operations(self.driver)
        self.assertEqual(result, '15', "加法運算結果不正確")
        
    def test_clear_operation(self):
        """測試清除操作"""
        try:
            # 先輸入一些數(shù)字
            btn_5 = self.driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/digit_5')
            btn_5.click()
            
            # 點擊清除按鈕
            btn_clear = self.driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/clr')
            btn_clear.click()
            
            # 驗證顯示區(qū)域是否已清除
            result = self.driver.find_element(AppiumBy.ID, 'com.android.calculator2:id/formula')
            current_display = result.text
            
            # 清除后顯示區(qū)域應該為空或顯示0
            self.assertTrue(not current_display or current_display == '0', 
                          "清除操作未正常工作")
            
        except Exception as e:
            self.fail(f"清除操作測試失敗: {str(e)}")

5. 進階操作

5.1 處理不同的元素定位情況

在實際應用中,我們可能會遇到各種復雜的定位情況。以下是一些常用的定位方法:

def advanced_element_locating(driver):
    """演示高級元素定位方法"""
    
    # 1. 使用XPath定位
    # 通過文本內(nèi)容定位元素
    element_by_text = driver.find_element(AppiumBy.XPATH, "http://*[@text='確定']")
    
    # 通過部分文本內(nèi)容定位
    element_by_partial_text = driver.find_element(
        AppiumBy.XPATH, "http://*[contains(@text, '確定')]"
    )
    
    # 2. 使用Accessibility ID定位(通常對應content-desc屬性)
    element_by_accessibility = driver.find_element(
        AppiumBy.ACCESSIBILITY_ID, "按鈕描述"
    )
    
    # 3. 使用Class Name定位
    elements_by_class = driver.find_elements(
        AppiumBy.CLASS_NAME, "android.widget.Button"
    )
    
    # 4. 使用Android UI Automator定位
    element_by_uiautomator = driver.find_element(
        AppiumBy.ANDROID_UIAUTOMATOR, 
        'new UiSelector().text("確定")'
    )
    
    return {
        'by_text': element_by_text,
        'by_partial_text': element_by_partial_text,
        'by_accessibility': element_by_accessibility,
        'by_class': elements_by_class,
        'by_uiautomator': element_by_uiautomator
    }

5.2 手勢操作

Appium支持多種手勢操作,如滑動、長按、拖拽等:

def gesture_operations(driver):
    """演示手勢操作"""
    
    # 獲取屏幕尺寸
    window_size = driver.get_window_size()
    screen_width = window_size['width']
    screen_height = window_size['height']
    
    # 1. 滑動操作 - 從底部滑動到頂部
    start_x = screen_width / 2
    start_y = screen_height * 0.8
    end_x = screen_width / 2
    end_y = screen_height * 0.2
    
    driver.swipe(start_x, start_y, end_x, end_y, 1000)
    
    # 2. 滾動操作
    # 滾動到指定元素
    scroll_to_element = driver.find_element(
        AppiumBy.ANDROID_UIAUTOMATOR,
        'new UiScrollable(new UiSelector().scrollable(true))'
        '.scrollIntoView(new UiSelector().text("目標元素"))'
    )
    
    # 3. 長按操作
    element_to_long_press = driver.find_element(AppiumBy.ID, 'some.element.id')
    driver.long_press(element_to_long_press)
    
    # 4. 拖拽操作
    source_element = driver.find_element(AppiumBy.ID, 'source.element')
    target_element = driver.find_element(AppiumBy.ID, 'target.element')
    driver.drag_and_drop(source_element, target_element)

5.3 處理彈窗和權限請求

def handle_popups_and_permissions(driver):
    """處理彈窗和權限請求"""
    
    try:
        # 嘗試查找并點擊允許按鈕
        allow_button = driver.find_element(
            AppiumBy.ID, 'com.android.packageinstaller:id/permission_allow_button'
        )
        allow_button.click()
        print("已處理權限請求")
        
    except Exception:
        # 如果找不到特定的允許按鈕,嘗試其他方式
        try:
            # 使用文本定位允許按鈕
            allow_by_text = driver.find_element(
                AppiumBy.XPATH, "http://*[@text='允許' or @text='ALLOW']"
            )
            allow_by_text.click()
            print("通過文本定位處理了權限請求")
            
        except Exception:
            print("未找到權限請求彈窗或處理失敗")
            
    # 處理其他類型的彈窗
    try:
        # 查找確定、好的、知道了等按鈕
        confirm_buttons = [
            "確定", "確認", "好的", "知道了", "OK", "Okay"
        ]
        
        for button_text in confirm_buttons:
            try:
                confirm_btn = driver.find_element(
                    AppiumBy.XPATH, f"http://*[@text='{button_text}']"
                )
                confirm_btn.click()
                print(f"點擊了 {button_text} 按鈕")
                break
            except Exception:
                continue
                
    except Exception as e:
        print(f"處理彈窗時出現(xiàn)錯誤: {str(e)}")

5.4 等待策略

合理的等待策略對于自動化測試的穩(wěn)定性至關重要:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def wait_strategies(driver):
    """演示不同的等待策略"""
    
    # 1. 顯式等待 - 等待元素可點擊
    wait = WebDriverWait(driver, 10)
    element = wait.until(
        EC.element_to_be_clickable((AppiumBy.ID, 'some.element.id'))
    )
    element.click()
    
    # 2. 顯式等待 - 等待元素可見
    visible_element = wait.until(
        EC.visibility_of_element_located((AppiumBy.ID, 'visible.element'))
    )
    
    # 3. 顯式等待 - 等待元素存在(不一定可見)
    present_element = wait.until(
        EC.presence_of_element_located((AppiumBy.ID, 'present.element'))
    )
    
    # 4. 自定義等待條件
    def custom_condition(driver):
        """自定義等待條件"""
        try:
            element = driver.find_element(AppiumBy.ID, 'custom.element')
            return element.is_displayed()
        except Exception:
            return False
    
    custom_element = wait.until(custom_condition)
    
    return {
        'clickable': element,
        'visible': visible_element,
        'present': present_element,
        'custom': custom_element
    }

6. 完整代碼示例

下面是一個完整的Appium腳本示例,展示了如何使用Python操作手機:

#!/usr/bin/env python3
"""
Appium手機操作示例
作者:你的名字
日期:2024年1月
描述:使用Python和Appium操作手機計算器應用
"""

import time
import unittest
import logging
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException


# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


class MobileAutomationFramework:
    """移動自動化框架類"""
    
    def __init__(self, server_url='http://localhost:4723'):
        self.server_url = server_url
        self.driver = None
        self.wait = None
        
    def setup_driver(self, capabilities_dict=None):
        """設置Appium驅動"""
        
        if capabilities_dict is None:
            # 默認配置 - Android計算器
            capabilities_dict = {
                'platformName': 'Android',
                'platformVersion': '12',
                'deviceName': 'Android Emulator',
                'automationName': 'UiAutomator2',
                'appPackage': 'com.android.calculator2',
                'appActivity': 'com.android.calculator2.Calculator',
                'noReset': True,
                'newCommandTimeout': 300
            }
        
        try:
            options = UiAutomator2Options()
            for key, value in capabilities_dict.items():
                setattr(options, key, value)
                
            logger.info("正在連接Appium服務器...")
            self.driver = webdriver.Remote(self.server_url, options=options)
            
            # 設置顯式等待
            self.wait = WebDriverWait(self.driver, 15)
            
            logger.info("Appium驅動設置成功")
            return True
            
        except Exception as e:
            logger.error(f"設置Appium驅動失敗: {str(e)}")
            return False
    
    def teardown(self):
        """清理資源"""
        if self.driver:
            self.driver.quit()
            logger.info("Appium驅動已關閉")
    
    def find_element_with_wait(self, by, value, timeout=15):
        """帶等待的元素查找"""
        wait = WebDriverWait(self.driver, timeout)
        return wait.until(EC.presence_of_element_located((by, value)))
    
    def safe_click(self, by, value, timeout=15):
        """安全的點擊操作"""
        try:
            element = self.find_element_with_wait(by, value, timeout)
            element.click()
            logger.info(f"成功點擊元素: {value}")
            return True
        except Exception as e:
            logger.error(f"點擊元素失敗: {value}, 錯誤: {str(e)}")
            return False
    
    def take_screenshot(self, filename=None):
        """截取屏幕截圖"""
        if filename is None:
            filename = f"screenshot_{int(time.time())}.png"
        
        try:
            self.driver.save_screenshot(filename)
            logger.info(f"截圖已保存: {filename}")
            return True
        except Exception as e:
            logger.error(f"截圖失敗: {str(e)}")
            return False
    
    def get_page_source(self):
        """獲取頁面源代碼"""
        try:
            return self.driver.page_source
        except Exception as e:
            logger.error(f"獲取頁面源代碼失敗: {str(e)}")
            return None


class CalculatorAutomation(MobileAutomationFramework):
    """計算器自動化類"""
    
    def __init__(self):
        super().__init__()
        self.number_mapping = {
            '0': 'digit_0', '1': 'digit_1', '2': 'digit_2',
            '3': 'digit_3', '4': 'digit_4', '5': 'digit_5',
            '6': 'digit_6', '7': 'digit_7', '8': 'digit_8',
            '9': 'digit_9'
        }
        self.operator_mapping = {
            '+': 'op_add', '-': 'op_sub', 
            '*': 'op_mul', '/': 'op_div'
        }
    
    def input_number(self, number):
        """輸入數(shù)字"""
        if not isinstance(number, (int, str)):
            raise ValueError("數(shù)字必須是整數(shù)或字符串")
        
        number_str = str(number)
        for digit in number_str:
            if digit in self.number_mapping:
                element_id = f"com.android.calculator2:id/{self.number_mapping[digit]}"
                self.safe_click(AppiumBy.ID, element_id)
                time.sleep(0.1)  # 短暫延遲,確保輸入穩(wěn)定
            else:
                logger.warning(f"無法識別的數(shù)字: {digit}")
    
    def input_operator(self, operator):
        """輸入操作符"""
        if operator not in self.operator_mapping:
            raise ValueError(f"不支持的操作符: {operator}")
        
        element_id = f"com.android.calculator2:id/{self.operator_mapping[operator]}"
        self.safe_click(AppiumBy.ID, element_id)
    
    def calculate(self, num1, operator, num2):
        """執(zhí)行計算"""
        logger.info(f"執(zhí)行計算: {num1} {operator} {num2}")
        
        # 輸入第一個數(shù)字
        self.input_number(num1)
        
        # 輸入操作符
        self.input_operator(operator)
        
        # 輸入第二個數(shù)字
        self.input_number(num2)
        
        # 點擊等號
        self.safe_click(AppiumBy.ID, 'com.android.calculator2:id/eq')
        
        # 獲取結果
        return self.get_result()
    
    def get_result(self):
        """獲取計算結果"""
        try:
            result_element = self.find_element_with_wait(
                AppiumBy.ID, 'com.android.calculator2:id/result'
            )
            result = result_element.text
            logger.info(f"計算結果: {result}")
            return result
        except Exception as e:
            logger.error(f"獲取結果失敗: {str(e)}")
            return None
    
    def clear_calculator(self):
        """清除計算器"""
        self.safe_click(AppiumBy.ID, 'com.android.calculator2:id/clr')
        logger.info("計算器已清除")


class TestCalculatorOperations(unittest.TestCase):
    """計算器操作測試類"""
    
    @classmethod
    def setUpClass(cls):
        """測試類設置"""
        cls.calculator = CalculatorAutomation()
        success = cls.calculator.setup_driver()
        if not success:
            raise Exception("無法初始化Appium驅動")
    
    @classmethod
    def tearDownClass(cls):
        """測試類清理"""
        cls.calculator.teardown()
    
    def setUp(self):
        """單個測試設置"""
        # 確保每次測試前計算器是清除狀態(tài)
        self.calculator.clear_calculator()
        time.sleep(1)
    
    def test_addition(self):
        """測試加法"""
        result = self.calculator.calculate(15, '+', 7)
        self.assertEqual(result, '22', "加法測試失敗")
    
    def test_subtraction(self):
        """測試減法"""
        result = self.calculator.calculate(20, '-', 8)
        self.assertEqual(result, '12', "減法測試失敗")
    
    def test_multiplication(self):
        """測試乘法"""
        result = self.calculator.calculate(6, '*', 9)
        self.assertEqual(result, '54', "乘法測試失敗")
    
    def test_division(self):
        """測試除法"""
        result = self.calculator.calculate(56, '/', 7)
        self.assertEqual(result, '8', "除法測試失敗")
    
    def test_complex_operation(self):
        """測試復雜運算"""
        # 15 + 27 - 8
        self.calculator.input_number(15)
        self.calculator.input_operator('+')
        self.calculator.input_number(27)
        self.calculator.input_operator('-')
        self.calculator.input_number(8)
        self.calculator.safe_click(AppiumBy.ID, 'com.android.calculator2:id/eq')
        
        result = self.calculator.get_result()
        self.assertEqual(result, '34', "復雜運算測試失敗")


def main():
    """主函數(shù)"""
    logger.info("開始Appium手機操作演示")
    
    # 創(chuàng)建計算器自動化實例
    calculator = CalculatorAutomation()
    
    try:
        # 設置驅動
        if not calculator.setup_driver():
            logger.error("無法啟動Appium驅動,程序退出")
            return
        
        # 執(zhí)行一系列測試計算
        test_calculations = [
            (8, '+', 4),
            (15, '-', 6),
            (7, '*', 9),
            (81, '/', 9)
        ]
        
        for num1, op, num2 in test_calculations:
            result = calculator.calculate(num1, op, num2)
            expected = str(eval(f"{num1}{op}{num2}"))
            
            if result == expected:
                logger.info(f"? {num1} {op} {num2} = {result} (正確)")
            else:
                logger.error(f"? {num1} {op} {num2} = {result} (期望: {expected})")
        
        # 截取屏幕截圖
        calculator.take_screenshot("calculator_final_state.png")
        
        logger.info("Appium手機操作演示完成")
        
    except Exception as e:
        logger.error(f"程序執(zhí)行過程中出現(xiàn)錯誤: {str(e)}")
        
    finally:
        # 確保資源被正確清理
        calculator.teardown()


if __name__ == "__main__":
    # 可以直接運行演示
    main()
    
    # 或者運行單元測試
    # unittest.main(verbosity=2)

7. 常見問題與解決方案

7.1 連接問題

問題:無法連接到Appium服務器

解決方案:

  • 確保Appium服務器正在運行:appium
  • 檢查端口是否被占用,默認端口是4723
  • 驗證URL格式:http://localhost:4723

7.2 元素找不到問題

問題:腳本無法找到指定元素

解決方案:

  • 增加等待時間,使用顯式等待
  • 使用不同的定位策略
  • 檢查應用是否已正確啟動
  • 使用Appium Desktop的Inspector工具驗證元素定位

7.3 權限問題

問題:應用權限請求導致腳本中斷

解決方案:

  • 在Desired Capabilities中設置autoGrantPermissions: true
  • 在腳本中添加權限處理邏輯
  • 手動預先授予應用所需權限

7.4 性能問題

問題:腳本運行緩慢

解決方案:

  • 減少不必要的等待時間
  • 使用更高效的元素定位策略
  • 避免頻繁的頁面源代碼獲取
  • 考慮使用更快的測試設備或模擬器

8. 最佳實踐

8.1 代碼組織

使用Page Object模式將頁面元素和操作封裝成類

將配置信息與測試邏輯分離

使用配置文件或環(huán)境變量管理設備信息和應用信息

8.2 錯誤處理

實現(xiàn)完善的異常處理機制

添加重試機制處理偶發(fā)性失敗

使用日志記錄詳細的操作信息

8.3 維護性

使用有意義的變量名和函數(shù)名

添加清晰的注釋和文檔

定期更新Appium和相關依賴

9. 總結

通過本文的介紹,我們學習了如何使用Python和Appium來操作手機應用。從環(huán)境搭建到基礎操作,再到高級技巧,我們覆蓋了使用Appium進行移動自動化的關鍵知識點。

Appium作為一個強大的跨平臺移動自動化工具,結合Python的簡潔語法,為我們提供了強大的手機操作能力。無論是進行自動化測試還是實現(xiàn)復雜的手機操作流程,Appium都是一個值得掌握的技能。

隨著移動應用的不斷發(fā)展,掌握移動自動化技術將會變得越來越重要。希望本文能夠為你提供一個良好的起點,幫助你在移動自動化的道路上走得更遠。

注意:在實際使用中,請根據(jù)你的具體設備和應用調(diào)整代碼中的元素定位信息和配置參數(shù)。不同的設備和應用版本可能會有差異,需要靈活調(diào)整腳本。

到此這篇關于Python使用Appium實現(xiàn)自動化操作手機入門教學的文章就介紹到這了,更多相關Python Appium操作手機內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

邵武市| 渭源县| 丰县| 祁东县| 右玉县| 湖口县| 珠海市| 山阳县| 科技| 高邑县| 唐河县| 常熟市| 寿阳县| 湄潭县| 利川市| 云梦县| 行唐县| 博白县| 龙岩市| 青铜峡市| 江华| 连城县| 建瓯市| 雅江县| 永城市| 班玛县| 鹰潭市| 罗甸县| 临颍县| 陇西县| 林口县| 临沂市| 聂荣县| 射阳县| 醴陵市| 阳原县| 南岸区| 探索| 乌审旗| 图们市| 宝丰县|