Appearance
5.2 桌面软件自动化
在日常办公中,我们不仅需要与网页进行交互,还需要操作各种桌面应用程序。通过Python实现桌面软件自动化可以帮助我们高效完成重复性任务。
本文将介绍如何使用Python实现桌面软件自动化,包括基础窗口操作、键盘输入模拟以及复杂的应用场景实现。
桌面自动化工具简介
在Python中,有多个强大的库可用于桌面软件自动化:
- pyautogui:跨平台的GUI自动化库,可以模拟鼠标和键盘操作
- pywinauto:专注于Windows平台的GUI自动化库
- AutoIt:一个专门用于Windows自动化的脚本语言(需配合Python使用)
- keyboard:专门用于键盘事件监听和模拟的库
- mouse:专门用于鼠标事件监听和模拟的库
安装所需依赖:
bash
pip install pyautogui pywinauto keyboard mouse
基础窗口操作
使用pyautogui控制鼠标
pyautogui 是一个跨平台的 GUI 自动化库,可以用来模拟鼠标操作。
以下是一个基础示例,展示如何使用 pyautogui 控制鼠标:
python
import pyautogui
import time
def basic_mouse_control():
"""
演示基础的鼠标控制
包括移动鼠标、点击、拖拽等操作
"""
try:
# 获取屏幕分辨率
screen_width, screen_height = pyautogui.size()
print(f"屏幕分辨率: {screen_width}x{screen_height}")
# 获取当前鼠标位置
current_position = pyautogui.position()
print(f"当前鼠标位置: {current_position}")
# 移动鼠标到屏幕中央
print("移动鼠标到屏幕中央...")
pyautogui.moveTo(screen_width / 2, screen_height / 2, duration=1)
# 等待1秒
time.sleep(1)
# 单击左键
print("单击左键...")
pyautogui.click()
# 等待1秒
time.sleep(1)
# 右击
print("右击...")
pyautogui.click(button='right')
# 等待1秒
time.sleep(1)
# 双击
print("双击...")
pyautogui.doubleClick()
# 拖拽(先移动到新位置,然后拖拽)
print("执行拖拽操作...")
pyautogui.moveTo(screen_width / 2, screen_height / 2, duration=1)
pyautogui.dragTo(screen_width / 2 + 100, screen_height / 2 + 100, 1, button='left')
print("鼠标操作完成")
return True
except Exception as e:
print(f"鼠标操作时出错: {e}")
return False
# 如果作为主程序运行
if __name__ == "__main__":
result = basic_mouse_control()
print(f"鼠标操作演示 {'成功' if result else '失败'}")
使用pywinauto管理窗口
pywinauto 是一个专注于 Windows 平台的 GUI 自动化库,以下是使用它管理窗口的示例:
python
from pywinauto import Application
import time
def manage_window_with_pywinauto():
"""
使用pywinauto管理窗口
示例功能:启动记事本并最大化窗口
"""
try:
# 启动记事本应用程序
app = Application().start("notepad.exe")
print("已启动记事本")
# 等待1秒
time.sleep(1)
# 连接到记事本窗口
window = app.window(title_re=".*Notepad", class_name="Notepad")
# 最大化窗口
window.maximize()
print("已最大化记事本窗口")
# 等待1秒
time.sleep(1)
# 最小化窗口
window.minimize()
print("已最小化记事本窗口")
# 等待1秒
time.sleep(1)
# 恢复窗口大小
window.restore()
print("已恢复记事本窗口大小")
# 关闭窗口
window.close()
print("已关闭记事本窗口")
return True
except Exception as e:
print(f"窗口管理时出错: {e}")
return False
# 如果作为主程序运行
if __name__ == "__main__":
result = manage_window_with_pywinauto()
print(f"窗口管理演示 {'成功' if result else '失败'}")
键盘输入自动化
使用pyautogui模拟键盘输入
pyautogui 不仅可以模拟鼠标操作,还可以模拟键盘输入。以下是一个示例:
python
import pyautogui
import time
def simulate_keyboard_input():
"""
模拟键盘输入操作
示例功能:打开记事本并输入文本
"""
try:
# 打开开始菜单
pyautogui.hotkey('win', 'r')
print("打开运行窗口")
# 输入notepad并回车
time.sleep(0.5)
pyautogui.write('notepad\n', interval=0.1)
print("启动记事本")
# 等待记事本打开
time.sleep(1)
# 输入欢迎信息
print("输入欢迎信息...")
pyautogui.write('欢迎来到Python自动化世界!\n', interval=0.1)
# 输入当前日期时间
from datetime import datetime
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"输入当前时间: {now}")
pyautogui.write(f"当前时间: {now}", interval=0.1)
# 保存文件
print("保存文件...")
pyautogui.hotkey('ctrl', 's') # 按下Ctrl+S
# 等待保存对话框
time.sleep(0.5)
# 输入文件名
file_name = "automated_text.txt"
print(f"输入文件名: {file_name}")
pyautogui.write(file_name, interval=0.1)
# 按Enter保存
time.sleep(0.5)
pyautogui.press('enter')
# 关闭记事本
print("关闭记事本...")
pyautogui.hotkey('alt', 'f4')
return True
except Exception as e:
print(f"键盘模拟时出错: {e}")
return False
# 如果作为主程序运行
if __name__ == "__main__":
result = simulate_keyboard_input()
print(f"键盘模拟演示 {'成功' if result else '失败'}")
监听和响应键盘事件
有时我们需要监听键盘事件来触发特定操作,以下是一个示例:
python
import keyboard
import time
def on_key_event(e):
"""
键盘事件处理函数
Args:
e: 键盘事件对象
"""
print(f"按键 '{e.name}' 被按下")
def listen_keyboard_events():
"""
监听键盘事件
示例功能:监听全局键盘事件
"""
print("开始监听键盘事件(按Esc停止监听)")
# 注册事件监听器
keyboard.on_press(on_key_event)
# 持续运行直到按下Esc键
while True:
if keyboard.is_pressed('esc'):
print("检测到Esc键被按下,停止监听")
break
time.sleep(0.1)
# 移除所有事件监听器
keyboard.unhook_all()
print("键盘事件监听结束")
# 如果作为主程序运行
if __name__ == "__main__":
listen_keyboard_events()
实际应用场景
场景一:自动化数据录入
python
import pyautogui
import time
import pandas as pd
def automated_data_entry(csv_file):
"""
自动从CSV文件读取数据并在桌面上录入
Args:
csv_file: 包含数据的CSV文件路径
"""
try:
# 加载数据
df = pd.read_csv(csv_file)
print(f"成功加载 {len(df)} 条记录")
# 提示用户切换到目标应用程序
print("请在5秒内切换到目标应用程序...")
time.sleep(5) # 给用户时间切换到目标应用
# 记录开始时间
start_time = time.time()
# 处理每条记录
processed_count = 0
for _, row in df.iterrows():
try:
# 输入姓名
pyautogui.write(row['name'], interval=0.1)
# 按Tab键
pyautogui.press('tab')
# 输入邮箱
pyautogui.write(row['email'], interval=0.1)
# 按Tab键
pyautogui.press('tab')
# 输入电话
pyautogui.write(row['phone'], interval=0.1)
# 按Enter键
pyautogui.press('enter')
# 模拟随机延迟以模仿真实操作
time.sleep(random.uniform(0.5, 1.5))
processed_count += 1
except Exception as e:
print(f"处理记录时出错: {e}")
# 计算耗时
elapsed_time = time.time() - start_time
print(f"数据录入完成,共处理 {processed_count} 条记录,耗时 {elapsed_time:.2f} 秒")
return processed_count > 0
except Exception as e:
print(f"自动化数据录入时出错: {e}")
return False
# 如果作为主程序运行
if __name__ == "__main__":
# 示例CSV文件格式应包含 name, email, phone 字段
result = automated_data_entry("data_entries.csv")
print(f"数据录入任务 {'成功' if result else '失败'}")
场景二:自动化报告生成器
python
import pyautogui
import time
import random
from datetime import datetime
def generate_automated_report():
"""
自动化报告生成流程
模拟打开Excel、创建报告、保存和关闭Excel的操作
"""
try:
# 打开Excel
print("打开Excel...")
pyautogui.hotkey('win', 'r')
time.sleep(0.5)
pyautogui.write('excel', interval=0.1)
pyautogui.press('enter')
time.sleep(2) # 等待Excel启动
# 创建新的报告
print("正在创建报告...")
# 输入标题
pyautogui.write('月度销售报告 - ' + datetime.now().strftime("%Y年%m月"), interval=0.1)
pyautogui.press('enter')
pyautogui.press('enter')
# 输入表头
headers = ['产品', '销售额', '数量']
for header in headers:
pyautogui.write(header, interval=0.1)
pyautogui.press('tab')
pyautogui.press('enter')
# 输入数据
products = ['产品A', '产品B', '产品C', '产品D']
sales = [random.randint(10000, 50000) for _ in range(4)]
quantities = [random.randint(100, 500) for _ in range(4)]
for i in range(4):
pyautogui.write(products[i], interval=0.1)
pyautogui.press('tab')
pyautogui.write(str(sales[i]), interval=0.1)
pyautogui.press('tab')
pyautogui.write(str(quantities[i]), interval=0.1)
pyautogui.press('enter')
# 计算总和
print("计算总和...")
pyautogui.hotkey('ctrl', 'end')
pyautogui.hotkey('ctrl', 'shiftleft', 'tab') # 选择最后一列
pyautogui.hotkey('alt', 'M', 'U', 'S') # 插入求和公式
# 保存文件
print("保存报告...")
pyautogui.hotkey('ctrl', 's')
time.sleep(0.5)
report_name = f"Monthly_Report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
pyautogui.write(report_name, interval=0.1)
pyautogui.press('enter')
time.sleep(0.5)
# 关闭Excel
print("关闭Excel...")
pyautogui.hotkey('alt', 'F4')
return True
except Exception as e:
print(f"自动化报告生成失败: {e}")
return False
# 如果作为主程序运行
if __name__ == "__main__":
result = generate_automated_report()
print(f"报告生成任务 {'成功' if result else '失败'}")
场景三:自动化软件测试助手
python
import pyautogui
import time
import random
import pandas as pd
def run_software_test(test_script_file):
"""
运行软件测试脚本
Args:
test_script_file: 测试脚本文件路径
"""
try:
# 加载测试脚本
test_steps = pd.read_excel(test_script_file)
print(f"加载了 {len(test_steps)} 个测试步骤")
# 初始化测试
print("开始软件测试...")
# 记录开始时间
start_time = time.time()
successful_steps = 0
# 执行每个测试步骤
for index, step in enumerate(test_steps.itertuples(), 1):
try:
print(f"执行步骤 {index}: {step.description}")
# 执行操作
if step.action == 'type':
pyautogui.write(step.value, interval=0.1)
elif step.action == 'press':
pyautogui.press(step.value)
elif step.action == 'hotkey':
keys = step.value.split('+')
pyautogui.hotkey(*keys)
elif step.action == 'wait':
wait_time = float(step.value) if step.value.isdigit() else 1
time.sleep(wait_time)
elif step.action == 'move_and_click':
coords = step.value.split(',')
x, y = int(coords[0]), int(coords[1])
pyautogui.moveTo(x, y, duration=0.5)
pyautogui.click()
successful_steps += 1
time.sleep(random.uniform(0.5, 1.5)) # 模拟人工作业间隔
except Exception as e:
print(f"步骤{index}执行失败:{e}")
break # 出错后跳出循环
# 计算耗时
elapsed_time = time.time() - start_time
success_rate = (successful_steps / len(test_steps)) * 100
print(f"测试完成,成功率: {success_rate:.2f}%,耗时: {elapsed_time:.2f} 秒")
print(f"成功步骤: {successful_steps}/{len(test_steps)}")
return successful_steps == len(test_steps)
except Exception as e:
print(f"软件测试执行失败: {e}")
return False
# 如果作为主程序运行
if __name__ == "__main__":
# 测试脚本文件应包含 description, action, value 字段
result = run_software_test("test_script.xlsx")
print(f"软件测试任务 {'成功' if result else '失败'}")
高级桌面自动化技巧
图像识别与操作
在某些情况下,我们需要基于屏幕上的图像来执行操作,pyautogui提供了强大的图像识别功能:
python
import pyautogui
import time
import os
def image_based_automation(image_folder):
"""
基于图像识别的自动化操作
Args:
image_folder: 包含目标图像的文件夹路径
"""
try:
print("开始基于图像的自动化操作...")
# 确保图像文件夹存在
if not os.path.exists(image_folder):
print(f"错误:图像文件夹 {image_folder} 不存在")
return False
# 查找并点击图标
icon_path = os.path.join(image_folder, "target_icon.png")
if os.path.exists(icon_path):
print(f"查找图标: {icon_path}")
icon_location = pyautogui.locateOnScreen(icon_path, confidence=0.8)
if icon_location:
print(f"找到图标,位置: {icon_location}")
icon_center = pyautogui.center(icon_location)
pyautogui.click(icon_center)
print(f"已点击图标,坐标: {icon_center}")
time.sleep(1)
else:
print("未找到目标图标")
return False
# 等待特定图像出现
dialog_path = os.path.join(image_folder, "dialog.png")
if os.path.exists(dialog_path):
print("等待对话框出现...")
start_time = time.time()
timeout = 10 # 10秒超时
while time.time() - start_time < timeout:
dialog_location = pyautogui.locateOnScreen(dialog_path, confidence=0.8)
if dialog_location:
print("对话框已出现")
break
time.sleep(0.5)
else:
print("等待对话框超时")
return False
# 执行其他基于图像的操作
print("基于图像的自动化操作完成")
return True
except Exception as e:
print(f"基于图像的自动化操作失败: {e}")
return False
屏幕区域监控
有时我们需要监控屏幕的特定区域,以便在发生变化时执行操作:
python
import pyautogui
import time
import numpy as np
from PIL import ImageGrab
def monitor_screen_region(region, check_interval=1.0, duration=60):
"""
监控屏幕特定区域的变化
Args:
region: 要监控的区域 (left, top, width, height)
check_interval: 检查间隔(秒)
duration: 监控持续时间(秒)
"""
try:
print(f"开始监控屏幕区域: {region}")
# 获取初始屏幕截图
initial_screenshot = np.array(ImageGrab.grab(bbox=region))
print("已获取初始屏幕截图")
start_time = time.time()
changes_detected = 0
# 监控循环
while time.time() - start_time < duration:
# 等待指定的检查间隔
time.sleep(check_interval)
# 获取当前屏幕截图
current_screenshot = np.array(ImageGrab.grab(bbox=region))
# 计算差异
diff = np.sum(initial_screenshot != current_screenshot)
change_percentage = (diff / (region[2] * region[3] * 3)) * 100 # 3 channels (RGB)
# 如果变化超过阈值,执行操作
if change_percentage > 5: # 5%的像素变化
changes_detected += 1
print(f"检测到屏幕变化 #{changes_detected},变化百分比: {change_percentage:.2f}%")
# 在这里执行响应变化的操作
# 例如:点击特定位置、发送通知等
# 更新初始截图
initial_screenshot = current_screenshot
print(f"监控结束,共检测到 {changes_detected} 次变化")
return changes_detected > 0
except Exception as e:
print(f"屏幕监控失败: {e}")
return False
安全与最佳实践
安全措施
在使用桌面自动化工具时,应采取以下安全措施:
python
import pyautogui
import time
# 设置安全措施
def setup_safety_measures():
"""
设置桌面自动化的安全措施
"""
# 设置pyautogui的安全措施
# 将鼠标移动到屏幕左上角将中断程序
pyautogui.FAILSAFE = True
print("已启用故障安全模式:将鼠标移动到屏幕左上角可中断自动化程序")
# 设置操作之间的延迟,防止操作过快
pyautogui.PAUSE = 0.5 # 每个操作之间暂停0.5秒
print(f"已设置操作间隔: {pyautogui.PAUSE}秒")
# 获取屏幕尺寸
screen_width, screen_height = pyautogui.size()
print(f"屏幕尺寸: {screen_width}x{screen_height}")
# 定义安全区域(避免操作屏幕边缘)
safe_margin = 10 # 像素
safe_region = (safe_margin, safe_margin,
screen_width - safe_margin * 2,
screen_height - safe_margin * 2)
print(f"已定义安全操作区域: {safe_region}")
return safe_region
# 使用示例
if __name__ == "__main__":
safe_region = setup_safety_measures()
# 在执行自动化操作前,先确认
print("\n警告:即将开始自动化操作!")
print("请确保:")
print("1. 已关闭所有重要文档")
print("2. 已保存所有未保存的工作")
print("3. 不会在自动化过程中手动操作鼠标和键盘")
confirmation = input("\n输入'yes'开始自动化操作,或任意键取消: ")
if confirmation.lower() != 'yes':
print("自动化操作已取消")
exit()
print("\n自动化操作将在5秒后开始...")
for i in range(5, 0, -1):
print(f"{i}...")
time.sleep(1)
print("开始自动化操作!")
# 在这里执行您的自动化操作
错误处理与恢复
在桌面自动化中,错误处理和恢复机制非常重要:
python
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 robust_automation_with_recovery(max_retries=3):
"""
具有错误恢复机制的健壮自动化流程
Args:
max_retries: 最大重试次数
"""
try:
# 定义检查点和恢复操作
checkpoints = [
{
"name": "应用程序启动",
"verify": lambda: pyautogui.locateOnScreen("app_window.png", confidence=0.8) is not None,
"action": lambda: pyautogui.hotkey('win', 'r') and pyautogui.write('notepad\n', interval=0.1),
"timeout": 5
},
{
"name": "文件打开",
"verify": lambda: pyautogui.locateOnScreen("file_open.png", confidence=0.8) is not None,
"action": lambda: pyautogui.hotkey('ctrl', 'o'),
"timeout": 3
},
# 添加更多检查点...
]
# 执行自动化流程
for checkpoint in checkpoints:
logging.info(f"执行检查点: {checkpoint['name']}")
# 尝试执行并验证
retry_count = 0
success = False
while not success and retry_count < max_retries:
try:
# 执行操作
checkpoint['action']()
# 等待并验证
start_time = time.time()
while time.time() - start_time < checkpoint['timeout']:
if checkpoint['verify']():
success = True
logging.info(f"检查点 '{checkpoint['name']}' 成功")
break
time.sleep(0.5)
# 如果验证失败
if not success:
retry_count += 1
logging.warning(f"检查点 '{checkpoint['name']}' 验证失败,重试 {retry_count}/{max_retries}")
except Exception as e:
retry_count += 1
logging.error(f"检查点 '{checkpoint['name']}' 执行出错: {e},重试 {retry_count}/{max_retries}")
# 如果所有重试都失败
if not success:
logging.error(f"检查点 '{checkpoint['name']}' 在 {max_retries} 次尝试后仍然失败,中止自动化流程")
return False
logging.info("自动化流程成功完成")
return True
except Exception as e:
logging.critical(f"自动化流程发生严重错误: {e}")
return False
实际应用场景(续)
场景四:批量文件处理助手
python
import pyautogui
import time
import os
import logging
def batch_file_processor(input_folder, output_folder, file_extension=".txt"):
"""
批量处理文件的自动化助手
Args:
input_folder: 输入文件夹路径
output_folder: 输出文件夹路径
file_extension: 要处理的文件扩展名
"""
try:
# 设置日志
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
# 确保输出文件夹存在
if not os.path.exists(output_folder):
os.makedirs(output_folder)
logging.info(f"已创建输出文件夹: {output_folder}")
# 获取所有需要处理的文件
files_to_process = []
for file in os.listdir(input_folder):
if file.endswith(file_extension):
files_to_process.append(os.path.join(input_folder, file))
logging.info(f"找到 {len(files_to_process)} 个{file_extension}文件需要处理")
if not files_to_process:
logging.warning(f"没有找到{file_extension}文件,任务结束")
return True
# 打开处理应用程序(以记事本为例)
pyautogui.hotkey('win', 'r')
time.sleep(0.5)
pyautogui.write('notepad', interval=0.1)
pyautogui.press('enter')
time.sleep(1)
# 处理每个文件
processed_count = 0
for file_path in files_to_process:
try:
file_name = os.path.basename(file_path)
logging.info(f"处理文件: {file_name}")
# 打开文件
pyautogui.hotkey('ctrl', 'o')
time.sleep(0.5)
pyautogui.write(file_path, interval=0.1)
pyautogui.press('enter')
time.sleep(0.5)
# 执行处理操作(示例:全选并转换为大写)
pyautogui.hotkey('ctrl', 'a') # 全选
time.sleep(0.2)
pyautogui.hotkey('ctrl', 'x') # 剪切
time.sleep(0.2)
# 模拟处理操作(在实际应用中替换为真实处理逻辑)
clipboard_text = pyautogui.hotkey('ctrl', 'v') # 粘贴回来
# 保存为新文件
pyautogui.hotkey('ctrl', 's') # 保存
time.sleep(0.5)
# 构建输出文件路径
output_file = os.path.join(output_folder, f"processed_{file_name}")
pyautogui.write(output_file, interval=0.1)
pyautogui.press('enter')
time.sleep(0.5)
# 处理可能出现的对话框(如覆盖确认)
confirm_dialog = pyautogui.locateOnScreen("confirm_dialog.png", confidence=0.7)
if confirm_dialog:
pyautogui.press('left') # 选择"是"
pyautogui.press('enter')
time.sleep(0.5)
processed_count += 1
logging.info(f"已处理文件: {file_name} -> processed_{file_name}")
except Exception as e:
logging.error(f"处理文件 {file_name} 时出错: {e}")
# 关闭应用程序
pyautogui.hotkey('alt', 'f4')
logging.info(f"批量处理完成,成功处理 {processed_count}/{len(files_to_process)} 个文件")
return processed_count == len(files_to_process)
except Exception as e:
logging.error(f"批量文件处理失败: {e}")
return False
小结
桌面软件自动化是提高工作效率的强大工具,通过Python可以实现各种复杂的自动化任务。本文介绍了以下关键内容:
- 基础窗口操作:使用pyautogui控制鼠标,使用pywinauto管理窗口
- 键盘输入自动化:模拟键盘输入和监听键盘事件
- 实际应用场景:
- 自动化数据录入
- 自动化报告生成器
- 自动化软件测试助手
- 批量文件处理助手
- 高级技巧:
- 基于图像识别的自动化
- 屏幕区域监控
- 安全与最佳实践:
- 安全措施设置
- 错误处理与恢复机制
在实际应用中,桌面自动化可以大大减少重复性工作,提高工作效率。但也需要注意安全措施和错误处理,确保自动化过程的稳定性和可靠性。
随着人工智能技术的发展,未来的桌面自动化将更加智能化,能够处理更复杂的任务,进一步提升办公效率。