WPS文字操作一站式方案(COM直连)


WPS 文字操作一站式方案(COM 直连)

结论先行

经过 23(批注)/24(修订)/25(MCP 实时编辑)/34(COM 直连)几轮折腾,结论很清楚:

做标书时,AI 操作 WPS 文字,只用一条通道:win32com 直连你正在打开的 WPS。

  • word-mcp-live(SSE 服务)不是不能用,而是「连接层」本身不稳定:SSE 长连接会掉、并发会堵、大文档会超时卡死、WPS 下 get_comments 报错。它的「实时编辑」底层也是 Word COM——等于在 COM 外面又套了一层会断的管道。
  • 纯 COM 直连(win32com)是 AI 直接握着 WPS 的 COM 把手,没有中间服务器,稳定。几次实测也验证了这一点。

所以:MCP/SSE 从主流程退役,只作为「离线批量生成整篇新文档」的可选后端(而且那用 python-docx 直接做也一样,不绕 MCP)。实时改你正在编的标书模板,一律走 COM。

你项目里 com_insert.py / com_read_para.py / com_fill_blanks.py / get_table.py 已经全是 COM 直连写法,方向本来就对。混乱只来自「表格读写 + 批注」还挂在 MCP 上(见第三节)。


一、连接方式(最关键,先把坑钉死)

✓ 正确:连到正在运行的 WPS(实时编辑用这个)

import win32com.client
app = win32com.client.GetActiveObject('KWPS.Application')  # WPS
# 或 'Word.Application'(MS Word)
doc = app.ActiveDocument
  • 你项目里四个 COM 脚本全是这个写法,实测可用。
  • 多软件兜底:循环试 ['KWPS.Application', 'Word.Application'],哪个能连上用哪个(见各脚本里的 _get_word_app())。
  • ProgID 大小写不敏感,kwps / KWPS 都行。

✗ 三个常见坑

  1. 别用 pythoncom.GetActiveObject(...)(低层那个) —— 返回的是裸 PyIUnknown 壳,没有 .Documents,一调就挂。要用 win32com.client.GetActiveObject(带 client 的,它会帮你包装好)。34 号笔记说的「GetActiveObject 不能用」指的就是低层那个,不是现在脚本里这个。两者名字只差一个 client。
  2. 别用 win32com.client.Dispatch(...) 去开已打开的文档 —— Dispatch 会新起一个 WPS 实例,文档被你手头的 WPS 锁着,它打不开。Dispatch 只在「WPS 没开这个文件、纯离线处理」时才用。
  3. win32com.client.GetObject(Class='Word.Application') 也能连运行中的实例,和 GetActiveObject 等价(34 号推荐它)。两种都行,脚本统一用 GetActiveObject 即可。

⚠ 兜底:后台进程 COM 激活失败(无效的类字符串)

WorkBuddy 的 Bash 若在后台 / 非交互桌面上下文跑,可能报 (-2147221005, '无效的类字符串')。这是 Windows COM 拒给「非交互式」子进程激活 LocalServer 的问题,不是代码错。

解法:写个 .bat,用 explorer.exe 启动它(explorer 继承真正的交互桌面上下文),Python 把结果写进 txt,再读 txt。详见 34 号笔记「QClaw/OpenClaw 无法直接调用 COM」一节。当前 WorkBuddy 一般能直连,失败才走这座桥。


二、操作全景表(每个动作对应哪个脚本)

你要做什么 走 COM 的哪个脚本 / 函数 命令示例
读某段文字 / 看空格段结构 com_read_para.py → read_para / analyze_spaces python com_read_para.py 6
在段落指定位置插字 com_insert.py → insert_text_at_pos python com_insert.py insert 12 10 "山西金辉"
在某个词后面插字 com_insert.py → insert_text_after_anchor python com_insert.py after "供应商:" "山西金辉"
模板填空(保留空格、插内容) com_fill_blanks.py → fill_paragraph 先 probe 6,再 fill(读 JSON)
光标定位当前表格序号 get_table.py → get_current_table 光标点进表,返回序号
插入文档块(营业执照等) get_table.py → insert_block insert_block('营业执照.docx', after='...')
读 / 写表格单元格 ⚠ 目前还在 mcp_client.py(MCP) —
加批注 ⚠ 笔记里有 COM 写法,但没封装成脚本 —

表里打 ⚠ 的两项,就是你现在「还不得不碰 MCP」或「没脚本」的地方。这正是混乱根源,见第三节。


三、为什么还乱 + 怎么收口

混乱来自两点:

(1)表格读写和批注还挂在 MCP 上。 mcp_client.py 用 SSE 连 word_mcp_server 做 get_table_info / set_cell,而定位表格用 COM 的 get_current_table,等于「一半 COM 一半 MCP」。表格填几十个格时 SSE 一抖就前功尽弃。其实表格单元格读写用纯 COM 一句话就能做,根本不需要服务器:

# 读
val = doc.Tables(ti).Cell(row, col).Range.Text.rstrip('\r\x07')
# 写
doc.Tables(ti).Cell(row, col).Range.Text = "张三"

应该新增一个 com_table.py:读表结构 + 批量 set_cell(从后往前、插入不动原格式),把 mcp_client.py 彻底替掉。

(2)批注没脚本。 23 号笔记用的是解压 docx 改 XML 的老路(适合离线),但实时给打开的文档加批注,COM 一句话更稳:

doc.Comments.Add(range, "批注内容")   # range 用 Find 定位或段落 Range

封装进 com_comment.py 即可。

收口后的工具集(全 COM,零 SSE):

.workbuddy/scripts/
├── com_conn.py        # 统一连接(_get_word_app,循环 KWPS/Word + 报错提示)
├── com_read_para.py   # 读段 / 空格段分析
├── com_insert.py      # 插字 / 锚点插字
├── com_fill_blanks.py # 模板填空
├── com_table.py       # 定位表 + 读表 + 批量写格  ← 新建
├── com_comment.py     # 加批注                      ← 新建
├── get_table.py       # get_current_table + insert_block(可并入 com_table)
└── scripts_guide.md   # 改成纯 COM 版

mcp_client.py 和 word_mcp_server.exe 从主流程删除(保留说明:仅当你哪天要离线批量生成整篇文档且不想引 python-docx 时用)。scripts 目录里那 30 多个 _*.py 实验/探查文件也应清掉(移到 _archive/ 或直接删)。


四、通用铁律(每条都来自踩坑)

  1. 插入,不替换。 用 InsertAfter / InsertBefore 在指定位置塞字,不动原内容;别用 range.Text = xxx 整体覆盖(会把格式和空格带崩)。填空保留 6 空格、在第 3 空格后插内容(com_fill_blanks 已内置)。
  2. 多格 / 多填空区,从后往前处理。 每插一处,后面的字符位置全变;从后往前才不影响已处理的(com_fill_blanks 已做)。
  3. 每次改完重新读位置。 调了插入 / 删空格后,段落的 Start/End 会变,必须重新 doc.Paragraphs(n).Range 拿新位置,不能用旧的继续算。
  4. 段落尾部标记要清。 Range.Text 尾巴一定带 \r(普通段)/ \n(软回车)/ \x07(表格单元格)。统一 rstrip("\r\n\x0d\x0a\x07"),别只 rstrip \r。
  5. 控制台中文乱码: 跑脚本前设 PYTHONIOENCODING=utf-8(Git Bash 管道默认 GBK,会炸)。
  6. 大文档先 sleep 再操作。 几十 MB 的说明文档 Open 后等 2–3 秒再动。
  7. 批量操作前先 Ctrl+S。 COM 直接改文档,没有「撤销服务器」这层保护;改前存盘,错了能撤。
  8. Find 用短词。 财建〔2019〕 找不到就搜 财建〔,全角半角括号差异大。

五、要不要保留 MCP?

一句话:实时编辑场景,不需要。 它给你的 120 个工具里,批注 / 修订 / 查找替换 / 表格,COM 都能做且更稳。唯一 MCP 还有点价值的是「跨平台离线生成整篇文档」(python-docx 模式,不依赖打开 WPS)——但这种用 python-docx 直接写也一样,不绕 MCP。所以主流程纯 COM,MCP 退役。


六、修订(Track Changes)怎么做

24 号笔记折腾的「解压 docx 改 XML 插 <w:ins>」是离线 fragile 路线。实时场景下,COM 一把开关就够:

doc.TrackRevisions = True          # 开跟踪更改
# 之后任何 InsertBefore/InsertAfter 都会变成红色修订标记
doc.Revisions.AcceptAll()          # 一次性接受(相当于填完模板后落定)
doc.Revisions.RejectAll()          # 或全拒

比 XML 手改稳得多,且人工在 WPS 里 Ctrl+Z 也能撤。


文章作者: 摸鱼
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 摸鱼 !
赏
  目录