E-Documents & E-books

import xlwings as xw import os def copy_shapes_with_position(src_file, src_sheet_name, tgt_file, tgt_sheet_name): app = None try: # 检查文件是否存在 if not os.path.exists(src_file): raise FileNotFoundError(f"源文件不存在: {src_file}") if not os.path.exists(tgt_file): raise FileNotFoundError(f"目标文件不存在: {tgt_file}") print("启动 Excel 应用...") app = xw.App(visible=False) app.screen_updating = False # 打开工作簿 src_wb = app.books.open(src_file) tgt_wb = app.books.open(tgt_file) src_ws = src_wb.sheets[src_sheet_name] tgt_ws = tgt_wb.sheets[tgt_sheet_name] shapes = src_ws.shapes count = shapes.count print(f"在 '{src_sheet_name}' 中找到 {count} 个形状") if count == 0: print("警告:没有发现任何形状。") return for i, shape in enumerate(shapes): name = shape.name left = shape.left top = shape.top width = shape.width height = shape.height text = shape.text if hasattr(shape, 'text') and shape.text is not None else "" print(f"处理形状 {i+1}: {name} -> 位置({left}, {top}), 大小({width}x{height})") # 使用 .api 添加文本框(适用于文本类形状) try: # 在目标工作表中添加一个文本框 new_shape_api = tgt_ws.api.Shapes.AddTextbox( Orientation=1, # msoTextOrientationHorizontal Left=left, Top=top, Width=width, Height=height ) # 设置名称和文本 new_shape_api.Name = f"TextBox_Copied_{i + 1}" # 可选:保留原名或避免重复 new_shape_api.TextFrame.Characters().Text = text print(f"✅ 已添加文本框: {new_shape_api.Name}") except Exception as e: print(f"❌ 添加文本框失败 ({name}): {e}") # 保存目标文件 tgt_wb.save() print(f"✅ 成功保存到: {tgt_file}") except Exception as e: print(f"⛔ 发生错误: {e}") import traceback traceback.print_exc() finally: if app: print("关闭 Excel 应用...") app.quit() # 调用函数 copy_shapes_with_position( src_file='3104.xlsx', src_sheet_name='3104', tgt_file='test.xlsx', tgt_sheet_name='Sheet2' ) 会 发生错误: (-2147352567, '发生意外。', (0, None, None, None, 0, -2147467259), None)
11-26
你正在使用以下代码尝试通过 `xlwings` 在目标 Excel 工作表中 **用 `.api.Shapes.AddTextbox()` 创建文本框**,但仍然抛出经典 COM 错误: ``` ⛔ 发生错误: (-2147352567, '发生意外。', (0, None, None, None, 0, -2147467259), None) ``` 这个错误码: - `-2147352567` → `DISP_E_EXCEPTION` - `-2147467259` → `E_FAIL`(未指定失败) 虽然代码逻辑看似正确,但 **`.api.Shapes.AddTextbox()` 是一个非常敏感的 COM 调用**,它对运行环境、Excel 版本、权限和上下文有严格要求。 --- ## ✅ 根本原因分析 你遇到的问题不是 Python 或 xlwings 的 bug,而是底层 **Microsoft Excel COM 接口调用失败**。常见原因如下: | 原因 | 是否可能 | 说明 | |------|----------|------| | ❌ 使用 WPS Office 替代 Microsoft Excel | ⭐⭐⭐⭐⭐ | WPS 不支持大多数 `.api.*` 操作 | | ❌ 后台残留 Excel 进程 | ⭐⭐⭐⭐☆ | 即使看不到窗口也会导致冲突 | | ❌ 宏安全设置过高 | ⭐⭐⭐⭐☆ | 阻止自动化创建形状 | | ❌ 文件路径含中文或 OneDrive 路径 | ⭐⭐⭐☆☆ | 可能导致加载异常 | | ❌ 没有激活目标工作表 | ⭐⭐⭐☆☆ | `.AddTextbox()` 需要上下文 | | ❌ 形状名称重复或非法字符 | ⭐⭐☆☆☆ | 导致后续操作失败 | --- ## ✅ 终极解决方案:确保所有前提条件满足 + 添加容错机制 ### ✅ 改进后的稳定版本代码 ```python import xlwings as xw import os import time import traceback def copy_shapes_with_position(src_file, src_sheet_name, tgt_file, tgt_sheet_name): app = None try: # 检查文件是否存在 if not os.path.exists(src_file): raise FileNotFoundError(f"源文件不存在: {src_file}") if not os.path.exists(tgt_file): raise FileNotFoundError(f"目标文件不存在: {tgt_file}") print("关闭旧 Excel 实例...") os.system("taskkill /f /im EXCEL.EXE >nul 2>&1") time.sleep(2) # 等待完全关闭 print("启动 Excel 应用...") app = xw.App(visible=False) # 先设为 False;调试时可改为 True 查看界面 app.screen_updating = False app.display_alerts = False # 打开工作簿 print("打开源文件和目标文件...") src_wb = app.books.open(src_file) tgt_wb = app.books.open(tgt_file) src_ws = src_wb.sheets[src_sheet_name] tgt_ws = tgt_wb.sheets[tgt_sheet_name] # ✅ 关键:先激活目标工作表 tgt_ws.activate() shapes = src_ws.shapes count = shapes.count print(f"在 '{src_sheet_name}' 中找到 {count} 个形状") if count == 0: print("警告:没有发现任何形状。") return for i, shape in enumerate(shapes): name = shape.name try: left = float(shape.left) top = float(shape.top) width = float(shape.width) height = float(shape.height) text = shape.text or "" except Exception as e: print(f"❌ 读取形状属性失败 ({name}): {e}") continue print(f"处理形状 {i+1}: {name} -> 位置({left}, {top}), 大小({width}x{height})") try: # ✅ 确保目标 sheet 被选中(建立上下文) tgt_ws.select() # 使用 .api 添加文本框 new_shape_api = tgt_ws.api.Shapes.AddTextbox( Orientation=1, # msoTextOrientationHorizontal Left=left, Top=top, Width=width, Height=height ) # 设置名称(避免重复) new_name = f"Copied_TextBox_{i + 1}" new_shape_api.Name = new_name # 设置文本内容 if text.strip(): new_shape_api.TextFrame.Characters().Text = text print(f"✅ 成功添加文本框: {new_name}") except Exception as e: print(f"❌ AddTextbox 失败 ({name}): {e}") # 输出详细堆栈 traceback.print_exc() # 保存文件 tgt_wb.save() print(f"✅ 成功保存到: {tgt_file}") except Exception as e: print(f"⛔ 发生错误: {e}") traceback.print_exc() finally: if app: print("关闭 Excel 应用...") app.quit() # 调用函数(请确保路径为英文) copy_shapes_with_position( src_file=r'C:\temp\3104.xlsx', # 改为纯英文路径! src_sheet_name='3104', tgt_file=r'C:\temp\test.xlsx', tgt_sheet_name='Sheet2' ) ``` --- ## ✅ 必须满足的前提条件(否则必失败) ### ✅ 1. 必须使用 **Microsoft Excel**(不能是 WPS) > ❌ WPS Office 完全不支持 `.api.Shapes.AddTextbox()` > ✅ 必须安装 MS Office(如 Office 365、Office 2016+) 📌 检查方法: ```python import xlwings as xw app = xw.App() print(app.version) # 如果输出类似 '16.x' 表示是 MS Excel app.quit() ``` --- ### ✅ 2. 必须开启“信任对 VBA 工程对象模型的访问” #### 步骤: 1. 打开 Excel 2. 文件 → 选项 → 信任中心 → 信任中心设置 3. 宏设置 → ✅ 勾选“信任对 VBA 工程对象模型的访问” 👉 这是关键中的关键!否则 `.api.*` 调用会被阻止! --- ### ✅ 3. 使用纯英文路径(不要包含中文、空格、OneDrive) ❌ 错误路径: ```python 'D:/用户/桌面/test.xlsx' 'C:/Users/张三/Documents/test.xlsx' ``` ✅ 正确路径: ```python r'C:\temp\test.xlsx' ``` 建议: - 新建文件夹 `C:\temp\` - 把你的 `3104.xlsx` 和 `test.xlsx` 复制进去再试 --- ### ✅ 4. 以管理员身份运行脚本 右键你的 IDE 或命令行 → “以管理员身份运行” 否则可能无法与 COM 正常通信。 --- ### ✅ 5. 测试最小案例:手动创建一个简单文本框 你可以先不用复制,直接测试是否能新建一个文本框: ```python import xlwings as xw app = xw.App(visible=True) wb = app.books.add() ws = wb.sheets[0] # 尝试添加一个文本框 try: shape = ws.api.Shapes.AddTextbox( Orientation=1, Left=100, Top=100, Width=200, Height=80 ) shape.TextFrame.Characters().Text = "Hello from Python!" shape.Name = "TestBox" print("✅ 成功创建文本框") except Exception as e: print("❌ 创建失败:", e) import traceback traceback.print_exc() # 不退出,让你能看到结果 input("按回车关闭...") app.quit() ``` 📌 如果这个都失败 → 说明是环境问题,不是代码问题! --- ## ✅ 替代方案:如果 `.AddTextbox()` 始终失败? 可以考虑改用 `.copy()` + `.Paste()` 方法(更可靠),前提是形状本身是可复制的。 ```python shape.copy() tgt_ws.activate() tgt_ws.range("A1").select() tgt_ws.api.Paste() # 更稳定 ``` 或者导出为图片、HTML、PDF 等格式间接处理。 --- ## ✅ 总结:你现在应该怎么做? | 步骤 | 操作 | |------|------| | 1 | 确认使用的是 **Microsoft Excel**(非 WPS) | | 2 | 开启“信任对 VBA 工程对象模型的访问” | | 3 | 把文件放到 `C:\temp\` 下 | | 4 | 以管理员身份运行脚本 | | 5 | 使用上面改进后的完整代码测试 | | 6 | 先跑最小测试验证能否创建文本框 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值