惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cloudbric
Cloudbric
Schneier on Security
Schneier on Security
V2EX - 技术
V2EX - 技术
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
O
OpenAI News
S
Security @ Cisco Blogs
Scott Helme
Scott Helme
Security Archives - TechRepublic
Security Archives - TechRepublic
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
T
Threatpost
Hacker News: Ask HN
Hacker News: Ask HN
Microsoft Azure Blog
Microsoft Azure Blog
Know Your Adversary
Know Your Adversary
博客园 - 三生石上(FineUI控件)
A
About on SuperTechFans
Forbes - Security
Forbes - Security
NISL@THU
NISL@THU
Security Latest
Security Latest
G
Google Developers Blog
D
Docker
T
Threat Research - Cisco Blogs
N
Netflix TechBlog - Medium
C
CERT Recently Published Vulnerability Notes
H
Help Net Security
B
Blog
Martin Fowler
Martin Fowler
N
News and Events Feed by Topic
Simon Willison's Weblog
Simon Willison's Weblog
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
Lohrmann on Cybersecurity
Y
Y Combinator Blog
PCI Perspectives
PCI Perspectives
F
Fortinet All Blogs
MyScale Blog
MyScale Blog
Project Zero
Project Zero
爱范儿
爱范儿
Cisco Talos Blog
Cisco Talos Blog
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
人人都是产品经理
人人都是产品经理
V
Vulnerabilities – Threatpost
P
Proofpoint News Feed
Cyberwarzone
Cyberwarzone
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
TaoSecurity Blog
TaoSecurity Blog
N
News | PayPal Newsroom
Recorded Future
Recorded Future

逸思杂陈

家用网络 vlan 单线复用 Linux 平台 intel UHD 6xx 核显 openvino 探索 UI 区域检测的 vibe coding 复盘 mitmproxy 使用 esim 使用相关 阻止 bilibili 网页自动关注 Hexo 版本更新与技术债务 配置 Linux 作为主力操作系统 语言的力量 联想笔记本 BIOS 跳过检测强制降级 redroid “设备未获得play保护机制认证” 问题 在 iOS 上访问安卓应用 在 VSCode 中用 Rust 刷LeetCode 跨域的那些事 HomeBrew 与无 root 权限 Linux 环境包管理 给 macOS 词典增加生词本功能 关闭子进程打开的文件描述符 容器内进程优雅退出 Python 循环变量泄露与延迟绑定 bash 语法备忘 MySQL 自定义数据库路径
在 Linux 虚拟机中使用 PyAutoGUI 做自动化
Jay.Run · 2025-05-28 · via 逸思杂陈

PyAutoGUI 是 GUI 功能强大自动化方案,但 UI 程序的运行环境选择与配置也是一大难题。

系统选择

为了让环境可迁移,免维护,资源消耗少,必须使用虚拟化的方案。
虽然 PyAutoGUI 支持 Windows/macOS/Linux 三个平台。但是各有各的弊端。

  • Windows 的系统臃肿且开发环境不友好
  • macOS 的权限管理过于严格且虚拟化难度大,高dpi的屏幕也不适合自动化
  • Linux 就是最好的选择了,但执行的应用可能不支持 Linux,必须引入 Wine

综合以上情况考虑,系统环境选择如下

  • pve: 宿主机系统,也可以选择别的环境
  • debian: 客户机系统,目前是 debian 12, 方便使用 deepin 的 wine 程序
  • mate: 桌面环境,比较轻量,实测兼容性比 xfce 好
  • 星火应用商店: 方便安装各种国内软件和 Wine 程序
  • 统信 Windows 应用兼容引擎: 在星火应用商店中安装,可以用于安装和打包商店中没有的程序

虚拟机配置

步骤

  1. 创建好 pve 虚拟机, 安装 debian,选择 mate 桌面
  2. 设置分辨率:控制中心 -> 显示器 -> 设置为 1920x1080
  3. 关闭自动睡眠:控制中心 -> 电源管理 -> 动作和显示修改为从不
  4. 关闭屏幕保护:控制中心 -> 屏幕保护程序 -> 取消勾选所有选项
  5. 安装gnome-screenshot: 用于 PyAutoGUI 内部调用截图
  6. 安装星火应用商店(可选)
  7. 安装统信 Windows 应用兼容引擎(可选):在星火应用商店中安装
  8. 火焰截图(可选):在星火应用商店中安装,更方便对应用的按钮和文字截图。

其他说明:

  • 如果不关闭自动睡眠和屏幕保护,PyAutoGUI 就无法截取到应用的图像,也就无法操作了。
  • 图形显示协议默认选 x11,wayland 对显卡有要求,虚拟机不方便处理。

睡眠后时间不对

虚拟机睡眠唤醒后时间没有更新,不知道为什么没有触发时间更新。
目前只能通过强行同步来解决

在脚本里执行同步命令

1
2

sudo ntpdig -S ntp.aliyun.com

或者,理论上可以通过虚拟机中的 systemd-suspend hook,或者 pve hookscript 来解决(没试成功)

远程登录调试

pve 默认图片控制台不太方便,不能复制粘贴,所以使用远程登录调试
由于系统使用 x11 环境,这里使用 xrdp 作为远程服务端。
如果以后更新到 wayland,可以使用 gnome-remote-desktop

1
2
sudo apt update
sudo apt install xorgxrdp xrdp

远程登录时找不到显示器

xrdp 或者 ssh 远程登录执行脚本时,窗口相关命令可能会提示找不到显示器。
可以在自动化脚本中设置以下环境变量

1
2
os.environ['DISPLAY'] = ':0'
os.environ['XAUTHORITY'] = '/home/<your-name>/.Xauthority'

过滤没必要的截图日志

gnome-screenshot 截图时会产生一些无用日志

1
2
** Message: 17:36:31.888: Unable to use GNOME Shell's 
builtin screenshot interface, resorting to fallback X11.

新建一个 gnome-screenshot 文件,赋予执行权限,放到 PATH 环境变量中比 /usr/bin 靠前的路径

1
2
#!/bin/bash
exec /usr/bin/gnome-screenshot "$@" >> /tmp/gnome-screenshot.log 2>&1

验证码识别

pytesseract

常见的方案是 pytesseract, 但是效果不好,识别率比较一般。

安装

1
2
sudo apt install tesseract-ocr
pip install pytesseract

使用

1
pytesseract.image_to_string(image, config='--psm 8 -c tessedit_char_whitelist=0123456789')

ddddocr

ddddocr 是基于机器学习的验证码识别库,识别效果比较好。

这里使用 docker 安装 fastapi接口

1
docker run -d -p 8000:8000 oozzbb/ddddocr-fastapi:latest

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def ocr_image(file='region.png'):
url = 'http://your-address:8000/ocr'
with open(file, 'rb') as fp:
files = {
'file': fp,
}
data = {
'probability': 'false',
'png_fix': 'false',
'charsets': '0123456789'
}
response = requests.post(url, files=files, data=data)
assert response.ok
return response.json()['data']

高效执行自动化脚本

可以在宿主机远程调用自动化脚本,并且脚本执行完成后挂起虚拟机

1
2
3
4
5
6
7
8
9
10
HOST=your-name@vm-ip-address
VMID=109

qm resume $VMID
sleep 2

ssh $HOST "SOME_VAR=foobar python your-script.py"
sleep 1

qm suspend $VMID

其他有用的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

def wm_to_front(title: str):
if sys.platform == 'linux':
return subprocess.check_call(['wmctrl', '-a', title])
raise NotImplementedError


def click_image(image, confidence=0.9, grayscale=True, delay=1.5,
duration=0.6, offset=(1, 0), abort=True, click=True):
try:
loc = pyautogui.locateOnScreen(image, confidence=confidence, grayscale=grayscale)
except pyautogui.ImageNotFoundException:
loc = None
if loc:
x, y = pyautogui.center(loc)
if click:
pyautogui.click(x+offset[0], y+offset[1], duration=duration)
else:
pyautogui.moveTo(x+offset[0], y+offset[1], duration=duration)
time.sleep(delay)
return loc
else:
if abort:
raise RuntimeError(f"can not find {image}!")
else:
return None


def wait_button(image, timeout, interval=10):
for _ in range(timeout//interval):
time.sleep(interval)
loc = click_image(image, abort=False)
if loc:
break
else:
raise RuntimeError(f'wait {image} failed')
time.sleep(interval/2)

使用感受

PyAutoGUI 是基于图像而不是图型控件来识别目标,没有确认反馈。
相比于网页自动化的 Selenium 就感觉落后些了。
当然,Windows 平台有 pywinauto 支持控件识别,但我不咋熟悉。
总之,PyAutoGUI 就像手枪,虽然比较简陋,但还是很直观的,执行简单的任务也够用了。

注意事项

  • 自动化代码中不要编码用户名密码相关信息,建议用环境变量传入
  • 不要轻易调整系统的 dpi(建议设为1.0) 和分辨率,可能导致图片无法识别
  • xfce 对 wine 应用的兼容性似乎不好,wine 文件保存对话框被可能被反复触发,原因不明。