[python]用pywin32库实现鼠标键盘自动控制:TaoToken统一Key接入与config.toml配置骨架
1. 为什么要在 Windows 上用 pywin32 做鼠标键盘自动控制如果你每天在 Windows 上重复做同一套操作——打开某个软件、点几个固定按钮、粘贴一段文本、再切到另一个窗口——那这套动作其实完全可以交给 Python 脚本。pywin32是 Python 在 Windows 平台上调用系统 API 的经典库它把user32.dll里的鼠标、键盘、窗口相关函数封装成了可以直接调用的 Python 接口。你不需要装驱动、不需要额外运行时pip install pywin32之后就能用win32api、win32con这些模块去模拟鼠标移动、点击、键盘按键。这篇内容聚焦一个最小可运行场景用pywin32完成鼠标移动点击与键盘输入跑通一次「坐标拾取 → 回放测试」的完整流程。同时我会给出一份config.toml配置骨架把脚本里未来可能用到的 AI 调用通道比如让脚本根据一段自然语言决定点哪里、输入什么预留成统一 Key 的配置位。这样你的自动化脚本不只是死板的坐标回放后面想接入模型做「看懂屏幕再操作」时不用再重构配置层。适合谁看写过一点 Python、想在 Windows 上做桌面自动化的同学或者已经在用pyautogui但想更贴近系统 API、控制更细的人。整篇的节奏是先装库、再拾取坐标、然后写最小脚本、最后用 TaoToken 的统一 Key 把 AI 调用位留出来。2. TaoToken 前置统一 Key 与 API 通道准备桌面自动化脚本本身不需要联网但一旦你想让脚本「智能一点」——比如把当前窗口标题发给模型判断下一步该点哪个按钮或者让模型生成一段要输入的文本——就需要一个稳定的 API 通道。TaoToken 在这里的角色是用一个统一 Key 对接多家模型脚本里只维护一份配置不用为每个模型单独改代码。你需要先拿到 Key。访问官网注册后进入控制台在 API Keys 页面创建一个新 Key官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content控制台创建 Keyhttps://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentconsoleAPI Keys 管理页https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi-keysAPI 的基础地址是https://taotoken.net/api注意这个地址不带 UTM 参数直接写进配置即可。如果你后面要接 Claude Code 这类编码工具可以看文档里的 Anthropic 兼容说明接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdocClaudeCode Anthropic 配置https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentClaudeCodeAnthropic注意Key 只存在本地config.toml里不要提交到 Git。脚本里读配置不要硬编码。3. 可复制配置config.toml 骨架与 pywin32 安装3.1 安装 pywin32在 Windows 的 cmd 或 PowerShell 里执行pip install pywin32装完后建议跑一次 post-install 脚本把一些系统 DLL 注册好某些版本需要python -m pywin32_postinstall -install验证是否可用import win32api import win32con print(win32api.GetCursorPos())如果这行能打印出当前鼠标坐标说明环境没问题。3.2 config.toml 骨架在项目根目录建一个config.toml把自动化参数和 AI 通道配置分开写。下面这份可以直接复制# config.toml [automation] # 动作之间的默认间隔单位秒太小容易丢事件 step_delay 0.15 # 点击后等待时间 click_delay 0.05 # 是否在每次动作前打印日志 verbose true [coordinates] # 坐标拾取后填进来格式 [x, y] source_start [100, 200] source_end [400, 200] target_point [800, 500] [ai] # TaoToken 统一 Key 通道 enabled false base_url https://taotoken.net/api api_key sk-你的Key model gpt-4o-mini timeout 30读取配置用 Python 3.11 自带的tomllibimport tomllib with open(config.toml, rb) as f: cfg tomllib.load(f) print(cfg[automation][step_delay]) print(cfg[ai][base_url])这样脚本里所有可变的东西都在配置里换坐标、换模型都不用动代码。4. 坐标拾取与鼠标键盘回放测试4.1 坐标拾取脚本先写一个pick_point.py运行后按回车就打印当前鼠标位置方便你把config.toml里的坐标填对import ctypes import time class Point(ctypes.Structure): _fields_ [(x, ctypes.c_long), (y, ctypes.c_long)] def get_point(): po Point() ctypes.windll.user32.GetCursorPos(ctypes.byref(po)) return int(po.x), int(po.y) if __name__ __main__: print(把鼠标移到目标位置然后按回车记录坐标。输入 q 退出。) while True: cmd input( ) if cmd.strip().lower() q: break print(当前坐标:, get_point())操作方式把鼠标放到「待复制文本的起点」回车记下坐标再放到终点回车最后放到目标位置回车。把这三个坐标填进config.toml的[coordinates]。4.2 最小回放脚本下面这个win_mouse_key.py是核心包含鼠标移动、点击、键盘输入三个基础能力# win_mouse_key.py import time import ctypes import win32api import win32con VK_CODE { ctrl: 0x11, shift: 0x10, alt: 0x12, a: 0x41, c: 0x43, v: 0x56, enter: 0x0D, esc: 0x1B, spacebar: 0x20, } def mouse_move(x, y): ctypes.windll.user32.SetCursorPos(x, y) def mouse_click(xNone, yNone, delay0.05): if x is not None and y is not None: mouse_move(x, y) time.sleep(delay) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0) def key_down(key): win32api.keybd_event(VK_CODE[key], 0, 0, 0) def key_up(key): win32api.keybd_event(VK_CODE[key], 0, win32con.KEYEVENTF_KEYUP, 0) def key_combo(keys, delay0.05): for k in keys: key_down(k) for k in reversed(keys): key_up(k) time.sleep(delay) def type_text(text, delay0.05): for ch in text: vk win32api.VkKeyScan(ch) 0xFF shift (win32api.VkKeyScan(ch) 8) 0x1 if shift: key_down(shift) win32api.keybd_event(vk, 0, 0, 0) win32api.keybd_event(vk, 0, win32con.KEYEVENTF_KEYUP, 0) if shift: key_up(shift) time.sleep(delay)4.3 回放测试写一个replay.py读配置、执行「选中文本 → 复制 → 粘贴到目标位置」import time import tomllib from win_mouse_key import mouse_click, key_combo with open(config.toml, rb) as f: cfg tomllib.load(f) coords cfg[coordinates] delay cfg[automation][step_delay] x1, y1 coords[source_start] x2, y2 coords[source_end] x3, y3 coords[target_point] def replay(): mouse_click(x1, y1) time.sleep(delay) key_combo([shift]) mouse_click(x2, y2) time.sleep(delay) key_combo([ctrl, c]) time.sleep(delay) mouse_click(x3, y3) time.sleep(delay) key_combo([ctrl, v]) if __name__ __main__: print(3 秒后开始回放请切到目标窗口...) time.sleep(3) replay() print(回放完成)实测下来把step_delay设成 0.15 秒比较稳太快的话某些应用会丢事件。运行前先切到你要操作的窗口脚本会等 3 秒再动手。5. 本篇常见错排查5.1 鼠标动了但没点击SetCursorPos只移动光标不触发点击。必须再调mouse_event发LEFTDOWN和LEFTUP。如果你只调了mouse_move看起来鼠标到位了但按钮没反应就是这个原因。5.2 键盘输入大写或符号不对keybd_event发的是虚拟键码大写字母和上档符号需要配合shift。上面type_text里用VkKeyScan自动判断是否需要 shift比手写映射表省事。如果你直接发0x41想输入大写 A实际出来的是小写 a。5.3 坐标在高分屏上偏移Windows 缩放不是 100% 时GetCursorPos返回的是物理像素但某些应用内部用的是逻辑坐标。如果发现点击位置总是偏先把系统缩放调到 100% 测试确认是缩放问题后再考虑用SetProcessDpiAwareness处理。5.4 config.toml 读取报错tomllib是 Python 3.11 才有的。如果你用的是 3.10 或更早装tomli然后import tomli as tomllib。另外open必须用rb二进制模式用文本模式会报错。5.5 AI 调用预留位没生效config.toml里[ai]段的enabled默认是false脚本不会主动去调模型。等你需要时把它改成true并在脚本里加一段 HTTP 请求。请求地址用base_url /v1/chat/completionsHeader 里带Authorization: Bearer api_key。想先验证模型通道是否通可以直接用模型对话页面发一条消息测试模型对话https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentchat如果你后面要把这套自动化接到长期运行的编码或 Agent 流程里可以考虑 Coding Plan省得每次手动管 KeyCoding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding-plan6. 把 AI 调用位接进自动化脚本前面config.toml里的[ai]段不是摆设。举个实际用法你希望脚本根据当前剪贴板内容决定粘贴到哪个坐标而不是写死。可以加一个函数把剪贴板文本发给模型让它返回目标坐标的键名import urllib.request import json def ask_model(prompt, cfg): url cfg[ai][base_url] /v1/chat/completions headers { Content-Type: application/json, Authorization: Bearer cfg[ai][api_key], } body { model: cfg[ai][model], messages: [{role: user, content: prompt}], } req urllib.request.Request( url, datajson.dumps(body).encode(), headersheaders, methodPOST ) with urllib.request.urlopen(req, timeoutcfg[ai][timeout]) as resp: data json.loads(resp.read()) return data[choices][0][message][content]调用时把cfg[ai][enabled]判断一下关闭时走默认坐标开启时走模型返回。这样你的pywin32自动化脚本就从「固定坐标回放」升级成「可配置的智能操作」而 Key 和地址始终只有一份。接入相关的细节和参数说明都在文档里遇到 401 或超时先查 Key 和base_url是否写对接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdocAPI Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi-keys最后提醒一句自动化脚本操作的是你自己的桌面测试时先把鼠标移到安全区域或者给脚本加个esc急停判断避免坐标填错点到不该点的地方。