首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >用 WorkBuddy + pyautogui 实现绿源ERP电池发货单全流程自动化

用 WorkBuddy + pyautogui 实现绿源ERP电池发货单全流程自动化

原创
作者头像
用户12517330
发布2026-05-27 12:26:00
发布2026-05-27 12:26:00
341
举报
代码语言:javascript
复制
# 用 WorkBuddy + pyautogui 实现绿源ERP电池发货单全流程自动化

> **场景**:电池车制造企业的PMC仓库每天需要打印50-80张电池发货单,手工操作繁琐易错。本文记录了如何用 WorkBuddy AI 助手 + Python pyautogui 实现从ERP打印到Excel表格自动生成的完整自动化方案。

---

## 一、背景与痛点

我是一名电池车制造企业PMC仓库的工作人员,日常工作流程如下:

1. 登录绿源ERP系统(Web端,通过夸克浏览器访问)
2. 从「整单发货管理」页面查询当天发货单
3. 逐个打开发货单明细,打印A4电池单
4. 根据打印出来的单据,手工制作电池发货明细Excel表格

**痛点**:
- 每天打印50-80张单子,重复操作大量时间
- 手工做表容易出错(型号、数量、分组计算)
- 数据一致性难以保证(ERP数据 vs Excel表格)

**目标**:错误率为0,效率最大化。

---

## 二、方案选型:为什么用 pyautogui 而不是 Selenium?

| 方案 | 优点 | 缺点 |
|------|------|------|
| **pyautogui(最终选择)** | 不需要浏览器驱动,模拟真实操作,零安全风险 | 依赖固定坐标,屏幕分辨率变化需调整 |
| Selenium/Playwright | 代码更稳定,不依赖坐标 | 需要安装驱动,可能触发ERP安全告警 |
| 直接调ERP后端API | 最高效 | 需要IT部门配合,有安全风险 |

选择 pyautogui 的原因:
- **零安全风险**:跟正常人工操作完全一样,不会触发任何安全告警
- **无需额外依赖**:不需要安装浏览器驱动、不需要获取API权限
- **AI辅助开发**:WorkBuddy 可以实时截图分析、调整坐标、调试脚本,开发效率极高

---

## 三、环境搭建

### 3.1 需要安装的Python库

```bash
pip install pyautogui pyperclip Pillow openpyxl
```

### 3.2 依赖说明

- `pyautogui` — 模拟鼠标键盘操作
- `pyperclip` — 剪贴板读写
- `Pillow` — 屏幕截图和像素检测
- `openpyxl` — 读写Excel文件

---

## 四、核心功能一:自动打印发货单

### 4.1 工作流程

```
输入单号 → 查询 → 双击结果行 → A4电池打印 → 打印预览
→ 扫描工具栏定位"打印"按钮 → 点击 → 打印对话框
→ 智能页码处理 → 确定打印 → 关闭预览 → 关闭Tab → 下一个
```

### 4.2 坐标适配(关键技巧)

所有坐标基于 1920×1080 参考分辨率,运行时自动缩放到实际屏幕:

```python
REF_W = 1920
REF_H = 1080

def sc(coord):
    """将参考坐标转换为实际屏幕坐标"""
    sw, sh = pyautogui.size()
    x = int(coord[0] * sw / REF_W)
    y = int(coord[1] * sh / REF_H)
    return x, y
```

### 4.3 坐标获取方法(踩坑经验)

**不要用像素扫描或估算坐标!** 正确做法:

1. AI助手运行 `pyautogui.position()` 读取鼠标当前位置
2. 用户手动把鼠标移到目标位置
3. AI读取坐标并写入脚本

这样获取的坐标100%准确。

### 4.4 打印预览按钮定位(亮点功能)

打印预览的工具栏按钮位置不固定,需要实时扫描定位:

```python
def find_toolbar_buttons():
    """在打印预览工具栏上实时定位"打印"和"关闭"按钮"""
    full = pyautogui.screenshot()
    toolbar = full.crop((0, 25, sw, 85))  # 裁剪工具栏区域

    # 自动检测背景色
    pixels = list(toolbar.getdata())
    color_counts = Counter(pixels)
    bg_color = color_counts.most_common(1)[0][0]

    # 按列统计非背景像素数,找出按钮块
    col_data = []
    for x in range(w):
        non_bg = sum(1 for y in range(h)
                     if not is_similar(pixels[y*w+x], bg_color))
        col_data.append(non_bg)

    # 根据非背景像素的连续分布,识别按钮位置
    # "关闭"按钮在最右边(宽度15~35像素)
    # "打印"按钮在"关闭"按钮左边紧邻
```

**核心思路**:工具栏是纯色背景+文字按钮,通过列方向非背景像素数的变化,就能准确定位每个按钮的边界。

### 4.5 多页文档只打印最后一页(智能页码处理)

电池发货单可能是多页的,但实际只需要最后一页的数据。解决方案:

```python
# 1. 点击"页码范围(G)"单选按钮
pyautogui.click(pr_x, pr_y)

# 2. 截取"从(F)"输入框像素判断是否可编辑
pixel = screen.getpixel(sc(COORD_FROM_F))

# 3. 灰色 = 单页文档,直接打印
# 4. 白色 = 多页文档,读取"到(T)"页码,把"从(F)"改为相同值
if not is_gray and to_num > 1:
    # 只打印最后一页
    paste_text(str(to_num))
```

---

## 五、核心功能二:自动采集数据

### 5.1 数据采集时机

在打开发货单明细页、打印之前,先采集页面数据:

```
打开明细页 → 点击表格区域 → Ctrl+A全选 → Ctrl+C复制 → 保存到文件 → 继续打印
```

### 5.2 为什么要点击表格再全选?

ERP页面的Ctrl+A默认全选的是整个页面(包括导航栏、按钮等),而不是表格内容。**必须先点击表格区域让焦点到表格上**,Ctrl+A才能选中表格数据。

### 5.3 数据解析(核心难点)

ERP复制出来的文本格式像这样(Ctrl+A → Ctrl+C的结果):

```
发货单号
            (空行)
ZCFH26032732
经销商:
            (空行)
吉长春宽城区于宝伟(专)
制单时间
            (空行)
2026/5/25 10:30:00

换配电池
1
ZCYDD260100001
...
标配电池编码    105000123    每组节数    4    标配配发数量    10
电池延迟发货    否
换配电池编码    105000244    每组节数    4    换配配发数量    44
```

**关键发现**:
1. 标签和值之间**隔了一个空行**,需要跳过空行取值
2. 用 `"否"`(电池延迟发货)作为标配和换配的分界线
3. 分界线后面的空行数量**不固定**,不同单号不一样

### 5.4 解析代码(跳过空行法)

```python
def get_next_value(keyword, start=0):
    """找到含keyword的行,跳过空行,返回下一个非空值"""
    for i in range(start, len(lines)):
        if keyword in lines[i]:
            for j in range(i + 1, min(i + 5, len(lines))):
                val = lines[j].strip()
                if val:
                    return val
            break
    return ""

# 提取换配电池数据:用"否"作为分界线
for j in range(rs, end):
    if lines[j].strip() == '否':
        delay_idx = j
        break

# 跳过空行,取换配编码、每组节数、配发数量
non_empty = []
for j in range(delay_idx + 1, min(delay_idx + 20, end)):
    s = lines[j].strip()
    if s:
        non_empty.append(s)

swap_code = non_empty[0]      # 换配电池编码
swap_per_group = non_empty[1]  # 每组节数
swap_qty = non_empty[2]        # 换配配发数量
```

---

## 六、核心功能三:自动生成Excel表格

### 6.1 电池型号与分组规则

| 电池类型 | 电压 | 每组节数 | 示例 |
|---------|------|---------|------|
| 铅酸电池 | 48V | ÷4 | 44节 ÷ 4 = 11组 |
| 铅酸电池 | 60V | ÷5 | 50节 ÷ 5 = 10组 |
| 铅酸电池 | 72V | ÷6 | 72节 ÷ 6 = 12组 |
| **锂电池** | **任意** | **÷1** | 30节 ÷ 1 = 30组 |

> **踩坑**:锂电池的分组除数是1,不是按电压算!通过电池编码映射表中的 `type` 字段判断。

### 6.2 电池编码映射表

维护了一个JSON映射文件 `battery_code_map.json`(135条记录),结构如下:

```json
{
  "105000244": {
    "model": "铅酸电池48V20AH",
    "factory": "天能",
    "type": "铅酸电池"
  },
  "1050010000H": {
    "model": "锂电池48V30AH",
    "factory": "星恒",
    "type": "锂电池"
  }
}
```

### 6.3 Excel表格公式

| 列 | 公式 | 说明 |
|----|------|------|
| J(实际发货组) | `=I{n}/每组节数` | 实际发货(节)÷每组节数 |
| M(应欠节) | `=I{n}-G{n}` | 实际发货-应发数量 |
| N(应欠组) | `=M{n}/每组节数` | 应欠节÷每组节数 |
| O(现欠发节) | `=Q{n}+M{n}` | 上次累计欠发+本次应欠 |

---

## 七、从OCR方案到数据采集方案的演进

### 7.0 第一版:手工做表
纯手工,50张单子做一天。

### 7.1 第二版:OCR拍照识别
打印出来后拍照 → AI识别单据上的型号和数量 → 生成Excel。

**问题**:
- OCR识别率不稳定,数字容易粘连
- 数据顺序可能被AI打乱
- 需要人工逐条核对

### 7.2 第三版:直接从ERP采集(最终方案)
打印时同步采集ERP页面数据 → 解析文本 → 生成Excel。

**优势**:
- **错误率为0**:直接从ERP原始数据提取,不经过OCR
- **数据顺序不变**:原始文本解析,严格保持原始顺序
- **效率翻倍**:打印和采集同时完成,不再需要额外拍照步骤

---

## 八、踩坑记录与解决方案

### 坑1:Ctrl+A没有选中表格内容
**原因**:焦点不在表格上,全选的是整个页面。
**解决**:先点击表格区域(坐标550,380),再Ctrl+A。

### 坑2:不同单号的空行数量不一样
**原因**:ERP复制出来的文本中,标签和值之间的空行数量不固定。
**解决**:用"跳过空行取非空值"的方法,不依赖固定偏移量。

### 坑3:锂电池分组计算错误
**原因**:锂电池48V30AH,按48V÷4=10.5组,但实际应该是30÷1=30组。
**解决**:通过编码映射表的 `type` 字段判断,锂电池统一÷1。

### 坑4:双击发货单号会打开详情页
**原因**:从列表页复制单号时,双击单元格会触发跳转。
**解决**:只能用鼠标拖选方式复制,不能双击。

### 坑5:单元格行高不统一
**原因**:ERP表格的行高不是固定的,有的行高有的行矮。
**解决**:整列拖选后用正则解析,不逐行按固定行高操作。

---

## 九、项目文件结构

```
Claw/
├── print_erp.py              # 主打印脚本(v12.0),含数据采集
├── gen_excel_standalone.py   # 独立Excel生成脚本
├── battery_code_map.json     # 电池编码映射表(135条)
├── clipboard_data/           # 采集数据存储目录
│   ├── ZCFH26032732.txt
│   ├── ZCFH26032740.txt
│   └── ...
├── test_query.py             # 日期筛选查询测试
└── copy_order_list.py        # 复制发货单号列表测试
```

---

## 十、效果对比

| 指标 | 自动化前 | 自动化后 |
|------|---------|---------|
| 打印50张单子 | ~2小时(手工) | ~20分钟(脚本) |
| 做Excel表格 | ~3小时(手工) | ~1分钟(自动生成) |
| 数据准确率 | ~95%(手工易错) | **100%**(原始数据直采) |
| 多页打印 | 手动选择页码 | 自动只打最后一页 |

---

## 十一、后续规划

1. **记账后数据核对**:装车后手工修改Excel实发数量 → ERP记账后导出数据 → AI自动核对两边是否一致
2. **整单发货管理页面自动查询**:自动填入日期、查询、读取单号列表
3. **全流程打通**:查询 → 读取单号 → 逐个打印+采集 → 生成Excel → 记账核对,一键完成

---

## 总结

这个项目的核心经验:

1. **AI辅助开发效率极高**:坐标定位、脚本调试、问题排查都可以让AI实时参与
2. **pyautogui + AI 是强大的组合**:AI负责"看"(截图分析)和"想"(逻辑处理),pyautogui负责"做"(鼠标键盘操作)
3. **先验证再编码**:每个坐标都通过用户手动验证,每个功能都经过实测确认
4. **从失败中迭代**:OCR方案失败后快速转向数据采集方案,最终实现了错误率为0的目标

希望这篇文章对有类似需求的朋友有所帮助!

---

*使用工具:WorkBuddy AI助手 + Python 3.13 + pyautogui + openpyxl*
*标签:#WorkBuddy #自动化 #ERP #pyautogui #办公效率*

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档