第7章:高级功能与技巧

7.1 多显示器支持

7.1.1 显示器信息获取
import pyautogui

def monitor_info():
    """
    显示器信息获取
    """

    # 获取主显示器尺寸
    screen_width, screen_height = pyautogui.size()
    print(f"主显示器尺寸: {screen_width}x{screen_height}")

    # 获取所有显示器信息
    try:
        import screeninfo
        monitors = screeninfo.get_monitors()
        print(f"\n检测到 {len(monitors)} 个显示器:")
        for i, monitor in enumerate(monitors):
            print(f"  显示器 {i+1}:")
            print(f"    位置: ({monitor.x}, {monitor.y})")
            print(f"    尺寸: {monitor.width}x{monitor.height}")
            print(f"    主显示器: {monitor.is_primary}")
    except ImportError:
        print("\n未安装screeninfo库,无法获取多显示器信息")
        print("请运行: pip install screeninfo")

    # 检测鼠标位置
    mouse_x, mouse_y = pyautogui.position()
    print(f"\n当前鼠标位置: ({mouse_x}, {mouse_y})")

    # 验证坐标范围
    def is_valid_coordinate(x, y):
        """验证坐标是否有效"""
        try:
            # 尝试获取像素颜色
            pyautogui.pixel(x, y)
            return True
        except Exception:
            return False

    # 测试坐标有效性
    test_coords = [(0, 0), (screen_width-1, screen_height-1), (10000, 10000)]
    print("\n坐标有效性测试:")
    for x, y in test_coords:
        valid = is_valid_coordinate(x, y)
        print(f"  坐标 ({x}, {y}): {'有效' if valid else '无效'}")
7.1.2 跨显示器操作
import pyautogui

def cross_monitor_operations():
    """
    跨显示器操作
    """

    # 获取主显示器尺寸
    screen_width, screen_height = pyautogui.size()

    # 移动鼠标到主显示器中心
    center_x = screen_width // 2
    center_y = screen_height // 2
    print(f"移动鼠标到主显示器中心: ({center_x}, {center_y})")
    pyautogui.moveTo(center_x, center_y, duration=1.0)

    # 假设第二显示器在主显示器右侧
    second_monitor_x = screen_width + 500
    second_monitor_y = center_y
    print(f"移动鼠标到第二显示器: ({second_monitor_x}, {second_monitor_y})")
    pyautogui.moveTo(second_monitor_x, second_monitor_y, duration=1.0)

    # 在第二显示器上点击
    print("在第二显示器上点击")
    pyautogui.click()

    # 在第二显示器上输入文本
    print("在第二显示器上输入文本")
    pyautogui.write("Hello from second monitor!")
    pyautogui.press('enter')

    # 跨显示器截图
    def screenshot_multiple_monitors():
        """跨显示器截图"""
        print("截取整个屏幕(包括所有显示器)")
        screenshot = pyautogui.screenshot()
        screenshot.save('full_screen.png')
        print(f"截图尺寸: {screenshot.size}")
        print("保存到 full_screen.png")

    # 测试跨显示器截图
    screenshot_multiple_monitors()

    # 安全的跨显示器操作
    def safe_cross_monitor_click(x, y):
        """
        安全的跨显示器点击

        Args:
            x: x坐标
            y: y坐标
        """
        try:
            # 先移动鼠标
            pyautogui.moveTo(x, y, duration=0.5)
            # 等待一小段时间
            pyautogui.PAUSE = 0.2
            # 执行点击
            pyautogui.click()
            print(f"成功点击坐标: ({x}, {y})")
        except Exception as e:
            print(f"点击失败: {e}")

    # 测试安全点击
    safe_cross_monitor_click(second_monitor_x, second_monitor_y)

7.2 安全机制与控制

7.2.1 FAILSAFE机制详解
import pyautogui

def failsafe_mechanism():
    """
    FAILSAFE机制详解
    """

    # 查看当前FAILSAFE设置
    print(f"当前FAILSAFE设置: {pyautogui.FAILSAFE}")

    # 启用FAILSAFE
    pyautogui.FAILSAFE = True
    print("已启用FAILSAFE")

    # 注意:FAILSAFE_POINTS 和 FAILSAFE_DISTANCE 不是PyAutoGUI标准属性
    # 以下展示如何自定义实现类似功能
    
    # 自定义安全区域检查函数
    def check_failsafe_area(x_threshold=50, y_threshold=50):
        """
        检查鼠标是否在安全区域(屏幕左上角)
        
        Args:
            x_threshold: X轴安全阈值(像素)
            y_threshold: Y轴安全阈值(像素)
        
        Returns:
            bool: 是否在安全区域内
        """
        current_pos = pyautogui.position()
        return current_pos[0] < x_threshold and current_pos[1] < y_threshold
    
    # 测试自定义安全区域检查
    print("\n测试自定义安全区域检查:")
    print("将鼠标移动到屏幕左上角(0,0)附近将触发安全警告")
    print("按Ctrl+C终止测试")

    try:
        # 无限循环移动鼠标
        import time
        x, y = 100, 100
        direction = 1
        while True:
            x += direction * 5
            if x > 500 or x < 100:
                direction *= -1
            pyautogui.moveTo(x, y, duration=0.1)
            time.sleep(0.1)
    except KeyboardInterrupt:
        print("测试终止")
    except pyautogui.FailSafeException:
        print("FAILSAFE触发!")

    # 禁用FAILSAFE(谨慎使用)
    def disable_failsafe():
        """禁用FAILSAFE"""
        pyautogui.FAILSAFE = False
        print("\n已禁用FAILSAFE")
        print("警告: 禁用FAILSAFE可能导致失控,建议仅在受控环境中使用")

    # 重新启用FAILSAFE
    def enable_failsafe():
        """启用FAILSAFE"""
        pyautogui.FAILSAFE = True
        print("已重新启用FAILSAFE")

    # 测试禁用和启用
    # disable_failsafe()
    # enable_failsafe()
7.2.2 延迟控制与速度调节
import pyautogui
import time

def delay_control():
    """
    延迟控制与速度调节
    """

    # 查看当前PAUSE设置
    print(f"当前PAUSE设置: {pyautogui.PAUSE}秒")

    # 临时修改PAUSE
    original_pause = pyautogui.PAUSE
    pyautogui.PAUSE = 0.1
    print(f"已将PAUSE设置为: {pyautogui.PAUSE}秒")

    # 测试不同速度
    def test_speed(duration, description):
        """
        测试移动速度

        Args:
            duration: 移动持续时间
            description: 测试描述
        """
        print(f"\n{description} (duration={duration}秒):")
        start_time = time.time()
        pyautogui.moveTo(100, 100, duration=duration)
        pyautogui.moveTo(500, 100, duration=duration)
        pyautogui.moveTo(500, 300, duration=duration)
        pyautogui.moveTo(100, 300, duration=duration)
        pyautogui.moveTo(100, 100, duration=duration)
        elapsed = time.time() - start_time
        print(f"  实际耗时: {elapsed:.2f}秒")

    # 测试不同速度
    test_speed(0.1, "快速移动")
    test_speed(0.5, "中等速度")
    test_speed(1.0, "慢速移动")

    # 恢复原始PAUSE
    pyautogui.PAUSE = original_pause
    print(f"\n已恢复PAUSE设置: {pyautogui.PAUSE}秒")

    # 批量操作的速度控制
    def batch_operations_with_speed_control():
        """带速度控制的批量操作"""
        items = [f"item_{i}" for i in range(5)]

        # 快速模式
        print("\n快速模式:")
        pyautogui.PAUSE = 0.05
        start_time = time.time()
        for item in items:
            pyautogui.click(100, 100)
            pyautogui.write(item)
            pyautogui.press('enter')
        elapsed = time.time() - start_time
        print(f"  处理 {len(items)} 个项目耗时: {elapsed:.2f}秒")

        # 慢速模式
        print("\n慢速模式:")
        pyautogui.PAUSE = 0.5
        start_time = time.time()
        for item in items:
            pyautogui.click(100, 100)
            pyautogui.write(item)
            pyautogui.press('enter')
        elapsed = time.time() - start_time
        print(f"  处理 {len(items)} 个项目耗时: {elapsed:.2f}秒")

        # 恢复默认
        pyautogui.PAUSE = original_pause

    # 测试批量操作速度
    batch_operations_with_speed_control()

7.3 坐标系统与映射

7.3.1 屏幕坐标系统
import pyautogui

def coordinate_system():
    """
    屏幕坐标系统
    """

    # 获取屏幕尺寸
    screen_width, screen_height = pyautogui.size()
    print(f"屏幕尺寸: {screen_width}x{screen_height}")

    # 计算中心点
    center_x = screen_width // 2
    center_y = screen_height // 2
    print(f"屏幕中心: ({center_x}, {center_y})")

    # 关键坐标点
    key_points = {
        '左上角': (0, 0),
        '右上角': (screen_width - 1, 0),
        '左下角': (0, screen_height - 1),
        '右下角': (screen_width - 1, screen_height - 1),
        '中心': (center_x, center_y)
    }

    print("\n关键坐标点:")
    for name, (x, y) in key_points.items():
        print(f"  {name}: ({x}, {y})")

    # 坐标转换
    def relative_to_absolute(relative_x, relative_y):
        """
        相对坐标转绝对坐标

        Args:
            relative_x: 相对x坐标 (0.0-1.0)
            relative_y: 相对y坐标 (0.0-1.0)

        Returns:
            tuple: 绝对坐标
        """
        absolute_x = int(screen_width * relative_x)
        absolute_y = int(screen_height * relative_y)
        return (absolute_x, absolute_y)

    # 测试坐标转换
    relative_coords = [(0, 0), (0.5, 0.5), (1.0, 1.0), (0.25, 0.75)]
    print("\n相对坐标转绝对坐标:")
    for rel_x, rel_y in relative_coords:
        abs_x, abs_y = relative_to_absolute(rel_x, rel_y)
        print(f"  相对 ({rel_x:.2f}, {rel_y:.2f}) -> 绝对 ({abs_x}, {abs_y})")

    # 安全坐标检查
    def safe_coordinate(x, y):
        """
        确保坐标在安全范围内

        Args:
            x: x坐标
            y: y坐标

        Returns:
            tuple: 安全的坐标
        """
        safe_x = max(0, min(x, screen_width - 1))
        safe_y = max(0, min(y, screen_height - 1))
        return (safe_x, safe_y)

    # 测试安全坐标
    test_coords = [(-100, -100), (screen_width + 100, screen_height + 100), (center_x, center_y)]
    print("\n安全坐标检查:")
    for x, y in test_coords:
        safe_x, safe_y = safe_coordinate(x, y)
        print(f"  原始 ({x}, {y}) -> 安全 ({safe_x}, {safe_y})")
7.3.2 窗口坐标映射
import pyautogui

def window_coordinate_mapping():
    """
    窗口坐标映射
    """

    # 获取活动窗口位置(需要pygetwindow)
    try:
        import pygetwindow as gw
        # 获取当前活动窗口
        active_window = gw.getActiveWindow()
        if active_window:
            print(f"活动窗口: {active_window.title}")
            print(f"窗口位置: ({active_window.left}, {active_window.top})")
            print(f"窗口尺寸: {active_window.width}x{active_window.height}")

            # 窗口内坐标转换
            def window_to_screen(window, window_x, window_y):
                """
                窗口内坐标转屏幕坐标

                Args:
                    window: 窗口对象
                    window_x: 窗口内x坐标
                    window_y: 窗口内y坐标

                Returns:
                    tuple: 屏幕坐标
                """
                screen_x = window.left + window_x
                screen_y = window.top + window_y
                return (screen_x, screen_y)

            # 测试窗口坐标转换
            window_center_x = active_window.width // 2
            window_center_y = active_window.height // 2
            screen_x, screen_y = window_to_screen(active_window, window_center_x, window_center_y)
            print(f"\n窗口中心 -> 屏幕坐标:")
            print(f"  窗口内: ({window_center_x}, {window_center_y})")
            print(f"  屏幕: ({screen_x}, {screen_y})")

            # 点击窗口中心
            print("点击窗口中心")
            pyautogui.click(screen_x, screen_y)
        else:
            print("未找到活动窗口")
    except ImportError:
        print("未安装pygetwindow库")
        print("请运行: pip install pygetwindow")

    # 模拟窗口坐标映射
    def simulate_window_mapping(window_left, window_top, window_width, window_height):
        """
        模拟窗口坐标映射

        Args:
            window_left: 窗口左边界
            window_top: 窗口上边界
            window_width: 窗口宽度
            window_height: 窗口高度
        """
        print("\n模拟窗口坐标映射:")
        print(f"窗口位置: ({window_left}, {window_top})")
        print(f"窗口尺寸: {window_width}x{window_height}")

        # 计算窗口内关键点
        points = [
            ('左上角', 0, 0),
            ('右上角', window_width, 0),
            ('左下角', 0, window_height),
            ('右下角', window_width, window_height),
            ('中心', window_width // 2, window_height // 2)
        ]

        print("\n窗口内坐标 -> 屏幕坐标:")
        for name, wx, wy in points:
            sx = window_left + wx
            sy = window_top + wy
            print(f"  {name}: 窗口({wx}, {wy}) -> 屏幕({sx}, {sy})")

    # 测试模拟窗口映射
    simulate_window_mapping(100, 100, 800, 600)

7.4 高级控制技巧

7.4.1 上下文管理与资源释放
import pyautogui
import contextlib

def context_management():
    """
    上下文管理与资源释放
    """

    # 临时修改设置的上下文管理器
    @contextlib.contextmanager
    def temporary_settings(**kwargs):
        """
        临时修改PyAutoGUI设置

        Args:
            **kwargs: 要临时修改的设置
        """
        # 保存原始设置
        original_settings = {}
        for key, value in kwargs.items():
            if hasattr(pyautogui, key):
                original_settings[key] = getattr(pyautogui, key)
                setattr(pyautogui, key, value)

        try:
            yield
        finally:
            # 恢复原始设置
            for key, value in original_settings.items():
                setattr(pyautogui, key, value)

    # 测试上下文管理器
    print(f"原始PAUSE: {pyautogui.PAUSE}")
    print(f"原始FAILSAFE: {pyautogui.FAILSAFE}")

    with temporary_settings(PAUSE=0.01, FAILSAFE=False):
        print(f"临时PAUSE: {pyautogui.PAUSE}")
        print(f"临时FAILSAFE: {pyautogui.FAILSAFE}")
        # 执行快速操作
        pyautogui.moveTo(100, 100, duration=0.1)
        pyautogui.click()

    print(f"恢复后PAUSE: {pyautogui.PAUSE}")
    print(f"恢复后FAILSAFE: {pyautogui.FAILSAFE}")

    # 资源管理
    def safe_operation():
        """
        安全的操作包装
        """
        try:
            # 执行操作
            pyautogui.moveTo(100, 100)
            pyautogui.click()
            pyautogui.write("Test")
            return True
        except Exception as e:
            print(f"操作失败: {e}")
            return False
        finally:
            # 确保资源释放
            pass

    # 测试安全操作
    success = safe_operation()
    print(f"操作结果: {'成功' if success else '失败'}")

    # 批量操作的上下文管理
    def batch_operations(items):
        """
        批量操作

        Args:
            items: 操作项列表
        """
        with temporary_settings(PAUSE=0.05):
            for i, item in enumerate(items):
                print(f"处理项目 {i+1}/{len(items)}")
                pyautogui.click(100, 100 + i * 20)
                pyautogui.write(item)
                pyautogui.press('enter')

    # 测试批量操作
    test_items = ["item1", "item2", "item3"]
    batch_operations(test_items)
7.4.2 事件驱动操作
import pyautogui
import time
import threading

def event_driven_operations():
    """
    事件驱动操作
    """

    # 事件类
    class PyAutoGUIEvent:
        """PyAutoGUI事件类"""

        def __init__(self):
            self._events = {}

        def on(self, event_name, callback):
            """
            注册事件回调

            Args:
                event_name: 事件名称
                callback: 回调函数
            """
            if event_name not in self._events:
                self._events[event_name] = []
            self._events[event_name].append(callback)

        def emit(self, event_name, *args, **kwargs):
            """
            触发事件

            Args:
                event_name: 事件名称
                *args: 位置参数
                **kwargs: 关键字参数
            """
            if event_name in self._events:
                for callback in self._events[event_name]:
                    try:
                        callback(*args, **kwargs)
                    except Exception as e:
                        print(f"事件处理失败: {e}")

    # 创建事件管理器
    events = PyAutoGUIEvent()

    # 注册事件
    def on_click(x, y):
        print(f"点击事件: ({x}, {y})")

    def on_move(x, y):
        print(f"移动事件: ({x}, {y})")

    events.on('click', on_click)
    events.on('move', on_move)

    # 模拟事件触发
    print("模拟事件触发:")
    events.emit('move', 100, 100)
    events.emit('click', 100, 100)

    # 监听鼠标位置变化
    def monitor_mouse_position(interval=0.5, duration=5):
        """
        监听鼠标位置变化

        Args:
            interval: 检查间隔
            duration: 监听时长
        """
        print(f"\n开始监听鼠标位置变化({duration}秒):")
        start_time = time.time()
        last_position = pyautogui.position()

        while time.time() - start_time < duration:
            current_position = pyautogui.position()
            if current_position != last_position:
                events.emit('move', *current_position)
                last_position = current_position
            time.sleep(interval)

        print("监听结束")

    # 测试鼠标位置监听
    monitor_mouse_position()

    # 异步操作
    def async_operation():
        """
        异步操作
        """
        def long_operation():
            """长时间操作"""
            print("开始长时间操作...")
            time.sleep(3)
            print("长时间操作完成")
            events.emit('operation_complete', 'success')

        # 启动异步线程
        thread = threading.Thread(target=long_operation)
        thread.daemon = True
        thread.start()

        # 主线程继续执行
        print("主线程继续执行")
        for i in range(5):
            print(f"主线程工作 {i+1}/5")
            time.sleep(0.5)

    # 注册操作完成事件
    def on_operation_complete(status):
        print(f"操作完成,状态: {status}")

    events.on('operation_complete', on_operation_complete)

    # 测试异步操作
    async_operation()
7.4.3 条件执行与智能判断
import pyautogui
import time

def conditional_execution():
    """
    条件执行与智能判断
    """

    # 等待条件满足
    def wait_for_condition(condition, timeout=10, interval=0.5):
        """
        等待条件满足

        Args:
            condition: 条件函数(返回bool)
            timeout: 超时时间
            interval: 检查间隔

        Returns:
            bool: 条件是否满足
        """
        start_time = time.time()
        while time.time() - start_time < timeout:
            if condition():
                return True
            time.sleep(interval)
        return False

    # 示例条件:鼠标在特定区域
    def mouse_in_region(x1, y1, x2, y2):
        """
        检查鼠标是否在指定区域

        Args:
            x1, y1: 区域左上角
            x2, y2: 区域右下角

        Returns:
            bool: 是否在区域内
        """
        mouse_x, mouse_y = pyautogui.position()
        return x1 <= mouse_x <= x2 and y1 <= mouse_y <= y2

    # 测试条件等待
    print("请将鼠标移动到区域 (100, 100) 到 (300, 300) 内")
    success = wait_for_condition(lambda: mouse_in_region(100, 100, 300, 300), timeout=10)
    print(f"条件满足: {success}")

    # 智能重试
    def smart_retry(operation, max_retries=3, delay=1):
        """
        智能重试

        Args:
            operation: 操作函数
            max_retries: 最大重试次数
            delay: 重试间隔

        Returns:
            操作结果
        """
        for attempt in range(max_retries):
            try:
                result = operation()
                return result
            except Exception as e:
                print(f"尝试 {attempt+1}/{max_retries} 失败: {e}")
                if attempt < max_retries - 1:
                    time.sleep(delay)
                else:
                    raise

    # 测试智能重试
    def flaky_operation():
        """不稳定的操作"""
        import random
        if random.random() < 0.7:
            raise Exception("随机失败")
        return "成功"

    try:
        result = smart_retry(flaky_operation, max_retries=5)
        print(f"操作结果: {result}")
    except Exception as e:
        print(f"所有尝试都失败: {e}")

    # 条件分支
    def conditional_branch():
        """
        条件分支执行
        """
        # 检查屏幕尺寸
        screen_width, screen_height = pyautogui.size()

        if screen_width > 1920:
            print("大屏幕模式")
            # 大屏幕操作
            pyautogui.moveTo(screen_width // 2, screen_height // 2)
        elif screen_width > 1366:
            print("中等屏幕模式")
            # 中等屏幕操作
            pyautogui.moveTo(screen_width // 2, screen_height // 2)
        else:
            print("小屏幕模式")
            # 小屏幕操作
            pyautogui.moveTo(screen_width // 2, screen_height // 2)

    # 测试条件分支
    conditional_branch()

7.5 高级应用技巧

7.5.1 模拟复杂用户操作
import pyautogui
import time

def complex_user_operations():
    """
    模拟复杂用户操作
    """

    # 模拟用户登录
    def simulate_login(username, password):
        """
        模拟用户登录

        Args:
            username: 用户名
            password: 密码
        """
        print("开始模拟登录...")

        # 打开登录窗口(假设已打开)
        # pyautogui.hotkey('win', 'r')
        # pyautogui.write('notepad')
        # pyautogui.press('enter')

        # 输入用户名
        print("输入用户名")
        pyautogui.write(username)
        pyautogui.press('tab')

        # 输入密码
        print("输入密码")
        pyautogui.write(password)
        pyautogui.press('enter')

        print("登录完成")

    # 测试登录模拟
    # simulate_login('testuser', 'password123')

    # 模拟文件操作
    def simulate_file_operation():
        """
        模拟文件操作
        """
        print("开始模拟文件操作...")

        # 打开文件浏览器
        pyautogui.hotkey('win', 'e')
        time.sleep(1)

        # 导航到桌面
        pyautogui.write('Desktop')
        pyautogui.press('enter')
        time.sleep(1)

        # 创建新文件夹
        pyautogui.hotkey('ctrl', 'shift', 'n')
        time.sleep(0.5)
        pyautogui.write('Test Folder')
        pyautogui.press('enter')

        # 双击打开文件夹
        pyautogui.doubleClick(100, 100)  # 假设文件夹在(100, 100)
        time.sleep(1)

        # 关闭窗口
        pyautogui.hotkey('alt', 'f4')

        print("文件操作完成")

    # 测试文件操作
    # simulate_file_operation()

    # 模拟网页操作
    def simulate_web_browsing():
        """
        模拟网页浏览
        """
        print("开始模拟网页浏览...")

        # 打开浏览器
        pyautogui.hotkey('win', 'r')
        pyautogui.write('chrome')
        pyautogui.press('enter')
        time.sleep(2)

        # 访问网站
        pyautogui.write('https://www.baidu.com')
        pyautogui.press('enter')
        time.sleep(3)

        # 搜索
        pyautogui.write('PyAutoGUI')
        pyautogui.press('enter')
        time.sleep(2)

        # 点击链接
        # 注意:实际坐标需要根据屏幕调整
        # pyautogui.click(500, 300)

        # 关闭浏览器
        pyautogui.hotkey('alt', 'f4')

        print("网页浏览完成")

    # 测试网页浏览
    # simulate_web_browsing()
7.5.2 自动化工作流
import pyautogui
import time

def automation_workflow():
    """
    自动化工作流
    """

    # 工作流类
    class Workflow:
        """自动化工作流类"""

        def __init__(self):
            self.steps = []

        def add_step(self, name, action, *args, **kwargs):
            """
            添加工作流步骤

            Args:
                name: 步骤名称
                action: 操作函数
                *args: 位置参数
                **kwargs: 关键字参数
            """
            self.steps.append({
                'name': name,
                'action': action,
                'args': args,
                'kwargs': kwargs
            })

        def run(self):
            """
            运行工作流
            """
            print(f"开始执行工作流,共 {len(self.steps)} 个步骤")
            
            for i, step in enumerate(self.steps, 1):
                print(f"执行步骤 {i}/{len(self.steps)}: {step['name']}")
                try:
                    step['action'](*step['args'], **step['kwargs'])
                    print(f"步骤 {i} 完成")
                except Exception as e:
                    print(f"步骤 {i} 失败: {e}")
                    # 可以添加错误处理逻辑
                time.sleep(1)  # 步骤间延迟

            print("工作流执行完成")

    # 创建工作流
    workflow = Workflow()

    # 定义步骤函数
    def open_application(app_name):
        """打开应用程序"""
        pyautogui.hotkey('win', 'r')
        pyautogui.write(app_name)
        pyautogui.press('enter')
        time.sleep(2)

    def enter_text(text):
        """输入文本"""
        pyautogui.write(text)

    def click_button(x, y):
        """点击按钮"""
        pyautogui.click(x, y)

    def close_application():
        """关闭应用程序"""
        pyautogui.hotkey('alt', 'f4')

    # 添加步骤
    workflow.add_step('打开记事本', open_application, 'notepad')
    workflow.add_step('输入标题', enter_text, 'PyAutoGUI 自动化测试\n')
    workflow.add_step('输入内容', enter_text, '这是一个自动化测试示例\n使用工作流管理多个操作步骤')
    workflow.add_step('点击编辑菜单', click_button, 50, 20)  # 假设坐标
    workflow.add_step('关闭记事本', close_application)

    # 运行工作流
    # workflow.run()

    # 条件工作流
    def conditional_workflow():
        """
        条件工作流
        """
        print("开始条件工作流")

        # 检查屏幕尺寸
        screen_width, screen_height = pyautogui.size()

        if screen_width >= 1920:
            print("高分辨率屏幕,执行A工作流")
            # 执行A工作流
        else:
            print("低分辨率屏幕,执行B工作流")
            # 执行B工作流

    # 测试条件工作流
    conditional_workflow()
7.5.3 性能优化技巧
import pyautogui
import time

def performance_optimization():
    """
    性能优化技巧
    """

    # 批量操作优化
    def batch_optimization():
        """
        批量操作优化
        """
        items = list(range(100))

        # 传统方法
        print("传统方法:")
        start_time = time.time()
        for item in items:
            pyautogui.moveTo(100, 100)
            pyautogui.click()
            pyautogui.write(str(item))
            pyautogui.press('enter')
        elapsed = time.time() - start_time
        print(f"  处理 {len(items)} 个项目耗时: {elapsed:.2f}秒")

        # 优化方法
        print("\n优化方法:")
        start_time = time.time()
        original_pause = pyautogui.PAUSE
        pyautogui.PAUSE = 0.01

        try:
            for item in items:
                pyautogui.moveTo(100, 100)
                pyautogui.click()
                pyautogui.write(str(item))
                pyautogui.press('enter')
        finally:
            pyautogui.PAUSE = original_pause

        elapsed = time.time() - start_time
        print(f"  处理 {len(items)} 个项目耗时: {elapsed:.2f}秒")

    # 测试批量优化
    # batch_optimization()

    # 坐标缓存
    def coordinate_caching():
        """
        坐标缓存
        """
        # 缓存常用坐标
        coordinates = {
            'button_ok': (100, 100),
            'button_cancel': (200, 100),
            'input_field': (150, 150)
        }

        print("使用坐标缓存:")
        start_time = time.time()

        for _ in range(100):
            # 从缓存获取坐标
            pyautogui.click(coordinates['button_ok'])
            pyautogui.click(coordinates['input_field'])
            pyautogui.click(coordinates['button_cancel'])

        elapsed = time.time() - start_time
        print(f"  执行100次操作耗时: {elapsed:.2f}秒")

    # 测试坐标缓存
    coordinate_caching()

    # 并行操作
    def parallel_operations():
        """
        并行操作
        """
        import threading

        def task1():
            """任务1"""
            for i in range(10):
                pyautogui.moveTo(100, 100 + i * 10)
                time.sleep(0.1)

        def task2():
            """任务2"""
            for i in range(10):
                pyautogui.moveTo(200, 100 + i * 10)
                time.sleep(0.1)

        print("\n并行操作:")
        start_time = time.time()

        # 创建线程
        thread1 = threading.Thread(target=task1)
        thread2 = threading.Thread(target=task2)

        # 启动线程
        thread1.start()
        thread2.start()

        # 等待完成
        thread1.join()
        thread2.join()

        elapsed = time.time() - start_time
        print(f"  并行执行耗时: {elapsed:.2f}秒")

    # 测试并行操作
    parallel_operations()

    # 减少屏幕交互
    def reduce_screen_interactions():
        """
        减少屏幕交互
        """
        print("\n减少屏幕交互:")

        # 直接操作vs屏幕操作
        start_time = time.time()

        # 直接操作(如果可能)
        # 这里只是示例,实际应用中需要根据具体情况
        print("  执行直接操作")

        elapsed = time.time() - start_time
        print(f"  直接操作耗时: {elapsed:.2f}秒")

        # 屏幕操作
        start_time = time.time()
        pyautogui.moveTo(100, 100)
        pyautogui.click()
        pyautogui.write("test")
        pyautogui.press('enter')

        elapsed = time.time() - start_time
        print(f"  屏幕操作耗时: {elapsed:.2f}秒")

    # 测试减少屏幕交互
    reduce_screen_interactions()

第8章 生产环境最佳实践

8.1 异常处理与容错机制

在生产环境中,异常处理是保证自动化脚本稳定运行的关键。

8.1.1 基本异常处理
import pyautogui
import traceback

def safe_automation():
    """
    安全的自动化操作,包含异常处理
    """
    try:
        # 执行自动化操作
        pyautogui.moveTo(100, 100, duration=0.5)
        pyautogui.click()
        pyautogui.write('Test', interval=0.1)
        
    except pyautogui.FailSafeException:
        print("检测到FAILSAFE信号,脚本已停止")
        return False
    except pyautogui.ImageNotFoundException:
        print("未找到目标图像")
        return False
    except Exception as e:
        print(f"发生异常: {e}")
        print(traceback.format_exc())
        return False
    else:
        print("操作执行成功")
        return True

# 调用示例
if __name__ == "__main__":
    success = safe_automation()
    if not success:
        print("自动化操作失败,需要人工干预")
8.1.2 高级异常处理策略
import pyautogui
import time
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('automation.log'),
        logging.StreamHandler()
    ]
)

def retry_operation(max_attempts=3, delay=1):
    """
    带重试机制的操作装饰器
    
    Args:
        max_attempts: 最大尝试次数
        delay: 重试间隔(秒)
    """
    def decorator(func):
        def wrapper(*args, **kwargs):
            attempts = 0
            while attempts < max_attempts:
                try:
                    result = func(*args, **kwargs)
                    return result
                except Exception as e:
                    attempts += 1
                    logging.warning(f"操作失败 (尝试 {attempts}/{max_attempts}): {e}")
                    if attempts < max_attempts:
                        time.sleep(delay)
                    else:
                        logging.error(f"操作最终失败: {e}")
                        raise
        return wrapper
    return decorator

@retry_operation(max_attempts=3, delay=2)
def locate_and_click(image_path, confidence=0.8):
    """
    定位并点击图像
    """
    logging.info(f"尝试定位图像: {image_path}")
    position = pyautogui.locateCenterOnScreen(
        image_path,
        confidence=confidence
    )
    
    if position is None:
        raise pyautogui.ImageNotFoundException(f"未找到图像: {image_path}")
    
    pyautogui.click(position)
    logging.info(f"点击位置: {position}")
    return position

# 调用示例
if __name__ == "__main__":
    try:
        locate_and_click('button.png')
    except Exception as e:
        logging.error(f"自动化流程失败: {e}")

8.2 日志记录与监控

8.2.1 结构化日志
import pyautogui
import logging
import json
from datetime import datetime

# 配置结构化日志
class JsonFormatter(logging.Formatter):
    def format(self, record):
        log_record = {
            'timestamp': datetime.utcnow().isoformat(),
            'level': record.levelname,
            'message': record.getMessage(),
            'module': record.module,
            'function': record.funcName,
            'line': record.lineno
        }
        return json.dumps(log_record)

# 设置日志
logger = logging.getLogger('pyautogui_automation')
logger.setLevel(logging.INFO)

# 添加文件处理器
file_handler = logging.FileHandler('automation.log')
file_handler.setFormatter(JsonFormatter())
logger.addHandler(file_handler)

# 添加控制台处理器
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
logger.addHandler(console_handler)

def automated_workflow():
    """
    自动化工作流
    """
    logger.info("开始自动化工作流")
    
    try:
        # 步骤1:启动应用
        logger.info("启动应用")
        pyautogui.press('win')
        pyautogui.write('notepad', interval=0.1)
        pyautogui.press('enter')
        time.sleep(1)
        
        # 步骤2:输入文本
        logger.info("输入示例文本")
        pyautogui.write('Hello, PyAutoGUI!', interval=0.05)
        
        # 步骤3:保存文件
        logger.info("保存文件")
        pyautogui.hotkey('ctrl', 's')
        time.sleep(0.5)
        pyautogui.write('test.txt', interval=0.05)
        pyautogui.press('enter')
        
        logger.info("工作流执行成功")
        return True
        
    except Exception as e:
        logger.error(f"工作流执行失败: {str(e)}")
        return False

if __name__ == "__main__":
    automated_workflow()
8.2.2 监控与告警
import pyautogui
import time
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

class AutomationMonitor:
    """
    自动化监控类
    """
    def __init__(self, alert_email=None):
        self.alert_email = alert_email
        self.start_time = None
        self.end_time = None
    
    def start(self):
        """开始监控"""
        self.start_time = time.time()
        print(f"监控开始: {time.strftime('%Y-%m-%d %H:%M:%S')}")
    
    def end(self):
        """结束监控"""
        self.end_time = time.time()
        duration = self.end_time - self.start_time
        print(f"监控结束: {time.strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"执行时间: {duration:.2f} 秒")
    
    def send_alert(self, subject, message):
        """发送告警邮件"""
        if not self.alert_email:
            return
        
        try:
            # 邮件配置
            sender = "automation@example.com"
            password = "your_password"  # 实际使用时应从环境变量获取
            smtp_server = "smtp.example.com"
            smtp_port = 587
            
            # 创建邮件
            msg = MIMEMultipart()
            msg['From'] = sender
            msg['To'] = self.alert_email
            msg['Subject'] = subject
            msg.attach(MIMEText(message, 'plain'))
            
            # 发送邮件
            with smtplib.SMTP(smtp_server, smtp_port) as server:
                server.starttls()
                server.login(sender, password)
                server.send_message(msg)
            
            print(f"告警邮件已发送到 {self.alert_email}")
            
        except Exception as e:
            print(f"发送告警邮件失败: {e}")

def critical_operation():
    """
    关键操作
    """
    monitor = AutomationMonitor(alert_email="admin@example.com")
    monitor.start()
    
    try:
        # 执行关键操作
        pyautogui.moveTo(100, 100, duration=0.5)
        pyautogui.click()
        # ... 其他操作 ...
        
        monitor.end()
        print("关键操作执行成功")
        
    except Exception as e:
        monitor.end()
        error_msg = f"关键操作执行失败: {str(e)}"
        print(error_msg)
        monitor.send_alert("自动化操作失败", error_msg)

if __name__ == "__main__":
    critical_operation()

8.3 性能优化策略

8.3.1 执行速度优化
import pyautogui
import time
import cProfile

def optimize_performance():
    """
    性能优化示例
    """
    # 1. 减少延迟
    original_pause = pyautogui.PAUSE
    pyautogui.PAUSE = 0.01  # 减少默认延迟
    
    try:
        # 2. 批量操作
        start_time = time.time()
        
        # 优化前:逐个点击
        print("优化前 - 逐个点击:")
        for i in range(10):
            pyautogui.click(100 + i*20, 100)
        
        time1 = time.time() - start_time
        print(f"耗时: {time1:.3f}秒")
        
        # 优化后:直接移动+点击
        start_time = time.time()
        print("\n优化后 - 直接移动+点击:")
        for i in range(10):
            x, y = 100 + i*20, 100
            pyautogui.moveTo(x, y, duration=0.05)
            pyautogui.click()
        
        time2 = time.time() - start_time
        print(f"耗时: {time2:.3f}秒")
        print(f"性能提升: {((time1 - time2) / time1 * 100):.1f}%")
        
    finally:
        # 恢复默认设置
        pyautogui.PAUSE = original_pause

def profile_automation():
    """
    性能分析
    """
    def test_workflow():
        for _ in range(5):
            pyautogui.moveTo(100, 100, duration=0.1)
            pyautogui.click()
            pyautogui.write('test', interval=0.05)
            pyautogui.press('enter')
    
    print("性能分析:")
    cProfile.run('test_workflow()')

if __name__ == "__main__":
    optimize_performance()
    print("\n" + "="*50 + "\n")
    profile_automation()
8.3.2 内存优化
import pyautogui
import gc
import psutil
import os

def memory_optimization():
    """
    内存优化示例
    """
    def get_memory_usage():
        """获取当前内存使用情况"""
        process = psutil.Process(os.getpid())
        return process.memory_info().rss / 1024 / 1024  # MB
    
    print(f"初始内存使用: {get_memory_usage():.2f} MB")
    
    # 模拟内存密集操作
    screenshots = []
    for i in range(10):
        screenshot = pyautogui.screenshot()
        screenshots.append(screenshot)
        print(f"截图 {i+1} 后内存使用: {get_memory_usage():.2f} MB")
    
    # 释放内存
    print("\n释放内存:")
    del screenshots
    gc.collect()
    print(f"释放后内存使用: {get_memory_usage():.2f} MB")

def efficient_screenshot():
    """
    高效截图方法
    """
    # 1. 只截取需要的区域
    region = (0, 0, 800, 600)
    print("截取指定区域:")
    screenshot = pyautogui.screenshot(region=region)
    print(f"区域截图大小: {screenshot.size}")
    
    # 2. 直接保存到文件,避免内存中存储
    print("\n直接保存到文件:")
    pyautogui.screenshot('region.png', region=region)
    print("截图已保存到 region.png")

if __name__ == "__main__":
    memory_optimization()
    print("\n" + "="*50 + "\n")
    efficient_screenshot()

8.4 跨平台兼容性

8.4.1 平台检测与适配
import pyautogui
import platform
import sys

def platform_specific_operations():
    """
    平台特定操作
    """
    current_platform = platform.system()
    print(f"当前平台: {current_platform}")
    
    if current_platform == 'Windows':
        # Windows 特定操作
        print("执行 Windows 特定操作")
        # 打开开始菜单
        pyautogui.press('win')
        time.sleep(0.5)
        pyautogui.write('notepad', interval=0.1)
        pyautogui.press('enter')
        
    elif current_platform == 'Darwin':  # macOS
        print("执行 macOS 特定操作")
        # 打开 Spotlight
        pyautogui.hotkey('command', 'space')
        time.sleep(0.5)
        pyautogui.write('textedit', interval=0.1)
        pyautogui.press('enter')
        
    elif current_platform == 'Linux':
        print("执行 Linux 特定操作")
        # 打开应用启动器 (Ubuntu Unity)
        pyautogui.hotkey('super')
        time.sleep(0.5)
        pyautogui.write('gedit', interval=0.1)
        pyautogui.press('enter')
        
    else:
        print(f"未知平台: {current_platform}")

def cross_platform_coordinates():
    """
    跨平台坐标处理
    """
    # 获取屏幕尺寸
    screen_width, screen_height = pyautogui.size()
    print(f"屏幕尺寸: {screen_width} x {screen_height}")
    
    # 使用相对坐标
    relative_positions = {
        'center': (0.5, 0.5),
        'top_left': (0.1, 0.1),
        'bottom_right': (0.9, 0.9)
    }
    
    print("相对坐标转换为绝对坐标:")
    for name, (rel_x, rel_y) in relative_positions.items():
        abs_x = int(screen_width * rel_x)
        abs_y = int(screen_height * rel_y)
        print(f"{name}: ({abs_x}, {abs_y})")
        
        # 移动到该位置
        pyautogui.moveTo(abs_x, abs_y, duration=0.5)
        time.sleep(0.2)

if __name__ == "__main__":
    platform_specific_operations()
    print("\n" + "="*50 + "\n")
    cross_platform_coordinates()
8.4.2 键盘布局适配
import pyautogui
import platform

def keyboard_layout_adapter():
    """
    键盘布局适配
    """
    current_platform = platform.system()
    
    # 平台特定的键盘操作
    key_mappings = {
        'Windows': {
            'copy': ['ctrl', 'c'],
            'paste': ['ctrl', 'v'],
            'save': ['ctrl', 's']
        },
        'Darwin': {
            'copy': ['command', 'c'],
            'paste': ['command', 'v'],
            'save': ['command', 's']
        },
        'Linux': {
            'copy': ['ctrl', 'c'],
            'paste': ['ctrl', 'v'],
            'save': ['ctrl', 's']
        }
    }
    
    # 获取当前平台的按键映射
    platform_mappings = key_mappings.get(current_platform, key_mappings['Linux'])
    
    print(f"当前平台: {current_platform}")
    print("按键映射:")
    for action, keys in platform_mappings.items():
        print(f"{action}: {'+'.join(keys)}")
    
    # 示例:执行复制操作
    print("\n执行复制操作:")
    pyautogui.hotkey(*platform_mappings['copy'])
    print("复制操作执行完成")

def unicode_compatibility():
    """
    Unicode 兼容性处理
    """
    # 测试 Unicode 输入
    test_texts = [
        "Hello World",
        "你好,世界",
        "こんにちは世界",
        "안녕하세요 세계"
    ]
    
    print("测试 Unicode 输入:")
    for text in test_texts:
        try:
            pyautogui.write(text, interval=0.1)
            pyautogui.press('enter')
            print(f"成功输入: {text}")
        except Exception as e:
            print(f"输入失败 {text}: {e}")
        time.sleep(0.5)

if __name__ == "__main__":
    keyboard_layout_adapter()
    print("\n" + "="*50 + "\n")
    unicode_compatibility()

8.5 CI/CD 集成

8.5.1 自动化测试集成
# .github/workflows/pyautogui-test.yml
"""
name: PyAutoGUI Automation Test

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '0 0 * * *'  # 每天执行

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.9'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install pyautogui opencv-python
        # 安装 Xvfb 用于无头测试
        sudo apt-get update
        sudo apt-get install -y xvfb
    
    - name: Run tests with Xvfb
      run: |
        Xvfb :99 -screen 0 1920x1080x24 &
        export DISPLAY=:99
        python test_automation.py
"""

# test_automation.py
import pyautogui
import time
import unittest

class TestAutomation(unittest.TestCase):
    """
    自动化测试用例
    """
    
    def setUp(self):
        """测试前准备"""
        pyautogui.PAUSE = 0.1
        pyautogui.FAILSAFE = False
    
    def test_basic_operations(self):
        """测试基本操作"""
        # 测试鼠标移动
        pyautogui.moveTo(100, 100, duration=0.5)
        self.assertAlmostEqual(pyautogui.position()[0], 100, delta=5)
        self.assertAlmostEqual(pyautogui.position()[1], 100, delta=5)
        
        # 测试点击
        pyautogui.click()
        
        # 测试键盘输入
        pyautogui.write('test', interval=0.05)
        
    def test_screen_size(self):
        """测试屏幕尺寸获取"""
        width, height = pyautogui.size()
        self.assertGreater(width, 0)
        self.assertGreater(height, 0)
    
    def tearDown(self):
        """测试后清理"""
        pass

if __name__ == '__main__':
    unittest.main()
8.5.2 持续集成最佳实践
import pyautogui
import os
import sys
import logging
from datetime import datetime

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    filename=f'ci_automation_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log'
)

def ci_automation_workflow():
    """
    CI 环境下的自动化工作流
    """
    try:
        logging.info("开始 CI 自动化工作流")
        
        # 1. 环境检查
        logging.info("检查环境")
        screen_width, screen_height = pyautogui.size()
        logging.info(f"屏幕尺寸: {screen_width} x {screen_height}")
        
        # 2. 执行自动化任务
        logging.info("执行自动化任务")
        
        # 示例:打开浏览器
        if sys.platform == 'win32':
            os.system('start chrome')
        elif sys.platform == 'darwin':
            os.system('open -a "Google Chrome"')
        else:
            os.system('google-chrome &')
        
        time.sleep(3)  # 等待浏览器启动
        
        # 3. 执行操作
        pyautogui.write('https://www.google.com', interval=0.05)
        pyautogui.press('enter')
        time.sleep(2)
        
        # 4. 验证结果
        logging.info("验证操作结果")
        # 这里可以添加图像识别验证
        
        logging.info("CI 自动化工作流执行成功")
        return True
        
    except Exception as e:
        logging.error(f"CI 自动化工作流失败: {str(e)}")
        return False

if __name__ == "__main__":
    success = ci_automation_workflow()
    sys.exit(0 if success else 1)

8.6 安全考虑

8.6.1 安全最佳实践
import pyautogui
import os
import getpass
import cryptography
from cryptography.fernet import Fernet

def secure_credentials():
    """
    安全处理凭证
    
    安全警告:
    1. 以下代码中的用户名和密码仅为演示用途
    2. 生产环境中绝不要硬编码敏感信息
    3. 建议使用环境变量、配置文件或密钥管理服务
    4. 密钥应安全存储,不要提交到版本控制
    """
    import os
    
    # 生成密钥(实际应用中应存储在安全位置,如环境变量或密钥管理服务)
    key = Fernet.generate_key()
    cipher_suite = Fernet(key)
    
    # 警告:以下硬编码的凭据仅用于演示
    # 生产环境应从环境变量或安全存储中获取
    # 例如:username = os.environ.get('APP_USERNAME')
    #       password = os.environ.get('APP_PASSWORD')
    
    print("警告:以下使用的是演示凭据,请勿在生产环境中使用!")
    username = "admin"  # 演示用途,实际应从环境变量获取
    password = "secure_password"  # 演示用途,实际应从环境变量获取
    
    print(f"原始用户名: {username}")
    print(f"原始密码: {'*' * len(password)} (已隐藏)")
    
    encrypted_username = cipher_suite.encrypt(username.encode())
    encrypted_password = cipher_suite.encrypt(password.encode())
    
    print(f"\n加密后的用户名: {encrypted_username}")
    print(f"加密后的密码: {encrypted_password}")
    
    # 解密使用
    decrypted_username = cipher_suite.decrypt(encrypted_username).decode()
    decrypted_password = cipher_suite.decrypt(encrypted_password).decode()
    
    print(f"\n解密后的用户名: {decrypted_username}")
    print(f"解密后的密码: {'*' * len(decrypted_password)} (已隐藏)")
    
    print("\n安全建议:")
    print("1. 使用环境变量存储敏感信息: os.environ.get('KEY')")
    print("2. 使用 .env 文件配合 python-dotenv 库")
    print("3. 考虑使用 AWS KMS、Azure Key Vault 等密钥管理服务")
    print("4. 定期轮换密钥和密码")
    print("5. 不要将密钥提交到Git等版本控制系统")

def safe_automation_boundaries():
    """
    安全自动化边界
    """
    # 设置操作边界
    SCREEN_WIDTH, SCREEN_HEIGHT = pyautogui.size()
    SAFE_AREA = (100, 100, SCREEN_WIDTH - 100, SCREEN_HEIGHT - 100)
    
    def validate_position(x, y):
        """验证位置是否在安全区域内"""
        return (SAFE_AREA[0] <= x <= SAFE_AREA[2] and 
                SAFE_AREA[1] <= y <= SAFE_AREA[3])
    
    def safe_move_to(x, y, duration=0.5):
        """安全移动鼠标"""
        if validate_position(x, y):
            pyautogui.moveTo(x, y, duration=duration)
            print(f"安全移动到 ({x}, {y})")
        else:
            print(f"位置 ({x}, {y}) 超出安全区域")
    
    # 测试安全移动
    safe_move_to(50, 50)  # 超出安全区域
    safe_move_to(200, 200)  # 在安全区域内
    safe_move_to(SCREEN_WIDTH - 50, SCREEN_HEIGHT - 50)  # 超出安全区域

if __name__ == "__main__":
    secure_credentials()
    print("\n" + "="*50 + "\n")
    safe_automation_boundaries()
8.6.2 权限管理
import pyautogui
import os
import stat
import getpass

def check_permissions():
    """
    检查权限
    """
    current_user = getpass.getuser()
    print(f"当前用户: {current_user}")
    
    # 检查文件权限
    test_file = "test.txt"
    if not os.path.exists(test_file):
        with open(test_file, 'w') as f:
            f.write("test")
    
    file_stats = os.stat(test_file)
    print(f"文件权限: {oct(file_stats.st_mode)[-3:]}")
    
    # 检查是否有写入权限
    if os.access(test_file, os.W_OK):
        print("有写入权限")
    else:
        print("无写入权限")
    
    # 清理测试文件
    if os.path.exists(test_file):
        os.remove(test_file)

def run_as_admin():
    """
    以管理员权限运行
    """
    import ctypes
    import sys
    
    def is_admin():
        try:
            return ctypes.windll.shell32.IsUserAnAdmin()
        except:
            return False
    
    if is_admin():
        print("当前以管理员权限运行")
        # 执行需要管理员权限的操作
        pyautogui.moveTo(100, 100)
        pyautogui.click()
    else:
        print("当前未以管理员权限运行")
        print("请以管理员权限运行此脚本")

if __name__ == "__main__":
    check_permissions()
    print("\n" + "="*50 + "\n")
    run_as_admin()

8.7 监控与维护

8.7.1 健康检查
import pyautogui
import time
import psutil
import platform

def system_health_check():
    """
    系统健康检查
    """
    print("系统健康检查:")
    
    # 1. 系统信息
    print("\n系统信息:")
    print(f"操作系统: {platform.system()} {platform.version()}")
    print(f"Python版本: {platform.python_version()}")
    
    # 2. 资源使用
    print("\n资源使用:")
    cpu_percent = psutil.cpu_percent(interval=1)
    memory = psutil.virtual_memory()
    disk = psutil.disk_usage('/')
    
    print(f"CPU使用率: {cpu_percent}%")
    print(f"内存使用率: {memory.percent}%")
    print(f"磁盘使用率: {disk.percent}%")
    
    # 3. 屏幕状态
    print("\n屏幕状态:")
    screen_width, screen_height = pyautogui.size()
    print(f"屏幕分辨率: {screen_width} x {screen_height}")
    
    # 4. 鼠标状态
    mouse_x, mouse_y = pyautogui.position()
    print(f"鼠标位置: ({mouse_x}, {mouse_y})")
    
    # 5. 网络状态
    print("\n网络状态:")
    net_io = psutil.net_io_counters()
    print(f"发送字节: {net_io.bytes_sent / 1024 / 1024:.2f} MB")
    print(f"接收字节: {net_io.bytes_recv / 1024 / 1024:.2f} MB")

def automated_maintenance():
    """
    自动化维护
    """
    print("自动化维护任务:")
    
    # 1. 清理临时文件
    print("\n1. 清理临时文件:")
    import tempfile
    temp_dir = tempfile.gettempdir()
    print(f"临时目录: {temp_dir}")
    
    # 2. 检查更新
    print("\n2. 检查更新:")
    try:
        import pip
        result = pip.main(['list', '--outdated'])
        if result == 0:
            print("更新检查完成")
    except Exception as e:
        print(f"更新检查失败: {e}")
    
    # 3. 系统重启提示
    print("\n3. 系统状态:")
    boot_time = psutil.boot_time()
    uptime = time.time() - boot_time
    uptime_days = uptime / 86400
    print(f"系统运行时间: {uptime_days:.1f} 天")
    
    if uptime_days > 7:
        print("建议重启系统以保持最佳性能")

if __name__ == "__main__":
    system_health_check()
    print("\n" + "="*50 + "\n")
    automated_maintenance()

8.8 最佳实践总结

8.8.1 生产环境自动化 checklist
# 生产环境自动化 checklist
PRODUCTION_CHECKLIST = [
    # 基础配置
    "启用 FAILSAFE 机制",
    "设置合理的 PAUSE 值",
    "配置日志记录",
    
    # 异常处理
    "实现全面的异常捕获",
    "添加重试机制",
    "设置超时处理",
    
    # 性能优化
    "使用相对坐标",
    "优化截图操作",
    "减少不必要的延迟",
    
    # 跨平台兼容
    "检测并适配不同平台",
    "处理键盘布局差异",
    "使用相对路径",
    
    # 安全考虑
    "加密敏感信息",
    "设置操作边界",
    "权限管理",
    
    # 监控与维护
    "实现健康检查",
    "设置告警机制",
    "定期维护",
    
    # CI/CD 集成
    "编写自动化测试",
    "配置持续集成",
    "自动化部署",
]

def run_checklist():
    """
    运行生产环境检查清单
    """
    print("生产环境自动化检查清单:")
    print("=" * 60)
    
    for i, item in enumerate(PRODUCTION_CHECKLIST, 1):
        print(f"{i:2d}. {item}")
    
    print("=" * 60)
    print("请确保所有项目都已实现")

if __name__ == "__main__":
    run_checklist()
8.8.2 自动化脚本模板
"""
PyAutoGUI 生产环境自动化脚本模板
"""

import pyautogui
import time
import logging
import traceback
import argparse
import sys

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('automation.log'),
        logging.StreamHandler()
    ]
)

class AutomationWorkflow:
    """
    自动化工作流类
    """
    def __init__(self):
        self.setup_environment()
    
    def setup_environment(self):
        """
        设置环境
        """
        # 启用安全机制
        pyautogui.FAILSAFE = True
        # 设置合理的延迟
        pyautogui.PAUSE = 0.1
        logging.info("环境设置完成")
    
    def run(self):
        """
        运行工作流
        """
        try:
            logging.info("开始自动化工作流")
            
            # 步骤 1: 准备
            self.prepare()
            
            # 步骤 2: 执行主要操作
            self.execute_main_operations()
            
            # 步骤 3: 验证结果
            self.verify_results()
            
            # 步骤 4: 清理
            self.cleanup()
            
            logging.info("工作流执行成功")
            return True
            
        except pyautogui.FailSafeException:
            logging.warning("检测到 FAILSAFE 信号,工作流已停止")
            return False
        except Exception as e:
            logging.error(f"工作流执行失败: {str(e)}")
            logging.error(traceback.format_exc())
            return False
    
    def prepare(self):
        """
        准备工作
        """
        logging.info("执行准备工作")
        # 示例:打开应用
        # pyautogui.press('win')
        # pyautogui.write('notepad')
        # pyautogui.press('enter')
        # time.sleep(1)
    
    def execute_main_operations(self):
        """
        执行主要操作
        """
        logging.info("执行主要操作")
        # 实现具体的自动化操作
    
    def verify_results(self):
        """
        验证结果
        """
        logging.info("验证操作结果")
        # 实现结果验证
    
    def cleanup(self):
        """
        清理工作
        """
        logging.info("执行清理工作")
        # 实现清理操作

def main():
    """
    主函数
    """
    parser = argparse.ArgumentParser(description='PyAutoGUI 自动化脚本')
    parser.add_argument('--test', action='store_true', help='运行测试模式')
    args = parser.parse_args()
    
    workflow = AutomationWorkflow()
    success = workflow.run()
    
    if args.test:
        logging.info(f"测试模式 - 执行结果: {'成功' if success else '失败'}")
    
    sys.exit(0 if success else 1)

if __name__ == "__main__":
    main()

第9章 常见问题与解决方案

9.1 安装与环境问题

9.1.1 安装失败

问题现象:使用 pip install pyautogui 安装失败。

可能原因

  • 网络连接问题
  • 依赖库安装失败
  • Python版本不兼容

解决方案

# 1. 确保网络连接正常
# 2. 安装依赖库
pip install Pillow pymsgbox pytweening pyscreeze

# 3. 安装PyAutoGUI
pip install pyautogui

# 4. 完整安装(包含所有依赖)
pip install pyautogui[opencv]

# 5. 对于macOS
pip install pyobjc-core pyobjc

代码示例

# 检查PyAutoGUI是否安装成功
import pyautogui

print(f"PyAutoGUI版本: {pyautogui.__version__}")
print("安装成功!")
9.1.2 环境依赖问题

问题现象:运行脚本时出现依赖库错误。

可能原因

  • 缺少必要的依赖库
  • 依赖库版本不兼容

解决方案

# 安装所有必要的依赖
pip install -r requirements.txt

requirements.txt

pillow>=9.0.0
pymsgbox>=1.0.9
pytweening>=1.0.4
pyscreeze>=0.1.28
opencv-python>=4.5.0

9.2 鼠标操作问题

9.2.1 鼠标移动不准确

问题现象:鼠标移动到指定位置时偏差较大。

可能原因

  • 屏幕分辨率设置问题
  • DPI缩放影响
  • 坐标系统理解错误

解决方案

import pyautogui

# 1. 获取屏幕尺寸
screen_width, screen_height = pyautogui.size()
print(f"屏幕尺寸: {screen_width} x {screen_height}")

# 2. 检查当前鼠标位置
current_x, current_y = pyautogui.position()
print(f"当前鼠标位置: ({current_x}, {current_y})")

# 3. 使用相对坐标
relative_x = 0.5  # 屏幕宽度的50%
relative_y = 0.5  # 屏幕高度的50%
absolute_x = int(screen_width * relative_x)
absolute_y = int(screen_height * relative_y)

print(f"相对坐标 ({relative_x}, {relative_y}) 转换为绝对坐标 ({absolute_x}, {absolute_y})")

# 4. 移动鼠标
pyautogui.moveTo(absolute_x, absolute_y, duration=0.5)
9.2.2 鼠标点击无效

问题现象:调用 click() 方法但没有实际点击效果。

可能原因

  • 坐标位置错误
  • 窗口焦点问题
  • 点击时机问题

解决方案

import pyautogui
import time

def reliable_click(x, y, clicks=1, interval=0.1):
    """
    可靠的点击方法
    """
    try:
        # 移动到目标位置
        pyautogui.moveTo(x, y, duration=0.3)
        time.sleep(0.2)  # 等待稳定
        
        # 执行点击
        for i in range(clicks):
            pyautogui.mouseDown()
            time.sleep(0.05)
            pyautogui.mouseUp()
            if i < clicks - 1:
                time.sleep(interval)
        
        return True
    except Exception as e:
        print(f"点击失败: {e}")
        return False

# 测试可靠点击
if __name__ == "__main__":
    # 点击屏幕中心
    screen_width, screen_height = pyautogui.size()
    center_x, center_y = screen_width // 2, screen_height // 2
    
    print(f"点击屏幕中心: ({center_x}, {center_y})")
    reliable_click(center_x, center_y)

9.3 键盘操作问题

9.3.1 键盘输入不生效

问题现象:使用 write()typewrite() 方法时,文本没有输入到目标输入框。

可能原因

  • 目标窗口没有焦点
  • 输入时机问题
  • 特殊字符处理问题

解决方案

import pyautogui
import time

def focus_and_type(window_title, text, interval=0.05):
    """
    聚焦窗口并输入文本
    """
    try:
        # 1. 激活窗口(如果使用pygetwindow)
        # import pygetwindow
        # window = pygetwindow.getWindowsWithTitle(window_title)[0]
        # window.activate()
        
        # 2. 或者点击目标区域
        # 假设目标输入框在 (300, 300)
        pyautogui.click(300, 300)
        time.sleep(0.3)  # 等待窗口激活
        
        # 3. 输入文本
        pyautogui.write(text, interval=interval)
        return True
    except Exception as e:
        print(f"输入失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    focus_and_type("Notepad", "Hello, PyAutoGUI!")
9.3.2 组合键不生效

问题现象:使用 hotkey() 方法时,组合键没有正确执行。

可能原因

  • 按键顺序问题
  • 平台差异
  • 按键释放不完整

解决方案

import pyautogui
import time

def reliable_hotkey(*keys):
    """
    可靠的组合键执行方法
    """
    try:
        # 按下所有键
        for key in keys:
            pyautogui.keyDown(key)
            time.sleep(0.05)
        
        # 释放所有键(反向顺序)
        for key in reversed(keys):
            pyautogui.keyUp(key)
            time.sleep(0.05)
        
        return True
    except Exception as e:
        print(f"组合键执行失败: {e}")
        # 确保所有键都被释放
        for key in keys:
            try:
                pyautogui.keyUp(key)
            except:
                pass
        return False

# 测试
if __name__ == "__main__":
    # 测试复制操作
    print("执行 Ctrl+C")
    reliable_hotkey('ctrl', 'c')
    
    # 测试粘贴操作
    time.sleep(1)
    print("执行 Ctrl+V")
    reliable_hotkey('ctrl', 'v')

9.4 图像识别问题

9.4.1 图像未找到

问题现象:使用 locateOnScreen() 方法时返回 None

可能原因

  • 图像文件不存在
  • 图像与屏幕内容不匹配
  • 置信度设置过高
  • 屏幕分辨率差异

解决方案

import pyautogui
import os

def locate_image_with_retry(image_path, max_attempts=3, confidence=0.8, grayscale=False):
    """
    带重试机制的图像定位
    """
    if not os.path.exists(image_path):
        print(f"图像文件不存在: {image_path}")
        return None
    
    attempts = 0
    while attempts < max_attempts:
        try:
            position = pyautogui.locateOnScreen(
                image_path,
                confidence=confidence,
                grayscale=grayscale
            )
            if position:
                print(f"找到图像: {image_path}")
                return position
            else:
                attempts += 1
                print(f"未找到图像 (尝试 {attempts}/{max_attempts})")
                # 降低置信度
                confidence -= 0.05
                if confidence < 0.6:
                    break
        except Exception as e:
            print(f"定位失败: {e}")
            attempts += 1
    
    return None

# 测试
if __name__ == "__main__":
    image_path = "button.png"
    position = locate_image_with_retry(image_path)
    if position:
        print(f"图像位置: {position}")
        # 点击图像中心
        center_x = position.left + position.width // 2
        center_y = position.top + position.height // 2
        pyautogui.click(center_x, center_y)
9.4.2 图像识别速度慢

问题现象:图像识别操作耗时过长。

可能原因

  • 图像尺寸过大
  • 搜索区域过大
  • 置信度计算复杂
  • CPU性能限制

解决方案

import pyautogui
import time

def optimized_image_recognition(image_path, region=None, confidence=0.8):
    """
    优化的图像识别
    """
    start_time = time.time()
    
    try:
        # 1. 使用区域限制
        if region:
            position = pyautogui.locateOnScreen(
                image_path,
                region=region,
                confidence=confidence,
                grayscale=True  # 启用灰度模式加速
            )
        else:
            position = pyautogui.locateOnScreen(
                image_path,
                confidence=confidence,
                grayscale=True
            )
        
        elapsed = time.time() - start_time
        print(f"识别耗时: {elapsed:.3f}秒")
        
        return position
    except Exception as e:
        print(f"识别失败: {e}")
        return None

# 测试
if __name__ == "__main__":
    # 定义搜索区域(屏幕的一部分)
    screen_width, screen_height = pyautogui.size()
    search_region = (0, 0, screen_width // 2, screen_height)
    
    print("使用区域限制进行图像识别")
    position = optimized_image_recognition("button.png", region=search_region)
    if position:
        print(f"找到图像: {position}")

9.5 屏幕截图问题

9.5.1 截图失败

问题现象:使用 screenshot() 方法时失败或返回空图像。

可能原因

  • 权限不足
  • 屏幕分辨率过高
  • 内存不足
  • 系统限制

解决方案

import pyautogui
import os

def safe_screenshot(region=None, filename=None):
    """
    安全的截图方法
    """
    try:
        # 1. 检查存储空间
        if filename:
            dir_path = os.path.dirname(filename)
            if dir_path and not os.path.exists(dir_path):
                os.makedirs(dir_path)
        
        # 2. 执行截图
        if region:
            screenshot = pyautogui.screenshot(region=region)
        else:
            screenshot = pyautogui.screenshot()
        
        # 3. 保存文件
        if filename:
            screenshot.save(filename)
            print(f"截图已保存到: {filename}")
        
        return screenshot
    except Exception as e:
        print(f"截图失败: {e}")
        return None

# 测试
if __name__ == "__main__":
    # 测试区域截图
    region = (0, 0, 800, 600)
    screenshot = safe_screenshot(region=region, filename="region_screenshot.png")
    if screenshot:
        print(f"截图尺寸: {screenshot.size}")
9.5.2 截图内存占用高

问题现象:截图操作导致内存使用激增。

可能原因

  • 截图尺寸过大
  • 频繁截图
  • 未及时释放内存

解决方案

import pyautogui
import gc
import os

def memory_efficient_screenshot(region=None, filename=None):
    """
    内存高效的截图方法
    """
    try:
        # 直接保存到文件,避免在内存中存储
        if filename:
            if region:
                pyautogui.screenshot(filename, region=region)
            else:
                pyautogui.screenshot(filename)
            print(f"截图已保存到: {filename}")
            return True
        else:
            # 只在需要时创建内存中的截图
            screenshot = pyautogui.screenshot(region=region)
            return screenshot
    except Exception as e:
        print(f"截图失败: {e}")
        return False
    finally:
        # 强制垃圾回收
        gc.collect()

# 测试
if __name__ == "__main__":
    print("执行内存高效截图")
    # 批量截图示例
    for i in range(5):
        filename = f"screenshot_{i+1}.png"
        memory_efficient_screenshot(filename=filename)
        # 处理截图...
        # 处理完成后可以删除文件
        # os.remove(filename)

9.6 平台兼容性问题

9.6.1 Windows平台问题

问题现象:在Windows系统上运行时出现特殊问题。

可能原因

  • UAC权限问题
  • 窗口管理差异
  • 键盘布局差异

解决方案

import pyautogui
import platform
import ctypes

def is_windows():
    """检查是否为Windows平台"""
    return platform.system() == "Windows"

def run_as_admin():
    """
    检查是否以管理员权限运行
    """
    if not is_windows():
        return True
    
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

def windows_specific_fixes():
    """
    Windows平台特定修复
    """
    if is_windows():
        # 禁用Windows键(可选)
        # 注意:这需要系统权限
        print("应用Windows特定修复")
        # 可以在这里添加Windows特定的修复代码

# 测试
if __name__ == "__main__":
    print(f"是否为Windows平台: {is_windows()}")
    print(f"是否以管理员权限运行: {run_as_admin()}")
    windows_specific_fixes()
9.6.2 macOS平台问题

问题现象:在macOS系统上运行时出现特殊问题。

可能原因

  • 权限设置问题
  • 辅助功能权限
  • 键盘快捷键差异

解决方案

import pyautogui
import platform
import subprocess

def is_macos():
    """检查是否为macOS平台"""
    return platform.system() == "Darwin"

def check_accessibility_permissions():
    """
    检查辅助功能权限
    """
    if not is_macos():
        return True
    
    try:
        # 检查辅助功能权限
        result = subprocess.run(
            ["osascript", "-e", "tell application \"System Events\" to get UI elements enabled"],
            capture_output=True,
            text=True
        )
        return "true" in result.stdout.lower()
    except Exception as e:
        print(f"检查权限失败: {e}")
        return False

def macos_specific_fixes():
    """
    macOS平台特定修复
    """
    if is_macos():
        print("应用macOS特定修复")
        # 可以在这里添加macOS特定的修复代码

# 测试
if __name__ == "__main__":
    print(f"是否为macOS平台: {is_macos()}")
    if is_macos():
        print(f"辅助功能权限: {check_accessibility_permissions()}")
        if not check_accessibility_permissions():
            print("请在系统偏好设置中启用辅助功能权限")
    macos_specific_fixes()

9.7 性能问题

9.7.1 执行速度慢

问题现象:自动化脚本执行速度过慢。

可能原因

  • 默认延迟设置过高
  • 不必要的等待时间
  • 低效的操作顺序
  • 资源密集型操作

解决方案

import pyautogui
import time

def optimize_performance():
    """
    性能优化设置
    """
    # 1. 减少默认延迟
    original_pause = pyautogui.PAUSE
    pyautogui.PAUSE = 0.01  # 减少到10毫秒
    
    try:
        # 2. 批量操作
        start_time = time.time()
        
        # 优化前
        print("优化前:")
        for i in range(10):
            pyautogui.moveTo(100 + i*20, 100)
            pyautogui.click()
        
        time1 = time.time() - start_time
        print(f"耗时: {time1:.3f}秒")
        
        # 优化后
        start_time = time.time()
        print("\n优化后:")
        for i in range(10):
            x, y = 100 + i*20, 100
            pyautogui.moveTo(x, y, duration=0.05)
            pyautogui.click()
        
        time2 = time.time() - start_time
        print(f"耗时: {time2:.3f}秒")
        print(f"性能提升: {((time1 - time2) / time1 * 100):.1f}%")
        
    finally:
        # 恢复默认设置
        pyautogui.PAUSE = original_pause

# 测试
if __name__ == "__main__":
    optimize_performance()
9.7.2 内存使用高

问题现象:脚本运行时内存使用持续增长。

可能原因

  • 未释放的对象
  • 频繁的截图操作
  • 内存泄漏

解决方案

import pyautogui
import gc
import psutil
import os

def monitor_memory():
    """
    监控内存使用
    """
    process = psutil.Process(os.getpid())
    return process.memory_info().rss / 1024 / 1024  # MB

def memory_optimization():
    """
    内存优化
    """
    print(f"初始内存使用: {monitor_memory():.2f} MB")
    
    # 执行内存密集操作
    screenshots = []
    for i in range(5):
        screenshot = pyautogui.screenshot(region=(0, 0, 800, 600))
        screenshots.append(screenshot)
        print(f"截图 {i+1} 后内存使用: {monitor_memory():.2f} MB")
    
    # 释放内存
    print("\n释放内存:")
    del screenshots
    gc.collect()  # 强制垃圾回收
    print(f"释放后内存使用: {monitor_memory():.2f} MB")

# 测试
if __name__ == "__main__":
    memory_optimization()

9.8 安全问题

9.8.1 FAILSAFE机制问题

问题现象:FAILSAFE机制意外触发。

可能原因

  • 鼠标意外移动到屏幕角落
  • 多显示器配置问题
  • 脚本逻辑问题

解决方案

import pyautogui

def configure_failsafe():
    """
    配置FAILSAFE机制
    
    注意:FAILSAFE_POINTS 和 FAILSAFE_DISTANCE 不是PyAutoGUI标准属性
    PyAutoGUI只支持 FAILSAFE 布尔值设置
    """
    # 1. 启用FAILSAFE(推荐)
    pyautogui.FAILSAFE = True
    print("已启用FAILSAFE机制")
    
    # 2. 自定义安全区域检查(替代方案)
    def check_failsafe_area(x_threshold=50, y_threshold=50):
        """
        检查鼠标是否在安全区域
        
        Args:
            x_threshold: X轴安全阈值(像素)
            y_threshold: Y轴安全阈值(像素)
        
        Returns:
            bool: 是否在安全区域内
        """
        current_pos = pyautogui.position()
        return current_pos[0] < x_threshold and current_pos[1] < y_threshold
    
    # 测试自定义安全区域检查
    print("\n自定义安全区域检查函数已定义")
    print("使用方法: check_failsafe_area(x_threshold, y_threshold)")
    print("注意:PyAutoGUI标准库不支持自定义FAILSAFE点或触发距离")

# 测试
if __name__ == "__main__":
    configure_failsafe()
    print("FAILSAFE配置完成")
9.8.2 权限安全问题

问题现象:脚本需要特殊权限才能运行。

可能原因

  • 需要管理员/root权限
  • 需要辅助功能权限
  • 文件系统权限问题

解决方案

import pyautogui
import os
import getpass

def check_permissions():
    """
    检查权限
    """
    current_user = getpass.getuser()
    print(f"当前用户: {current_user}")
    
    # 检查文件权限
    test_file = "test_permission.txt"
    try:
        with open(test_file, 'w') as f:
            f.write("test")
        print("文件写入权限: 正常")
        os.remove(test_file)
    except Exception as e:
        print(f"文件写入权限: 异常 - {e}")
    
    # 检查屏幕访问权限
    try:
        size = pyautogui.size()
        print(f"屏幕访问权限: 正常 (屏幕尺寸: {size})")
    except Exception as e:
        print(f"屏幕访问权限: 异常 - {e}")

# 测试
if __name__ == "__main__":
    check_permissions()

9.9 其他常见问题

9.9.1 脚本卡死

问题现象:脚本运行过程中突然卡死。

可能原因

  • 无限循环
  • 死锁
  • 系统资源耗尽
  • 异常未捕获

解决方案

import pyautogui
import time
import signal
import sys

def signal_handler(signal, frame):
    """
    信号处理函数
    """
    print("\n接收到中断信号,正在退出...")
    # 清理操作
    sys.exit(0)

def safe_automation():
    """
    安全的自动化操作
    """
    # 注册信号处理
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    
    try:
        print("开始自动化操作")
        print("按 Ctrl+C 停止")
        
        # 模拟长时间操作
        for i in range(100):
            pyautogui.moveTo(100 + i*10, 100)
            time.sleep(0.1)
            print(f"执行步骤 {i+1}/100")
        
        print("自动化操作完成")
    except Exception as e:
        print(f"发生异常: {e}")

# 测试
if __name__ == "__main__":
    safe_automation()
9.9.2 坐标计算错误

问题现象:坐标计算错误导致操作位置偏差。

可能原因

  • 屏幕分辨率变化
  • 窗口大小变化
  • 坐标系统理解错误
  • 多显示器配置

解决方案

import pyautogui

def calculate_relative_coordinates(relative_x, relative_y):
    """
    计算相对坐标
    
    Args:
        relative_x: 相对X坐标(0.0-1.0)
        relative_y: 相对Y坐标(0.0-1.0)
    
    Returns:
        tuple: (绝对X坐标, 绝对Y坐标)
    """
    screen_width, screen_height = pyautogui.size()
    absolute_x = int(screen_width * relative_x)
    absolute_y = int(screen_height * relative_y)
    return absolute_x, absolute_y

def handle_multi_monitor():
    """
    处理多显示器情况
    
    注意:需要使用 screeninfo 库获取多显示器信息
    """
    try:
        from screeninfo import get_monitors
        
        monitors = get_monitors()
        print(f"检测到 {len(monitors)} 个显示器")
        
        for i, monitor in enumerate(monitors):
            print(f"显示器 {i+1}:")
            print(f"  位置: ({monitor.x}, {monitor.y})")
            print(f"  尺寸: {monitor.width} x {monitor.height}")
            print(f"  主显示器: {monitor.is_primary}")
            
    except ImportError:
        print("未安装 screeninfo 库")
        print("运行: pip install screeninfo")
        print("\n或者使用以下命令安装:")
        print("  Windows: pip install screeninfo")
        print("  macOS: pip install screeninfo")
        print("  Linux: pip install screeninfo")
    except Exception as e:
        print(f"获取显示器信息失败: {e}")

# 测试
if __name__ == "__main__":
    # 测试相对坐标
    rel_x, rel_y = 0.5, 0.5  # 屏幕中心
    abs_x, abs_y = calculate_relative_coordinates(rel_x, rel_y)
    print(f"相对坐标 ({rel_x}, {rel_y}) 转换为绝对坐标 ({abs_x}, {abs_y})")
    
    # 测试多显示器
    handle_multi_monitor()

9.10 问题排查工具

9.10.1 调试工具
import pyautogui
import time

def debug_tool():
    """
    调试工具
    """
    print("PyAutoGUI调试工具")
    print("按 Ctrl+C 退出")
    
    try:
        while True:
            # 获取鼠标位置
            x, y = pyautogui.position()
            # 获取像素颜色
            color = pyautogui.pixel(x, y)
            
            # 清除屏幕并显示信息
            print(f"\r鼠标位置: ({x}, {y}) 颜色: {color}", end='')
            time.sleep(0.1)
    except KeyboardInterrupt:
        print("\n调试工具退出")

def screen_info():
    """
    屏幕信息工具
    """
    print("屏幕信息:")
    width, height = pyautogui.size()
    print(f"屏幕尺寸: {width} x {height}")
    
    # 显示常用位置
    positions = {
        '左上角': (0, 0),
        '右上角': (width-1, 0),
        '左下角': (0, height-1),
        '右下角': (width-1, height-1),
        '中心': (width//2, height//2)
    }
    
    for name, pos in positions.items():
        print(f"{name}: {pos}")

# 测试
if __name__ == "__main__":
    screen_info()
    print("\n启动鼠标位置调试工具...")
    debug_tool()
9.10.2 日志分析工具
import logging
import json
from datetime import datetime

class EnhancedLogger:
    """
    增强的日志记录器
    """
    def __init__(self, log_file="automation_debug.log"):
        self.logger = logging.getLogger("PyAutoGUI-Debug")
        self.logger.setLevel(logging.DEBUG)
        
        # 文件处理器
        file_handler = logging.FileHandler(log_file)
        file_handler.setLevel(logging.DEBUG)
        
        # 控制台处理器
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.INFO)
        
        # 格式化器
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        file_handler.setFormatter(formatter)
        console_handler.setFormatter(formatter)
        
        # 添加处理器
        self.logger.addHandler(file_handler)
        self.logger.addHandler(console_handler)
    
    def log(self, level, message, **extra):
        """
        记录日志
        """
        extra_info = " " + " ".join([f"{k}={v}" for k, v in extra.items()]) if extra else ""
        if level == "debug":
            self.logger.debug(message + extra_info)
        elif level == "info":
            self.logger.info(message + extra_info)
        elif level == "warning":
            self.logger.warning(message + extra_info)
        elif level == "error":
            self.logger.error(message + extra_info)
        elif level == "critical":
            self.logger.critical(message + extra_info)

# 测试
if __name__ == "__main__":
    logger = EnhancedLogger()
    logger.log("info", "开始自动化操作")
    
    try:
        import pyautogui
        logger.log("debug", "PyAutoGUI导入成功", version=pyautogui.__version__)
        
        # 执行一些操作
        screen_width, screen_height = pyautogui.size()
        logger.log("info", "获取屏幕尺寸", width=screen_width, height=screen_height)
        
        # 模拟错误
        # pyautogui.locateOnScreen("non_existent.png")
        
    except Exception as e:
        logger.log("error", "操作失败", error=str(e))
    
    logger.log("info", "自动化操作完成")

第10章 实战案例分析

10.1 网页自动化测试案例

10.1.1 登录表单自动填写

功能说明:自动打开浏览器,访问登录页面,填写用户名和密码并提交。

技术要点

  • 浏览器启动与导航
  • 元素定位与点击
  • 表单填写
  • 提交操作

代码实现

import pyautogui
import time
import os

def web_login_automation():
    """
    网页登录自动化
    """
    try:
        # 1. 启动浏览器
        print("启动浏览器...")
        if os.name == 'nt':  # Windows
            os.system('start chrome')
        elif os.name == 'posix':  # macOS/Linux
            if sys.platform == 'darwin':  # macOS
                os.system('open -a "Google Chrome"')
            else:  # Linux
                os.system('google-chrome &')
        
        time.sleep(3)  # 等待浏览器启动
        
        # 2. 访问登录页面
        print("访问登录页面...")
        pyautogui.write('https://example.com/login', interval=0.05)
        pyautogui.press('enter')
        time.sleep(3)  # 等待页面加载
        
        # 3. 填写用户名
        print("填写用户名...")
        # 假设用户名输入框在 (500, 300)
        pyautogui.click(500, 300)
        time.sleep(0.5)
        pyautogui.write('testuser', interval=0.05)
        
        # 4. 填写密码
        print("填写密码...")
        # 假设密码输入框在 (500, 350)
        pyautogui.click(500, 350)
        time.sleep(0.5)
        pyautogui.write('password123', interval=0.05)
        
        # 5. 点击登录按钮
        print("点击登录按钮...")
        # 假设登录按钮在 (500, 400)
        pyautogui.click(500, 400)
        time.sleep(2)  # 等待登录完成
        
        print("登录自动化完成!")
        return True
        
    except Exception as e:
        print(f"登录自动化失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    web_login_automation()
10.1.2 网页数据抓取

功能说明:自动打开网页,抓取指定数据并保存到文件。

技术要点

  • 网页导航
  • 数据定位与提取
  • 截图与OCR(可选)
  • 数据保存

代码实现

import pyautogui
import time
import os
from PIL import Image
import pytesseract

def web_data_extraction():
    """
    网页数据抓取
    """
    try:
        # 1. 启动浏览器
        print("启动浏览器...")
        if os.name == 'nt':
            os.system('start chrome')
        elif os.name == 'posix':
            if sys.platform == 'darwin':
                os.system('open -a "Google Chrome"')
            else:
                os.system('google-chrome &')
        
        time.sleep(3)
        
        # 2. 访问目标网页
        print("访问目标网页...")
        pyautogui.write('https://example.com/data', interval=0.05)
        pyautogui.press('enter')
        time.sleep(3)
        
        # 3. 定位数据区域并截图
        print("抓取数据区域...")
        # 假设数据区域在 (200, 200, 800, 600)
        region = (200, 200, 600, 400)  # (left, top, width, height)
        screenshot = pyautogui.screenshot(region=region)
        screenshot.save('data_screenshot.png')
        print("数据区域已截图保存")
        
        # 4. 使用OCR提取文本(可选)
        try:
            print("提取文本数据...")
            text = pytesseract.image_to_string(screenshot, lang='chi_sim+eng')
            print("提取的文本:")
            print(text)
            
            # 保存提取的文本
            with open('extracted_data.txt', 'w', encoding='utf-8') as f:
                f.write(text)
            print("文本数据已保存到 extracted_data.txt")
        except Exception as e:
            print(f"OCR提取失败: {e}")
        
        print("数据抓取完成!")
        return True
        
    except Exception as e:
        print(f"数据抓取失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    web_data_extraction()

10.2 桌面应用自动化案例

10.2.1 记事本自动化

功能说明:自动打开记事本,输入文本,保存文件。

技术要点

  • 应用启动
  • 文本输入
  • 菜单操作
  • 文件保存

代码实现

import pyautogui
import time
import os

def notepad_automation():
    """
    记事本自动化
    """
    try:
        # 1. 启动记事本
        print("启动记事本...")
        if os.name == 'nt':  # Windows
            os.system('start notepad')
        elif os.name == 'posix':  # macOS/Linux
            if sys.platform == 'darwin':  # macOS
                os.system('open -a TextEdit')
            else:  # Linux
                os.system('gedit &')
        
        time.sleep(2)  # 等待记事本启动
        
        # 2. 输入文本
        print("输入文本...")
        text = "Hello, PyAutoGUI!\n"
        text += "这是一个自动化测试示例。\n"
        text += "通过PyAutoGUI可以实现各种桌面应用的自动化操作。"
        
        pyautogui.write(text, interval=0.05)
        time.sleep(1)
        
        # 3. 保存文件
        print("保存文件...")
        if os.name == 'nt':  # Windows
            pyautogui.hotkey('ctrl', 's')
        elif sys.platform == 'darwin':  # macOS
            pyautogui.hotkey('command', 's')
        else:  # Linux
            pyautogui.hotkey('ctrl', 's')
        
        time.sleep(1)  # 等待保存对话框
        
        # 4. 输入文件名
        print("输入文件名...")
        filename = "test_automation.txt"
        pyautogui.write(filename, interval=0.05)
        pyautogui.press('enter')
        time.sleep(1)
        
        print("记事本自动化完成!")
        print(f"文件已保存为: {filename}")
        return True
        
    except Exception as e:
        print(f"记事本自动化失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    notepad_automation()
10.2.2 Excel数据处理

功能说明:自动打开Excel,填充数据,执行计算。

技术要点

  • Excel启动
  • 单元格操作
  • 公式输入
  • 数据填充

代码实现

import pyautogui
import time
import os

def excel_automation():
    """
    Excel自动化
    """
    try:
        # 1. 启动Excel
        print("启动Excel...")
        if os.name == 'nt':  # Windows
            os.system('start excel')
        elif sys.platform == 'darwin':  # macOS
            os.system('open -a Excel')
        else:  # Linux (使用LibreOffice)
            os.system('libreoffice --calc &')
        
        time.sleep(3)  # 等待Excel启动
        
        # 2. 输入表头
        print("输入表头...")
        pyautogui.click(100, 100)  # 点击A1单元格
        pyautogui.write('产品名称', interval=0.05)
        pyautogui.press('tab')  # 移动到B1
        pyautogui.write('数量', interval=0.05)
        pyautogui.press('tab')  # 移动到C1
        pyautogui.write('单价', interval=0.05)
        pyautogui.press('tab')  # 移动到D1
        pyautogui.write('金额', interval=0.05)
        pyautogui.press('enter')  # 移动到A2
        
        # 3. 输入数据
        print("输入数据...")
        products = [
            ["产品A", "10", "50"],
            ["产品B", "20", "30"],
            ["产品C", "15", "40"]
        ]
        
        for product in products:
            pyautogui.write(product[0], interval=0.05)
            pyautogui.press('tab')
            pyautogui.write(product[1], interval=0.05)
            pyautogui.press('tab')
            pyautogui.write(product[2], interval=0.05)
            pyautogui.press('tab')
            # 输入公式:B2*C2
            pyautogui.write('=B', interval=0.05)
            current_row = pyautogui.position()[1] // 20 + 1  # 估算当前行
            pyautogui.write(str(current_row), interval=0.05)
            pyautogui.write('*C', interval=0.05)
            pyautogui.write(str(current_row), interval=0.05)
            pyautogui.press('enter')
        
        # 4. 保存文件
        print("保存文件...")
        if os.name == 'nt':
            pyautogui.hotkey('ctrl', 's')
        elif sys.platform == 'darwin':
            pyautogui.hotkey('command', 's')
        else:
            pyautogui.hotkey('ctrl', 's')
        
        time.sleep(1)
        pyautogui.write('sales_data.xlsx', interval=0.05)
        pyautogui.press('enter')
        time.sleep(2)
        
        print("Excel自动化完成!")
        print("文件已保存为: sales_data.xlsx")
        return True
        
    except Exception as e:
        print(f"Excel自动化失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    excel_automation()

10.3 游戏自动化案例

10.3.1 游戏自动点击

功能说明:自动点击游戏中的特定位置,模拟游戏操作。

技术要点

  • 游戏窗口识别
  • 目标位置定位
  • 点击操作
  • 循环执行

代码实现

import pyautogui
import time
import random

def game_auto_click():
    """
    游戏自动点击
    """
    try:
        print("游戏自动点击脚本启动")
        print("按 Ctrl+C 停止")
        
        # 游戏中需要点击的位置(示例)
        click_positions = [
            (400, 300),  # 位置1
            (600, 300),  # 位置2
            (500, 400),  # 位置3
            (450, 500),  # 位置4
            (550, 500)   # 位置5
        ]
        
        # 循环执行
        count = 0
        start_time = time.time()
        
        while True:
            # 随机选择一个位置点击
            position = random.choice(click_positions)
            
            # 移动到位置并点击
            pyautogui.moveTo(position[0], position[1], duration=0.1)
            pyautogui.click()
            
            count += 1
            
            # 随机延迟
            delay = random.uniform(0.5, 1.5)
            time.sleep(delay)
            
            # 每10次点击显示一次状态
            if count % 10 == 0:
                elapsed = time.time() - start_time
                print(f"已点击 {count} 次,耗时 {elapsed:.1f} 秒")
                
    except KeyboardInterrupt:
        print("\n脚本已停止")
    except Exception as e:
        print(f"脚本执行失败: {e}")

# 测试
if __name__ == "__main__":
    game_auto_click()
10.3.2 游戏资源收集

功能说明:自动收集游戏中的资源,包括移动、点击、识别等操作。

技术要点

  • 资源识别
  • 路径规划
  • 状态判断
  • 异常处理

代码实现

import pyautogui
import time
import os

def game_resource_collection():
    """
    游戏资源收集
    """
    try:
        print("游戏资源收集脚本启动")
        print("按 Ctrl+C 停止")
        
        # 资源位置(示例)
        resource_positions = [
            (300, 200),  # 资源1
            (500, 250),  # 资源2
            (700, 200),  # 资源3
            (400, 400),  # 资源4
            (600, 400)   # 资源5
        ]
        
        # 基地位置(返回点)
        base_position = (900, 500)
        
        # 循环收集资源
        collection_count = 0
        start_time = time.time()
        
        while True:
            # 遍历所有资源位置
            for i, pos in enumerate(resource_positions):
                print(f"前往收集资源 {i+1}")
                
                # 移动到资源位置
                pyautogui.moveTo(pos[0], pos[1], duration=0.5)
                time.sleep(0.5)
                
                # 点击收集
                pyautogui.click()
                print(f"已收集资源 {i+1}")
                
                # 等待收集动画
                time.sleep(2)
                
                # 随机延迟,模拟人类操作
                time.sleep(random.uniform(0.5, 1.0))
            
            # 返回基地
            print("返回基地")
            pyautogui.moveTo(base_position[0], base_position[1], duration=0.5)
            pyautogui.click()
            time.sleep(3)  # 等待返回动画
            
            collection_count += 1
            elapsed = time.time() - start_time
            print(f"\n第 {collection_count} 轮收集完成,耗时 {elapsed:.1f} 秒\n")
            
            # 休息一下
            time.sleep(random.uniform(2, 5))
            
    except KeyboardInterrupt:
        print("\n脚本已停止")
    except Exception as e:
        print(f"脚本执行失败: {e}")

# 测试
if __name__ == "__main__":
    game_resource_collection()

10.4 数据录入自动化案例

10.4.1 表单自动填写

功能说明:自动填写网页或桌面应用中的表单数据。

技术要点

  • 数据准备
  • 表单定位
  • 批量填写
  • 提交操作

代码实现

import pyautogui
import time
import csv

def form_auto_fill():
    """
    表单自动填写
    """
    try:
        # 1. 读取数据
        print("读取表单数据...")
        form_data = []
        
        # 示例数据
        form_data = [
            {"name": "张三", "email": "zhangsan@example.com", "phone": "13800138001"},
            {"name": "李四", "email": "lisi@example.com", "phone": "13900139001"},
            {"name": "王五", "email": "wangwu@example.com", "phone": "13700137001"}
        ]
        
        print(f"读取到 {len(form_data)} 条数据")
        
        # 2. 打开表单页面
        print("打开表单页面...")
        # 这里可以根据实际情况打开相应的应用或网页
        # 示例:打开浏览器
        import os
        if os.name == 'nt':
            os.system('start chrome')
        elif os.name == 'posix':
            if sys.platform == 'darwin':
                os.system('open -a "Google Chrome"')
            else:
                os.system('google-chrome &')
        
        time.sleep(3)
        pyautogui.write('https://example.com/form', interval=0.05)
        pyautogui.press('enter')
        time.sleep(3)
        
        # 3. 循环填写表单
        for i, data in enumerate(form_data):
            print(f"填写第 {i+1} 条数据...")
            
            # 填写姓名
            print("  填写姓名...")
            pyautogui.click(400, 200)  # 假设姓名输入框位置
            time.sleep(0.5)
            pyautogui.write(data["name"], interval=0.05)
            
            # 填写邮箱
            print("  填写邮箱...")
            pyautogui.click(400, 250)  # 假设邮箱输入框位置
            time.sleep(0.5)
            pyautogui.write(data["email"], interval=0.05)
            
            # 填写电话
            print("  填写电话...")
            pyautogui.click(400, 300)  # 假设电话输入框位置
            time.sleep(0.5)
            pyautogui.write(data["phone"], interval=0.05)
            
            # 提交表单
            print("  提交表单...")
            pyautogui.click(400, 350)  # 假设提交按钮位置
            time.sleep(2)  # 等待提交完成
            
            # 刷新页面或打开新表单
            print("  准备下一条...")
            pyautogui.hotkey('ctrl', 'r')  # 刷新页面
            time.sleep(3)  # 等待页面加载
        
        print("表单填写完成!")
        return True
        
    except Exception as e:
        print(f"表单填写失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    form_auto_fill()
10.4.2 批量数据导入

功能说明:从Excel或CSV文件批量导入数据到目标应用。

技术要点

  • 数据读取
  • 应用操作
  • 批量处理
  • 错误处理

代码实现

import pyautogui
import time
import csv
import os

def batch_data_import():
    """
    批量数据导入
    """
    try:
        # 1. 准备数据文件
        print("准备数据文件...")
        
        # 创建示例数据
        with open('import_data.csv', 'w', newline='', encoding='utf-8') as f:
            writer = csv.writer(f)
            writer.writerow(['姓名', '年龄', '部门'])
            writer.writerow(['张三', '25', '技术部'])
            writer.writerow(['李四', '30', '市场部'])
            writer.writerow(['王五', '28', '财务部'])
        
        print("数据文件已创建: import_data.csv")
        
        # 2. 打开目标应用
        print("打开目标应用...")
        # 示例:打开Excel
        if os.name == 'nt':
            os.system('start excel')
        elif sys.platform == 'darwin':
            os.system('open -a Excel')
        else:
            os.system('libreoffice --calc &')
        
        time.sleep(3)
        
        # 3. 导入数据
        print("开始导入数据...")
        
        # 模拟导入操作
        # 实际应用中需要根据目标应用的导入流程进行调整
        
        # 点击数据菜单
        pyautogui.click(100, 50)  # 假设数据菜单位置
        time.sleep(0.5)
        
        # 选择导入选项
        pyautogui.click(150, 150)  # 假设导入选项位置
        time.sleep(1)
        
        # 选择CSV文件
        pyautogui.write('import_data.csv', interval=0.05)
        pyautogui.press('enter')
        time.sleep(2)
        
        # 完成导入向导
        pyautogui.click(500, 400)  # 假设下一步按钮位置
        time.sleep(1)
        pyautogui.click(500, 400)  # 假设完成按钮位置
        time.sleep(3)
        
        print("数据导入完成!")
        return True
        
    except Exception as e:
        print(f"数据导入失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    batch_data_import()

10.5 截图与监控自动化案例

10.5.1 定时截图监控

功能说明:定时截取屏幕内容,用于监控系统状态或应用运行情况。

技术要点

  • 定时操作
  • 屏幕截图
  • 文件管理
  • 异常处理

代码实现

import pyautogui
import time
import os
from datetime import datetime

def定时_screenshot_monitoring(interval=60, duration=3600):
    """
    定时截图监控
    
    Args:
        interval: 截图间隔(秒)
        duration: 监控持续时间(秒)
    """
    try:
        # 创建截图保存目录
        save_dir = 'screenshots'
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
        
        print(f"开始定时截图监控")
        print(f"截图间隔: {interval}秒")
        print(f"监控持续时间: {duration}秒")
        print("按 Ctrl+C 停止")
        
        start_time = time.time()
        screenshot_count = 0
        
        while time.time() - start_time < duration:
            # 生成文件名
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = os.path.join(save_dir, f'screenshot_{timestamp}.png')
            
            # 执行截图
            print(f"截取屏幕...")
            screenshot = pyautogui.screenshot()
            screenshot.save(filename)
            screenshot_count += 1
            
            print(f"截图已保存: {filename}")
            print(f"已截取 {screenshot_count} 张图片")
            
            # 等待下一次截图
            time.sleep(interval)
        
        print(f"\n监控完成")
        print(f"总共截取 {screenshot_count} 张图片")
        print(f"图片保存目录: {os.path.abspath(save_dir)}")
        return True
        
    except KeyboardInterrupt:
        print("\n监控已停止")
        return False
    except Exception as e:
        print(f"监控失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    定时_screenshot_monitoring(interval=10, duration=60)  # 每10秒截图一次,持续1分钟
10.5.2 屏幕变化监控

功能说明:监控屏幕特定区域的变化,当检测到变化时触发操作。

技术要点

  • 区域监控
  • 图像比较
  • 变化检测
  • 触发操作

代码实现

import pyautogui
import time
import os
from PIL import ImageChops
from PIL import Image

def screen_change_monitoring(region=None, threshold=1000):
    """
    屏幕变化监控
    
    Args:
        region: 监控区域 (left, top, width, height)
        threshold: 变化阈值
    """
    try:
        print("开始屏幕变化监控")
        print("按 Ctrl+C 停止")
        
        # 默认监控整个屏幕
        if not region:
            screen_width, screen_height = pyautogui.size()
            region = (0, 0, screen_width, screen_height)
        
        print(f"监控区域: {region}")
        print(f"变化阈值: {threshold}")
        
        # 获取初始屏幕状态
        previous_screenshot = pyautogui.screenshot(region=region)
        
        change_count = 0
        start_time = time.time()
        
        while True:
            # 获取当前屏幕状态
            current_screenshot = pyautogui.screenshot(region=region)
            
            # 比较屏幕变化
            diff = ImageChops.difference(previous_screenshot, current_screenshot)
            diff_value = sum(diff.convert('L').getdata())
            
            # 检测到变化
            if diff_value > threshold:
                change_count += 1
                timestamp = time.strftime('%Y%m%d_%H%M%S')
                
                # 保存变化前后的截图
                if not os.path.exists('screen_changes'):
                    os.makedirs('screen_changes')
                
                previous_screenshot.save(f'screen_changes/previous_{timestamp}.png')
                current_screenshot.save(f'screen_changes/current_{timestamp}.png')
                
                print(f"\n检测到屏幕变化 #{change_count}")
                print(f"变化值: {diff_value}")
                print(f"截图已保存到 screen_changes 目录")
                
                # 更新基准截图
                previous_screenshot = current_screenshot
                
                # 可以在这里添加触发操作,如发送通知等
                
            # 短暂延迟
            time.sleep(1)
            
    except KeyboardInterrupt:
        print("\n监控已停止")
        print(f"总共检测到 {change_count} 次变化")
    except Exception as e:
        print(f"监控失败: {e}")

# 测试
if __name__ == "__main__":
    # 监控屏幕中央区域
    screen_width, screen_height = pyautogui.size()
    monitor_region = (
        screen_width // 4,
        screen_height // 4,
        screen_width // 2,
        screen_height // 2
    )
    screen_change_monitoring(region=monitor_region)

10.6 综合自动化案例

10.6.1 系统维护自动化

功能说明:自动执行系统维护任务,如清理临时文件、检查更新、备份数据等。

技术要点

  • 多任务协调
  • 系统操作
  • 错误处理
  • 日志记录

代码实现

import pyautogui
import time
import os
import shutil
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    filename='system_maintenance.log'
)

def system_maintenance():
    """
    系统维护自动化
    """
    try:
        logging.info("开始系统维护")
        print("开始系统维护...")
        
        # 1. 清理临时文件
        print("1. 清理临时文件...")
        try:
            import tempfile
            temp_dir = tempfile.gettempdir()
            logging.info(f"清理临时目录: {temp_dir}")
            
            # 清理临时文件(示例)
            for file in os.listdir(temp_dir):
                file_path = os.path.join(temp_dir, file)
                try:
                    if os.path.isfile(file_path):
                        os.remove(file_path)
                        logging.info(f"删除临时文件: {file}")
                except Exception as e:
                    logging.warning(f"无法删除文件 {file}: {e}")
            
            print("临时文件清理完成")
        except Exception as e:
            logging.error(f"清理临时文件失败: {e}")
            print(f"清理临时文件失败: {e}")
        
        # 2. 检查系统更新
        print("\n2. 检查系统更新...")
        try:
            if os.name == 'nt':  # Windows
                print("检查Windows更新...")
                # 这里可以添加Windows更新检查代码
            elif os.name == 'posix':  # macOS/Linux
                if sys.platform == 'darwin':  # macOS
                    print("检查macOS更新...")
                    # 这里可以添加macOS更新检查代码
                else:  # Linux
                    print("检查Linux更新...")
                    # 这里可以添加Linux更新检查代码
            
            print("系统更新检查完成")
        except Exception as e:
            logging.error(f"检查系统更新失败: {e}")
            print(f"检查系统更新失败: {e}")
        
        # 3. 备份重要数据
        print("\n3. 备份重要数据...")
        try:
            # 创建备份目录
            backup_dir = f'backup_{time.strftime("%Y%m%d")}'
            if not os.path.exists(backup_dir):
                os.makedirs(backup_dir)
            
            # 示例:备份文档目录
            documents_dir = os.path.expanduser('~\Documents') if os.name == 'nt' else os.path.expanduser('~/Documents')
            if os.path.exists(documents_dir):
                backup_documents = os.path.join(backup_dir, 'Documents')
                shutil.copytree(documents_dir, backup_documents, ignore=shutil.ignore_patterns('*.tmp', '*.log'))
                logging.info(f"备份文档目录到: {backup_documents}")
                print("文档目录备份完成")
            
        except Exception as e:
            logging.error(f"备份数据失败: {e}")
            print(f"备份数据失败: {e}")
        
        # 4. 系统健康检查
        print("\n4. 系统健康检查...")
        try:
            import psutil
            
            # 检查CPU使用率
            cpu_percent = psutil.cpu_percent(interval=1)
            logging.info(f"CPU使用率: {cpu_percent}%")
            print(f"CPU使用率: {cpu_percent}%")
            
            # 检查内存使用率
            memory = psutil.virtual_memory()
            logging.info(f"内存使用率: {memory.percent}%")
            print(f"内存使用率: {memory.percent}%")
            
            # 检查磁盘使用率
            disk = psutil.disk_usage('/')
            logging.info(f"磁盘使用率: {disk.percent}%")
            print(f"磁盘使用率: {disk.percent}%")
            
        except Exception as e:
            logging.error(f"系统健康检查失败: {e}")
            print(f"系统健康检查失败: {e}")
        
        logging.info("系统维护完成")
        print("\n系统维护完成!")
        return True
        
    except Exception as e:
        logging.error(f"系统维护失败: {e}")
        print(f"系统维护失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    system_maintenance()
10.6.2 多应用协同自动化

功能说明:协调多个应用之间的操作,实现复杂的工作流程自动化。

技术要点

  • 多应用切换
  • 数据传递
  • 工作流程控制
  • 异常处理

代码实现

import pyautogui
import time
import os
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    filename='multi_app_automation.log'
)

def multi_app_automation():
    """
    多应用协同自动化
    """
    try:
        logging.info("开始多应用协同自动化")
        print("开始多应用协同自动化...")
        
        # 1. 打开浏览器并获取数据
        print("1. 打开浏览器并获取数据...")
        if os.name == 'nt':
            os.system('start chrome')
        elif os.name == 'posix':
            if sys.platform == 'darwin':
                os.system('open -a "Google Chrome"')
            else:
                os.system('google-chrome &')
        
        time.sleep(3)
        pyautogui.write('https://example.com/data', interval=0.05)
        pyautogui.press('enter')
        time.sleep(3)
        
        # 假设在网页上获取数据
        print("获取网页数据...")
        # 这里可以添加数据获取代码
        
        # 2. 打开Excel并处理数据
        print("\n2. 打开Excel并处理数据...")
        if os.name == 'nt':
            os.system('start excel')
        elif sys.platform == 'darwin':
            os.system('open -a Excel')
        else:
            os.system('libreoffice --calc &')
        
        time.sleep(3)
        
        # 处理数据
        print("在Excel中处理数据...")
        # 这里可以添加Excel操作代码
        
        # 3. 打开Word并生成报告
        print("\n3. 打开Word并生成报告...")
        if os.name == 'nt':
            os.system('start winword')
        elif sys.platform == 'darwin':
            os.system('open -a Word')
        else:
            os.system('libreoffice --writer &')
        
        time.sleep(3)
        
        # 生成报告
        print("在Word中生成报告...")
        # 这里可以添加Word操作代码
        
        # 4. 保存并关闭所有应用
        print("\n4. 保存并关闭所有应用...")
        
        # 保存Word文档
        if os.name == 'nt':
            pyautogui.hotkey('ctrl', 's')
        elif sys.platform == 'darwin':
            pyautogui.hotkey('command', 's')
        else:
            pyautogui.hotkey('ctrl', 's')
        
        time.sleep(1)
        pyautogui.write('report.docx', interval=0.05)
        pyautogui.press('enter')
        time.sleep(1)
        
        # 保存Excel文件
        # 切换到Excel窗口(这里需要根据实际情况调整)
        pyautogui.hotkey('alt', 'tab')
        time.sleep(1)
        
        if os.name == 'nt':
            pyautogui.hotkey('ctrl', 's')
        elif sys.platform == 'darwin':
            pyautogui.hotkey('command', 's')
        else:
            pyautogui.hotkey('ctrl', 's')
        
        time.sleep(1)
        pyautogui.write('data.xlsx', interval=0.05)
        pyautogui.press('enter')
        time.sleep(1)
        
        logging.info("多应用协同自动化完成")
        print("\n多应用协同自动化完成!")
        return True
        
    except Exception as e:
        logging.error(f"多应用协同自动化失败: {e}")
        print(f"多应用协同自动化失败: {e}")
        return False

# 测试
if __name__ == "__main__":
    multi_app_automation()

10.7 案例总结与最佳实践

10.7.1 案例实施步骤
  1. 需求分析:明确自动化目标和范围
  2. 环境准备:安装必要的依赖和工具
  3. 脚本设计:规划自动化流程和步骤
  4. 代码实现:编写自动化脚本
  5. 测试验证:在测试环境中验证脚本
  6. 部署运行:在生产环境中部署和运行
  7. 监控维护:监控脚本运行状态并定期维护
10.7.2 最佳实践建议
  1. 模块化设计:将功能拆分为独立的函数,提高代码可维护性
  2. 异常处理:全面捕获和处理异常,确保脚本稳定运行
  3. 日志记录:详细记录脚本运行状态和错误信息
  4. 参数化配置:使用配置文件或命令行参数,提高脚本灵活性
  5. 性能优化:优化执行速度和内存使用
  6. 安全性:保护敏感信息,设置安全边界
  7. 可扩展性:设计可扩展的架构,便于添加新功能
  8. 文档化:编写详细的文档,说明脚本功能和使用方法
10.7.3 常见陷阱与避免方法
陷阱 避免方法
硬编码坐标 使用相对坐标或图像识别
固定延迟 使用动态等待或状态检测
缺少异常处理 全面捕获异常并添加重试机制
内存泄漏 及时释放资源,使用上下文管理器
安全风险 加密敏感信息,设置操作边界
平台兼容性 添加平台检测和适配代码
性能问题 优化算法,减少不必要的操作
维护困难 模块化设计,编写详细文档

10.8 未来发展趋势

10.8.1 技术发展方向
  1. AI 集成:结合人工智能技术,实现更智能的自动化
  2. 云服务:将自动化任务部署到云端,实现远程管理
  3. 容器化:使用Docker等容器技术,提高环境一致性
  4. 低代码平台:开发可视化的自动化配置平台
  5. 多设备协同:实现跨设备的自动化操作
10.8.2 行业应用前景
  1. 测试自动化:更智能、更全面的测试自动化
  2. 业务流程自动化:企业级业务流程的自动化
  3. 智能运维:IT系统的智能监控和维护
  4. 智能家居:家庭设备的自动化控制
  5. 工业自动化:工业生产流程的自动化

10.9 实战案例模板

10.9.1 通用自动化脚本模板
"""
PyAutoGUI 实战案例模板
"""

import pyautogui
import time
import logging
import argparse
import sys

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('automation.log'),
        logging.StreamHandler()
    ]
)

class AutomationTask:
    """
    自动化任务类
    """
    def __init__(self, config=None):
        self.config = config or {}
        self.setup()
    
    def setup(self):
        """
        初始化设置
        """
        # 启用安全机制
        pyautogui.FAILSAFE = True
        # 设置合理的延迟
        pyautogui.PAUSE = self.config.get('pause', 0.1)
        logging.info("环境设置完成")
    
    def run(self):
        """
        运行自动化任务
        """
        try:
            logging.info("开始自动化任务")
            
            # 步骤1: 准备
            self.prepare()
            
            # 步骤2: 执行主要操作
            self.execute()
            
            # 步骤3: 验证结果
            self.verify()
            
            # 步骤4: 清理
            self.cleanup()
            
            logging.info("自动化任务执行成功")
            return True
            
        except pyautogui.FailSafeException:
            logging.warning("检测到 FAILSAFE 信号,任务已停止")
            return False
        except Exception as e:
            logging.error(f"任务执行失败: {str(e)}")
            logging.error(traceback.format_exc())
            return False
    
    def prepare(self):
        """
        准备工作
        """
        logging.info("执行准备工作")
        # 实现准备逻辑
    
    def execute(self):
        """
        执行主要操作
        """
        logging.info("执行主要操作")
        # 实现主要操作逻辑
    
    def verify(self):
        """
        验证结果
        """
        logging.info("验证操作结果")
        # 实现验证逻辑
    
    def cleanup(self):
        """
        清理工作
        """
        logging.info("执行清理工作")
        # 实现清理逻辑

def main():
    """
    主函数
    """
    parser = argparse.ArgumentParser(description='PyAutoGUI 自动化脚本')
    parser.add_argument('--config', type=str, help='配置文件路径')
    parser.add_argument('--test', action='store_true', help='运行测试模式')
    args = parser.parse_args()
    
    # 加载配置
    config = {}
    if args.config:
        try:
            import json
            with open(args.config, 'r') as f:
                config = json.load(f)
        except Exception as e:
            logging.error(f"加载配置文件失败: {e}")
    
    # 创建并运行任务
    task = AutomationTask(config)
    success = task.run()
    
    if args.test:
        logging.info(f"测试模式 - 执行结果: {'成功' if success else '失败'}")
    
    sys.exit(0 if success else 1)

if __name__ == "__main__":
    main()
10.9.2 项目结构模板
automation_project/
├── main.py              # 主脚本
├── config.json          # 配置文件
├── modules/             # 模块目录
│   ├── __init__.py
│   ├── browser.py       # 浏览器自动化
│   ├── desktop.py       # 桌面应用自动化
│   └── utils.py         # 工具函数
├── resources/           # 资源目录
│   ├── images/          # 图像文件
│   └── data/            # 数据文件
├── logs/                # 日志目录
└── README.md            # 项目说明
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐