☰
Pywin32笔记:用统一 Key 打通 Python 桌面自动化与 AI 工具链
2026/9/29 20:25:29 网站建设 项目流程

1. 当 Pywin32 脚本开始需要 AI 能力

如果你在用 Pywin32 写 Windows 桌面自动化,大概率经历过这个阶段:一开始只是FindWindow找窗口、SendMessage填文本框、keybd_event敲回车,脚本跑得挺顺。但需求很快会变——比如让脚本读一段界面上的报错文本,自动判断该点哪个按钮;或者把抓到的表格内容丢给模型做归类,再回填到另一个窗口。这时候问题就来了:Pywin32 负责的是「手和眼」,AI 负责的是「脑子」,而这两边的凭证体系完全是两套。

我见过太多项目里,config.toml里躺着三四个不同平台的 Key,每个 Key 的额度、限流、模型名都不一样。脚本里写死一个openai_api_key,换模型要改代码,加一个工具又要再塞一个 Key。更麻烦的是,Pywin32 脚本经常是打包成 exe 丢给同事用的,Key 硬编码进去既不安全,也没法统一轮换。

这篇笔记就从这个痛点出发:用 TaoToken 作为统一的 Key 和 API 通道,把 Pywin32 桌面自动化和 AI 工具链串起来。适合已经会写基础 Pywin32 脚本、想让脚本「聪明一点」的开发者。核心思路很简单——Pywin32 继续管窗口和输入,所有 AI 调用走同一个 base_url 和同一个 Key,配置集中到settings.json和config.toml两个文件里。

TaoToken 在这里扮演的角色是「统一入口」:你不需要在脚本里区分今天调的是哪个模型、走的是哪家通道,只需要维护一份凭证。官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api ,下面所有配置都围绕这两个地址展开。

2. 前置准备:Pywin32 环境与统一 Key

2.1 安装 Pywin32 并确认版本

先确认你的 Python 环境。Pywin32 对 Python 版本比较敏感,建议用 3.9 到 3.11 之间的版本,太新的 Python 有时轮子还没跟上。

python -m pip install pywin32==306 python -m pip install requests

装完之后跑一句验证,能打印出当前前台窗口标题就说明环境没问题:

import win32gui hwnd = win32gui.GetForegroundWindow() print(win32gui.GetWindowText(hwnd))

如果这一步报ImportError: DLL load failed,多半是 Pywin32 的后处理脚本没跑,执行python Scripts/pywin32_postinstall.py -install(路径按你的 Python 安装目录调整)即可。

2.2 拿到统一 Key

去 TaoToken 控制台创建一个 API Key。地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,登录后在 API Keys 页面点新建,复制出来的字符串形如sk-xxxxxxxx。这个 Key 就是你后面所有 AI 调用的唯一凭证,Pywin32 脚本、命令行工具、编辑器插件都用它。

注意:Key 只显示一次,复制后先存到密码管理器里。不要直接写进会提交到 Git 的代码。

2.3 为什么用统一通道而不是多套 Key

假设你的 Pywin32 脚本要做三件事:识别截图里的文字、把识别结果翻译、根据翻译结果决定点哪个菜单。如果分别接三个平台,你要维护三份 Key、三套 base_url、三种请求格式。统一通道之后,请求格式收敛成一套 OpenAI 兼容的/v1/chat/completions,模型名在请求体里换,Key 和地址不变。对 Pywin32 这种「脚本里到处是业务逻辑」的场景,少一层凭证管理就少一堆 bug。

3. 可复制配置:settings.json 与 config.toml 骨架

3.1 settings.json:给脚本读的运行时配置

Pywin32 脚本通常用json读配置最省事,因为标准库自带。建一个settings.json:

{ "ai": { "base_url": "https://taotoken.net/api", "api_key": "sk-你的Key", "default_model": "gpt-4o-mini", "timeout": 30 }, "automation": { "target_window_title": "新建文本文档.txt - 记事本", "input_edit_class": "EDIT", "poll_interval": 0.5 } }

读取代码:

import json with open("settings.json", "r", encoding="utf-8") as f: cfg = json.load(f) BASE_URL = cfg["ai"]["base_url"] API_KEY = cfg["ai"]["api_key"] MODEL = cfg["ai"]["default_model"]

3.2 config.toml:给工具链读的配置

如果你同时用命令行工具或编辑器插件,它们更认config.toml。放在用户目录下,比如C:\Users\你的用户名\.taotoken\config.toml:

[provider] name = "taotoken" base_url = "https://taotoken.net/api" api_key = "sk-你的Key" [models] default = "gpt-4o-mini" coding = "claude-3-5-sonnet" [request] timeout = 30 max_retries = 2

这样 Pywin32 脚本读settings.json,外部工具读config.toml,两边指向同一个 base_url 和同一个 Key。换 Key 的时候两个文件一起改,或者用环境变量覆盖。

3.3 用环境变量兜底

生产环境里不要把 Key 写进文件。改成从环境变量读,配置文件里留空:

import os API_KEY = os.environ.get("TAOTOKEN_API_KEY") or cfg["ai"]["api_key"]

然后在系统环境变量里设TAOTOKEN_API_KEY。Pywin32 脚本打包成 exe 后,同事只需要在自己机器上配一次环境变量,不用改代码。

4. 在 Pywin32 脚本里调用 AI 并验证

4.1 封装一个最小的调用函数

Pywin32 脚本里调 AI,本质就是发一个 HTTP POST。用requests封装:

import requests def ask_ai(prompt, model=None): url = f"{BASE_URL}/v1/chat/completions" headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } payload = { "model": model or MODEL, "messages": [ {"role": "system", "content": "你是一个桌面自动化助手,只输出简洁结果。"}, {"role": "user", "content": prompt} ], "temperature": 0.2 } resp = requests.post(url, headers=headers, json=payload, timeout=30) resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"]

4.2 连通性验证:先跑通再集成

不要一上来就塞进复杂的 Pywin32 流程。先单独跑一个验证脚本:

if __name__ == "__main__": result = ask_ai("用一句话说明什么是窗口句柄") print("AI 返回:", result)

看到正常返回就说明 Key、base_url、模型名三者都对。如果报 401,检查 Key 有没有多余空格;报 404,检查 base_url 是不是写成了https://taotoken.net/api/v1(正确写法是 base_url 到/api,路径里再拼/v1/chat/completions)。

4.3 把 AI 结果接回 Pywin32 操作

验证通过后,做一个真实的小闭环:读取记事本内容,让 AI 判断是否包含关键词,包含就点确定按钮。

import win32gui, win32con, win32api, time def get_edit_text(hwnd_parent): edit = win32gui.FindWindowEx(hwnd_parent, 0, "EDIT", None) buf_size = win32api.SendMessage(edit, win32con.WM_GETTEXTLENGTH, 0, 0) + 1 buf = win32gui.PyMakeBuffer(buf_size) win32gui.SendMessage(edit, win32con.WM_GETTEXT, buf_size, buf) address, length = win32gui.PyGetBufferAddressAndLen(buf) return win32gui.PyGetString(address, length) hwnd = win32gui.FindWindow(0, "新建文本文档.txt - 记事本") if hwnd: text = get_edit_text(hwnd) verdict = ask_ai(f"下面这段文字是否包含'错误'二字?只回答是或否:\n{text}") print("AI 判断:", verdict) if "是" in verdict: # 这里可以接后续的按钮点击逻辑 pass

这段代码把 Pywin32 的窗口读取和 AI 的判断能力串起来了。实测下来,WM_GETTEXT拿中文时要注意编码,如果返回乱码,把PyGetString换成按 gbk 解码的方式。

4.4 批量场景下的连接复用

如果脚本要循环处理很多窗口,每次requests.post都新建连接会慢。用Session复用:

session = requests.Session() session.headers.update({ "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" }) def ask_ai_fast(prompt): payload = {"model": MODEL, "messages": [{"role": "user", "content": prompt}]} r = session.post(f"{BASE_URL}/v1/chat/completions", json=payload, timeout=30) r.raise_for_status() return r.json()["choices"][0]["message"]["content"]

5. 本篇常见错排查

5.1 401 Unauthorized

最常见的原因是 Key 复制时带了换行或空格。用print(repr(API_KEY))看一眼,正常应该是'sk-...'没有多余字符。另一个原因是环境变量没生效,Pywin32 脚本打包成 exe 后读的是打包时的环境,需要在目标机器上重新配。

5.2 404 Not Found

九成是 base_url 拼错。记住规则:base_url 写到https://taotoken.net/api,请求路径再拼/v1/chat/completions。如果你在 config.toml 里写成了https://taotoken.net/api/v1,代码里又拼一次/v1,就会变成/api/v1/v1/...。

5.3 窗口句柄找不到

FindWindow返回 0 通常是因为窗口标题变了。记事本打开不同文件标题不同,用EnumWindows遍历再匹配更稳:

def find_notepad(): result = [] def cb(hwnd, _): if win32gui.IsWindowVisible(hwnd): title = win32gui.GetWindowText(hwnd) if "记事本" in title: result.append(hwnd) return True win32gui.EnumWindows(cb, None) return result[0] if result else 0

5.4 中文乱码

Pywin32 的SendMessage设置文本时,中文要编码成 gbk:text.encode('gbk')。读取时如果PyGetString出来是乱码,改用win32gui.PyGetString(address, length)后手动encode('latin1').decode('gbk')试试。

5.5 请求超时

Pywin32 脚本常在后台跑,网络抖动会导致超时。给requests加max_retries:

from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry retry = Retry(total=2, backoff_factor=0.5, status_forcelist=[500, 502, 503]) session.mount("https://", HTTPAdapter(max_retries=retry))

6. 把统一 Key 用顺手的几个入口

配置跑通之后,日常最常用的几个动作可以直接走对应入口,省得每次翻文档。

需要管理或新建 Key 的时候,去 API Keys 页面:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。接入细节和参数说明看文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。想先在网页里试一下模型返回格式,用模型对话:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。

如果你的 Pywin32 脚本已经不只是「调一次 AI」,而是长期跑批、需要稳定额度和多模型切换,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。用 Claude Code 做自动化脚本开发的,Anthropic 接入入口在:https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。

最后留一个我踩过的坑:Pywin32 脚本里不要用time.sleep等 AI 返回,网络慢的时候会卡住整个自动化流程。改成先发请求、拿到结果再操作窗口,或者用线程池把 AI 调用和窗口操作分开。这样即使某次请求慢,也不会让鼠标键盘事件错位。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询