Appium框架详解

Appium是移动端自动化测试的明星框架,支持iOS和Android平台,使用WebDriver协议。

Appium基础配置

# Appium服务器配置
# 1. 启动Appium服务器
# appium --address 127.0.0.1 --port 4723 --session-override --log-timestamp --log-level info

# 2. Appium客户端配置
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
import time

class AppiumController:
    """Appium控制器 - 用于App自动化控制"""
    
    def __init__(self, platform_name='Android', device_name='Android Emulator', 
                 app_package=None, app_activity=None, remote_url='http://localhost:4723'):
        self.platform_name = platform_name
        self.device_name = device_name
        self.app_package = app_package
        self.app_activity = app_activity
        self.remote_url = remote_url
        self.driver = None
        
        # 配置Appium选项
        self.options = UiAutomator2Options() \
            .platform_name(platform_name) \
            .device_name(device_name) \
            .auto_grant_permissions(True) \
            .unicode_keyboard(True) \
            .reset_keyboard(True) \
            .no_reset(False) \
            .full_reset(False)
        
        if app_package:
            self.options.app_package(app_package)
        if app_activity:
            self.options.app_activity(app_activity)
    
    def connect(self):
        """连接到Appium服务器"""
        try:
            self.driver = webdriver.Remote(self.remote_url, options=self.options)
            print(f"✅ Appium连接成功: {self.remote_url}")
            return True
        except Exception as e:
            print(f"❌ Appium连接失败: {e}")
            return False
    
    def disconnect(self):
        """断开连接"""
        if self.driver:
            self.driver.quit()
            print("🔌 Appium连接已断开")
    
    def find_element(self, locator, timeout=10):
        """查找元素"""
        try:
            from selenium.webdriver.support.ui import WebDriverWait
            from selenium.webdriver.support import expected_conditions as EC
            
            wait = WebDriverWait(self.driver, timeout)
            element = wait.until(EC.presence_of_element_located(locator))
            return element
        except Exception as e:
            print(f"❌ 查找元素失败: {e}")
            return None
    
    def tap_element(self, locator):
        """点击元素"""
        element = self.find_element(locator)
        if element:
            element.click()
            print("✅ 元素点击成功")
            return True
        return False
    
    def send_keys(self, locator, text):
        """输入文本"""
        element = self.find_element(locator)
        if element:
            element.clear()
            element.send_keys(text)
            print(f"✅ 输入文本: {text}")
            return True
        return False

# Appium高级操作示例
def appium_advanced_operations():
    """Appium高级操作演示"""
    # 启动抖音APP的示例配置
    controller = AppiumController(
        app_package='com.ss.android.ugc.aweme',
        app_activity='.splash.SplashActivity'
    )
    
    if controller.connect():
        driver = controller.driver
        
        # 等待应用加载
        time.sleep(5)
        
        # 获取屏幕尺寸
        size = driver.get_window_size()
        width, height = size['width'], size['height']
        
        # 手势操作 - 向上滑动
        start_x, start_y = width // 2, height * 3 // 4
        end_x, end_y = width // 2, height // 4
        
        # 执行滑动操作
        driver.swipe(start_x, start_y, end_x, end_y, 1000)
        print("📱 执行滑动操作")
        
        # 获取页面源码
        page_source = driver.page_source
        print(f"📄 页面源码长度: {len(page_source)}")
        
        # 获取当前Activity
        current_activity = driver.current_activity
        print(f"🎯 当前Activity: {current_activity}")
        
        # 获取应用信息
        app_info = {
            'package': driver.current_package,
            'activity': driver.current_activity,
            'orientation': driver.orientation
        }
        print(f"📱 应用信息: {app_info}")
        
        controller.disconnect()

Appium实战 - 抖音自动化脚本

from appium import webdriver
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
import random

class DouyinAutomation:
    """抖音自动化控制类"""
    
    def __init__(self, device_udid=None):
        self.device_udid = device_udid
        self.driver = None
        self.setup_driver()
    
    def setup_driver(self):
        """设置Appium驱动"""
        options = UiAutomator2Options()
        options.platform_name = 'Android'
        options.app_package = 'com.ss.android.ugc.aweme'
        options.app_activity = '.splash.SplashActivity'
        options.auto_grant_permissions = True
        options.unicode_keyboard = True
        options.reset_keyboard = True
        
        if self.device_udid:
            options.udid = self.device_udid
        
        try:
            self.driver = webdriver.Remote('http://localhost:4723', options=options)
            print("✅ 抖音自动化驱动初始化成功")
        except Exception as e:
            print(f"❌ 驱动初始化失败: {e}")
    
    def wait_for_element(self, locator, timeout=10):
        """等待元素出现"""
        try:
            wait = WebDriverWait(self.driver, timeout)
            return wait.until(EC.presence_of_element_located(locator))
        except:
            return None
    
    def scroll_feed(self, count=5):
        """滚动信息流"""
        print(f"📱 开始滚动信息流,次数: {count}")
        
        for i in range(count):
            # 获取屏幕尺寸
            size = self.driver.get_window_size()
            width, height = size['width'], size['height']
            
            # 滑动参数
            start_x, start_y = width // 2, height * 3 // 4
            end_x, end_y = width // 2, height // 4
            
            # 执行滑动
            self.driver.swipe(start_x, start_y, end_x, end_y, 1000)
            
            # 随机等待
            time.sleep(random.uniform(2, 4))
            
            print(f"  ✅ 第{i+1}次滑动完成")
    
    def like_current_video(self):
        """点赞当前视频"""
        # 寻找点赞按钮(这里使用常见的点赞按钮定位方式)
        like_selectors = [
            ('id', 'com.ss.android.ugc.aweme:id/like_icon'),
            ('xpath', '//android.widget.ImageView[@content-desc="点赞"]'),
            ('xpath', '//android.widget.ImageView[contains(@resource-id, "like")]'),
        ]
        
        for selector in like_selectors:
            try:
                element = self.wait_for_element(selector, timeout=3)
                if element:
                    element.click()
                    print("❤️  点赞成功")
                    time.sleep(0.5)  # 等待动画
                    return True
            except:
                continue
        
        print("❌ 未找到点赞按钮")
        return False
    
    def comment_on_video(self, comment_text):
        """评论当前视频"""
        # 寻找评论按钮
        comment_selectors = [
            ('id', 'com.ss.android.ugc.aweme:id/comment_icon'),
            ('xpath', '//android.widget.ImageView[@content-desc="评论"]'),
        ]
        
        for selector in comment_selectors:
            try:
                element = self.wait_for_element(selector, timeout=3)
                if element:
                    element.click()
                    time.sleep(2)  # 等待评论框出现
                    
                    # 输入评论
                    input_selector = ('id', 'com.ss.android.ugc.aweme:id/aew')
                    input_element = self.wait_for_element(input_selector, timeout=3)
                    if input_element:
                        input_element.click()
                        input_element.send_keys(comment_text)
                        
                        # 发送评论
                        send_selector = ('id', 'com.ss.android.ugc.aweme:id/ag4')
                        send_element = self.wait_for_element(send_selector, timeout=2)
                        if send_element:
                            send_element.click()
                            print(f"💬 评论成功: {comment_text}")
                            time.sleep(1)
                            
                            # 返回
                            self.driver.back()
                            return True
                    
                    # 如果没找到输入框,直接返回
                    self.driver.back()
                    return False
            except:
                continue
        
        print("❌ 未找到评论功能")
        return False
    
    def follow_current_author(self):
        """关注当前视频作者"""
        # 寻找头像或关注按钮
        follow_selectors = [
            ('xpath', '//android.widget.ImageView[@content-desc="头像"]'),
            ('xpath', '//android.widget.Button[contains(@text, "关注")]'),
        ]
        
        for selector in follow_selectors:
            try:
                element = self.wait_for_element(selector, timeout=3)
                if element:
                    element.click()
                    print("👤 进入作者主页")
                    time.sleep(2)
                    
                    # 寻找关注按钮
                    follow_btn = self.wait_for_element(
                        ('xpath', '//android.widget.Button[contains(@text, "关注")]'), 
                        timeout=3
                    )
                    if follow_btn:
                        follow_btn.click()
                        print("✅ 关注成功")
                        time.sleep(1)
                    
                    # 返回
                    self.driver.back()
                    return True
            except:
                continue
        
        print("❌ 未找到关注功能")
        return False
    
    def run_automation_cycle(self, actions_config):
        """运行自动化循环"""
        print("🤖 开始抖音自动化任务")
        
        for cycle in range(actions_config.get('cycles', 10)):
            print(f"\n🔄 第 {cycle + 1} 个循环:")
            
            # 随机执行动作
            if random.random() < actions_config.get('like_probability', 0.7):
                self.like_current_video()
            
            if random.random() < actions_config.get('comment_probability', 0.1):
                comments = [
                    "不错👍",
                    "好看!",
                    "支持一下",
                    "厉害了"
                ]
                comment = random.choice(comments)
                self.comment_on_video(comment)
            
            if random.random() < actions_config.get('follow_probability', 0.05):
                self.follow_current_author()
            
            # 滑动到下一个视频
            self.scroll_feed(count=1)
            
            # 随机等待
            wait_time = random.uniform(3, 8)
            print(f"⏳ 等待 {wait_time:.1f} 秒")
            time.sleep(wait_time)
        
        print("🏁 自动化任务完成")
    
    def close(self):
        """关闭驱动"""
        if self.driver:
            self.driver.quit()

def demo_douyin_automation():
    """演示抖音自动化"""
    automation = DouyinAutomation()
    
    actions_config = {
        'cycles': 5,  # 循环次数
        'like_probability': 0.8,  # 点赞概率
        'comment_probability': 0.1,  # 评论概率
        'follow_probability': 0.05,  # 关注概率
    }
    
    try:
        automation.run_automation_cycle(actions_config)
    except KeyboardInterrupt:
        print("\n⏸️  用户中断")
    finally:
        automation.close()

if __name__ == "__main__":
    demo_douyin_automation()