更新Appium及Python客户端后移动端测试脚本报错求助
Appium 2.5.2 + appium-python-client 4.0.0 版本更新后脚本报错解决方案
问题背景
更新Appium至2.5.2、appium-python-client至4.0.0后,原有移动端Web测试脚本出现两类错误:
- 初始错误:
ModuleNotFoundError: No module named 'appium.webdriver.common.mobileby' - 替换MobileBy为By后新错误:
AttributeError: 'NoneType' object has no attribute 'to_capabilities'
错误原因及修复步骤
1. MobileBy模块找不到的问题
appium-python-client 4.x版本重构了定位方式模块,MobileBy已迁移至appium.webdriver.common.appiumby模块并更名为AppiumBy。直接使用selenium的By类会导致无法识别ANDROID_UIAUTOMATOR这类移动端专属定位策略。
修复方法:
- 替换导入语句:
from appium.webdriver.common.appiumby import AppiumBy - 代码中所有
MobileBy或错误使用的By替换为AppiumBy,例如:connections = WebDriverWait(driver, 7).until(EC.presence_of_element_located((AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("Connections")')))
2. 'NoneType' object has no attribute 'to_capabilities'错误
appium-python-client 4.x完全对齐Selenium 4的API规范,创建驱动时需要用AppiumOptions系列类封装capabilities,不再直接传入字典。此外原代码存在一处逻辑错误:在elif airplane_mode_status == 0分支中,调用toggle_airplane_mode时传入的是setup_settings_driver(device_id)(重新创建了一个驱动实例),而非已初始化的settings_driver,这会导致资源重复创建且可能引发异常。
修复方法:
- 导入对应平台的Options类:
from appium.options.android import UiAutomator2Options - 修改驱动创建逻辑,用
UiAutomator2Options封装capabilities(注意Appium 2.x服务器端点不再是/wd/hub):
以setup_settings_driver为例:def setup_settings_driver(device_id): settings_options = UiAutomator2Options() settings_options.set_capability('platformName', 'Android') settings_options.set_capability('deviceName', device_id) settings_options.set_capability('appPackage', 'com.android.settings') settings_options.set_capability('appActivity', '.Settings') settings_options.set_capability('noReset', True) settings_options.set_capability('newCommandTimeout', 200) logging.debug("Setting up driver for device settings") return webdriver.Remote('http://127.0.0.1:4723', settings_options) - 修复
elif分支的逻辑错误:elif airplane_mode_status == 0: settings_driver = setup_settings_driver(device_id) toggle_airplane_mode(settings_driver) # 传入已创建的driver实例,而非重新创建 settings_driver.quit()
完整修复后的代码
import logging from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.action_chains import ActionChains from appium.options.android import UiAutomator2Options import subprocess import time import random # 日志配置 logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') def check_airplane_mode(device_id): # 检查设备的飞行模式状态 logging.debug(f"Checking airplane mode status for device {device_id}") command = ["adb", "-s", device_id, "shell", "settings", "get", "global", "airplane_mode_on"] result = subprocess.check_output(command).decode().strip() logging.debug(f"Airplane mode status: {result}") return int(result) def setup_settings_driver(device_id): # 为设备设置配置驱动 settings_options = UiAutomator2Options() settings_options.set_capability('platformName', 'Android') settings_options.set_capability('deviceName', device_id) settings_options.set_capability('appPackage', 'com.android.settings') settings_options.set_capability('appActivity', '.Settings') settings_options.set_capability('noReset', True) settings_options.set_capability('newCommandTimeout', 200) logging.debug("Setting up driver for device settings") return webdriver.Remote('http://127.0.0.1:4723', settings_options) def toggle_airplane_mode(driver): # 切换飞行模式 logging.debug("Toggling airplane mode") driver.start_activity('com.android.settings', '.Settings') connections = WebDriverWait(driver, 7).until(EC.presence_of_element_located((AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("Connections")'))) connections.click() airplane_mode = WebDriverWait(driver, 7).until(EC.presence_of_element_located((AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("Airplane mode")'))) airplane_mode.click() toggle_switch = WebDriverWait(driver, 7).until(EC.presence_of_element_located((AppiumBy.ID, 'com.android.settings:id/switch_widget'))) toggle_switch.click() time.sleep(2) def setup_chrome_driver(device_id): # 配置Chrome驱动 chrome_options = UiAutomator2Options() chrome_options.set_capability('platformName', 'Android') chrome_options.set_capability('deviceName', device_id) chrome_options.set_capability('browserName', 'Chrome') chrome_options.set_capability('noReset', True) chrome_options.set_capability('newCommandTimeout', 200) logging.debug("Setting up Chrome driver") try: driver = webdriver.Remote('http://127.0.0.1:4723', chrome_options) return driver except Exception as e: logging.warning(f"Failed to create driver with UiAutomator2: {e}") return None def random_scroll(driver, min_scroll, max_scroll, min_duration, max_duration): # 在网页上执行随机滚动 width = driver.get_window_size()['width'] height = driver.get_window_size()['height'] start_x = width // 2 start_y = int(height * 0.8) end_y = int(height * 0.2) action = ActionChains(driver) for _ in range(random.randint(min_scroll, max_scroll)): action.move_to_element_with_offset(driver.find_element(AppiumBy.TAG_NAME, "body"), start_x, start_y) action.click_and_hold() action.move_by_offset(0, end_y - start_y) action.release() action.perform() time.sleep(random.randint(min_duration, max_duration) / 1000) def open_chrome_and_search(driver, query): # 打开Chrome浏览器并执行搜索 driver.get("https://www.google.com") time.sleep(2) random_scroll(driver, 1, 3, 300, 800) def get_connected_devices(): # 获取已连接设备列表 logging.debug("Fetching list of connected devices") result = subprocess.check_output(["adb", "devices"]).decode().splitlines() devices = [line.split()[0] for line in result if "device" in line and not "devices" in line] return devices print("Appium version: 2.5.2") devices = get_connected_devices() logging.info(f"Connected devices: {devices}") for device_id in devices: # 根据飞行模式状态执行对应操作 airplane_mode_status = check_airplane_mode(device_id) if airplane_mode_status == 1: settings_driver = setup_settings_driver(device_id) toggle_airplane_mode(settings_driver) settings_driver.quit() chrome_driver = setup_chrome_driver(device_id) if chrome_driver: open_chrome_and_search(chrome_driver, "test") chrome_driver.quit() elif airplane_mode_status == 0: settings_driver = setup_settings_driver(device_id) toggle_airplane_mode(settings_driver) settings_driver.quit()
额外注意事项
- Appium 2.x需要手动安装驱动,执行
appium driver install uiautomator2确保UiAutomator2驱动已安装 - 确认Python环境依赖正确,执行
pip list检查appium-python-client版本为4.x,selenium版本为4.x(需与appium-python-client兼容) - 设备需开启USB调试,且adb连接正常
内容的提问来源于stack exchange,提问作者斎藤大輔
相关产品推荐
相关产品推荐

