综合项目 2 第二个能力轴:对账

订单流水对账机器人

上一项练"生成文档",这一项练"比对数据"。财务、审计、运营每天都在做这种事。

项目目标

预计用时:4–6 小时(分 6 关,第 6 关为进阶选做) |  前置知识:建议先完成综合项目 1;本项依赖第 3 课(变量)、第 4 课(判断)、第 5 课(循环)、第 6 课(数组与字典)、第 7 课(Excel)、第 9 课(邮件)、第七部分(网页) |  本课性质:综合项目(第二个能力轴:交叉比对与差异报告)

同样分 6 关,逐关回报。这一项第 2 关的"标志变量"是零基础最容易写错的地方,做完第 2 关先发我。

知识地图

这是第二个综合项目,与项目 1 互补:项目 1 练"一行数据 → 一份文档",是流水线;项目 2 练"两张表互相找",是交叉比对。整套课程里第一次出现"双层循环 + 标志变量"的组合,它也是认证里比对类题目的通用套路。

本项目在哪儿
综合项目 2,在项目 1 之后;项目 1 练生成,本项目练比对。
重点
双层循环 + 标志变量 + 三类差异的分类判断。
难点
标志变量的初始化位置、变量作用范围、金额的类型与精度比较。
学完的标志
随便换两份流水,你都能自动找出全部差异,写成报告并发邮件。

一、需求说明

背景:月底财务要核对"业务系统流水"和"银行流水"是否一致,人工一条条对,几百条能对到眼花。

这类任务的核心不是"算数",而是"两边互查":以其中一张表为基准,逐条去另一张表里找同一条记录——找到了再比金额,找不到就是单边账。把这句话翻译成代码,就是"外层循环一行、内层循环找一遍"的双层循环。

项内容
输入①系统流水.xlsx:订单号、金额(6 条)
输入②银行流水.xlsx:订单号、金额(6 条)
输出①对账结果.xlsx:订单号、差异类型、系统金额、银行金额
输出②一封汇总邮件:共几处差异、各是什么类型

差异类型定义(对账的标准三类)

类型名含义
金额不一致两边都有这个订单号,但金额不同
系统有银行无系统里有,银行流水里找不到
银行有系统无银行流水里有,系统里找不到

为什么要先定死"三类差异"?因为对账的结论必须可枚举、可统计。只有分类标准统一,第 5 关发出去的邮件才能说清"共几处差异、各是什么类型",而不是一堆零散记录。

样例数据(已为你准备)

直接复制到 res/:系统流水.csv · 银行流水.csv(用 Excel 打开后另存为 .xlsx)。

两份数据对照
系统流水                银行流水
D001  100.00            D001  100.00
D002  250.50            D002  250.50
D003   80.00            D003   88.00   ← 金额不一致
D004  999.99   ←系统有  D005   45.00
D005   45.00            D006  320.00
D006  320.00            D007  500.00   ← 银行有

正确答案先剧透给你(用来验收,不要提前写进流程):差异共 3 处——D003 金额不一致、D004 系统有银行无、D007 银行有系统无;一致的 4 笔是 D001、D002、D005、D006。

二、关卡地图

六关层层递进:先是"读进来",再"正向查一遍",再"反向查一遍",然后"写报告、发邮件",最后是进阶优化。

第 1 关 · 读两张表 第 2 关 · 系统有 / 金额不一致 第 3 关 · 银行有系统无 第 4 关 · 写出对账结果.xlsx 第 5 关 · 发邮件汇总 第 6 关 · 进阶:字典查找表 / 金额容差 / 网页三方核对
对账机器人流程:读两张表、正向比对、反向比对、输出三类差异并写表发邮件 对账机器人:读两张表 → 正向 → 反向 → 输出 以系统流水为基准找银行,再反过来补一遍,才不会漏掉“银行有、系统无”。 ① 读入 读两张表 系统流水 + 银行流水 得到两个二维数组 ② 正向 系统 → 银行 标志变量记录找到没 找出金额差异 ③ 反向 银行 → 系统 补出银行独有 再查一遍不漏项 ④ 输出 写表 + 发邮件 对账结果.xlsx 邮件发汇总 三类差异 金额不一致 系统有,银行无 银行有,系统无 正向比对找前两类,反向比对补第三类;三类都齐了,报告才算完整。
图 9 · 先正向、再反向,才能覆盖三类差异;最后写进 Excel 并用邮件发出结论。

在你的流程文件夹下建好:

你的流程/
└── res/
    ├── 系统流水.xlsx
    ├── 银行流水.xlsx
    └── 对账结果.xlsx      ← 不用先建,第 4 关会自动新建

准备步骤

  1. 建 res 文件夹,把 系统流水.csv 和 银行流水.csv 用 Excel 打开后,分别另存为 res\系统流水.xlsx、res\银行流水.xlsx。期望:每张表第一行表头,下面 6 行数据。
  2. 打开两张表核对左下角对照图:D003 金额不同、D004 系统独有、D007 银行独有。期望:你能人工看出这 3 处差异,作为后面机器人结果的验收基准。
  3. 常见报错:若流程报"找不到文件",检查扩展名是否真为 .xlsx(Windows 可能隐藏扩展名),以及文件名里有无多余空格。

三、逐关实现

第 1 关 · 把两张表都读进来

用到:第 7 课(读取区域)、第 6 课(二维数组)

分别打开两张表,各读 "A1:B7",得到两个二维数组,各自打印确认。

  1. 新建变量 objSys、objBank、系统rows、银行rows。
  2. 拖入 打开Excel 打开 res\系统流水.xlsx,输出到 objSys;再拖 读取区域 读 "Sheet1"、"A1:B7" 存入 系统rows;随后 关闭Excel工作簿(objSys)。
  3. 对银行流水重复同样三步,结果存入 银行rows。期望:两个数组都读到了,含表头共 7 行。
  4. 用 输出调试信息 打印两个数组长度。提示:想取数组长度,用数据处理 ▸ 数组里的"获取数组长度"命令;不确定名字就翻命令手册。
  5. 常见报错:工作表名不对 → 试填 0;行数偏少 → 检查区域是否 A1:B7。
骨架
打开Excel(res\系统流水.xlsx) → objSys
读取区域(objSys, "Sheet1", "A1:B7") → 系统rows
关闭Excel工作簿(objSys)

打开Excel(res\银行流水.xlsx) → objBank
读取区域(objBank, "Sheet1", "A1:B7") → 银行rows
关闭Excel工作簿(objBank)

输出调试信息("系统行数:" & 系统rows 的长度)
输出调试信息("银行行数:" & 银行rows 的长度)
验收:两个数组都读到了(含表头共 7 行)。
提示:想取数组长度,用数据处理 ▸ 数组里的"获取数组长度"命令;不确定名字就翻命令手册。

第 2 关 · 遍历系统流水,找出两类差异

用到:第 5 课(双层 For Each)、第 4 课(If)、第 3 课(变量)
新技能:标志变量(flag)。外层的每一行,都要去内层找一遍。"找到"这个事实,必须用一个布尔变量记下来:进内层前设 找到 = False,内层找到了就设 找到 = True,内层结束后再看它——不是在内层里直接判断。
  1. 在外层用 For Each 遍历 系统rows,循环体先 序号 = 序号 + 1;用 If 序号 > 1 跳过表头。
  2. 取本行订单号和系统金额:订单号 = 系统行[0]、系统金额 = 系统行[1]。
  3. 进内层之前先重置:找到 = False、银行金额 = ""。期望:这两句写在 For Each 银行行 的外面、外层循环体的里面。
  4. 内层用 For Each 遍历 银行rows:若 银行行[0] = 订单号,则 找到 = True、银行金额 = 银行行[1]。
  5. 内层结束后才判断:If 找到 = False → 输出"系统有银行无";ElseIf 银行金额 <> 系统金额 → 输出"金额不一致"。
  6. 常见报错:结果多出或少出 → 九成是 找到 = False 放错位置(放到循环外了),或把变量定义在循环体里导致每轮被重新声明。
骨架(注意 找到 的位置)
Dim 序号 = 0
For Each 系统行 In 系统rows
    序号 = 序号 + 1
    If 序号 > 1                      // 跳过表头(BotScript 不写 Then)
        Dim 订单号 = 系统行[0]
        Dim 系统金额 = 系统行[1]
        Dim 找到 = False             // ← 每行重新置为 False
        Dim 银行金额 = ""

        For Each 银行行 In 银行rows
            If 银行行[0] = 订单号
                找到 = True
                银行金额 = 银行行[1]
            End If
        Next

        If 找到 = False
            输出调试信息(订单号 & " 系统有银行无(" & 系统金额 & ")")
        ElseIf 银行金额 <> 系统金额
            输出调试信息(订单号 & " 金额不一致:系统 " & 系统金额 & " / 银行 " & 银行金额)
        End If
    End If
Next
验收:应输出两条——D003 金额不一致、D004 系统有银行无。
如果多输出或少输出:九成是 找到 = False 放错位置(放到循环外面了),或 Dim 写进了循环体导致变量没重置。

第 3 关 · 反向再查一遍:银行有系统无

用到:第 2 关同样的套路,方向反过来

再遍历一遍银行流水,去系统流水里找;找不到的就是"银行有系统无"。同样用标志变量。

  1. 照抄第 2 关的结构,把"外层 系统rows / 内层 银行rows"换成"外层 银行rows / 内层 系统rows"。
  2. 标志变量依旧在外层每轮开头重置为 False;内层命中则记为 True。
  3. 内层结束后,若 找到 = False,输出"银行有系统无"。注意:这一轮只输出单边差异,不需要再比金额。
  4. 常见报错:若把方向写反或忘了重置标志,会漏掉 D007 或多报一堆假差异。
验收:新增输出一条 D007 银行有系统无(500.00),此时三类差异各一条,共 3 条。

第 4 关 · 写出对账结果.xlsx

用到:第 6 课(数组追加)、第 7 课(写入区域、文件不存在自动新建)

把结果先攒成一个二维数组(第一行是表头),再一次性 写入区域。

  1. 流程一开始先建结果数组并放表头:Dim 结果 = [["订单号", "差异类型", "系统金额", "银行金额"]]。
  2. 在发现差异的每一处,往数组尾部追加一行:结果 = 在数组尾部添加元素(结果, [订单号, "金额不一致", 系统金额, 银行金额])。三类差异各追加一次。
  3. 全部比完后打开(不存在会自动新建)res\对账结果.xlsx,用 写入区域 把整个数组写到 "A1:D4"(表头 + 3 条差异),立即保存=是,最后关闭。
  4. 常见坑:区域写成 "A1:D4" 但结果有 5 行 → 报错或写错位。结果行数 = 1(表头)+ 差异条数。
骨架
// 一开始先放表头
Dim 结果 = [["订单号", "差异类型", "系统金额", "银行金额"]]

// 发现差异时,往数组尾部追加一行
结果 = 在数组尾部添加元素(结果, [订单号, "金额不一致", 系统金额, 银行金额])

// 全部比完,写出到新文件(不存在会自动新建)
打开Excel(res\对账结果.xlsx, 可见=True) → objOut
写入区域(objOut, "Sheet1", "A1:D4", 结果, 立即保存=是)
关闭Excel工作簿(objOut)
验收:对账结果.xlsx 里有 4 行:表头 + D003/D004/D007 三条差异,列与含义对应正确。
常见坑:区域写成 "A1:D4" 但结果有 5 行 → 报错或写错位。结果行数 = 1 + 差异条数。

第 5 关 · 发汇总邮件

用到:第 9 课(SMTP 发邮件)、第 3 课(& 拼接)

把"共发现 3 处差异"和每条的简要描述拼成正文,发给自己。

  1. 循环开始前定义正文头:Dim 正文 = "本月对账完成。\n共发现 " & 差异条数 & " 处差异:\n"。
  2. 在发现差异时逐条追加:正文 = 正文 & 订单号 & " - " & 差异类型 & "\n"。
  3. 循环结束后拖入 发送邮件,SMTP 参数照第 9 课填,登录密码用授权码变量,收信邮箱填自己,标题"月度对账报告",正文传 正文,结果存入 成功与否。
  4. 常见报错:登录失败 → 授权码错或未开 SMTP;正文没有换行 → 检查字符串里的 \n 有没有被拼进变量。
骨架
Dim 正文 = "本月对账完成。\n共发现 " & 差异条数 & " 处差异:\n"
// 循环中逐条追加:正文 = 正文 & 订单号 & " - " & 差异类型 & "\n"
发送邮件(SMTP服务器="smtp.qq.com", 服务器端口=465, SSL加密=True,
         邮箱帐号=..., 登录密码=<授权码变量>, 收信邮箱=...,
         邮件标题="月度对账报告", 邮件正文=正文) → 成功与否
验收:邮件正文出现"共发现 3 处差异"并列出三条。
想练更规范的写法:差异条数不用单独计数,用数组长度减 1 也算得出来。

第 6 关 · 进阶(三选一,至少做一个)

A. 用字典替代内层循环(性能优化)
现在每比对一行,都要把另一张表整扫一遍(双层循环)。数据一多就慢。做法:先把银行流水装进一个字典(订单号 → 金额),之后直接用 银行字典[订单号] 一次查到。这就是第 6 课字典的实战价值。 (空字典怎么写、用哪条字典命令,去命令手册搜"字典"确认你的版本;不确定就先做 B 或 C。)
B. 加金额容差
浮点数比较常有微小误差(0.1 + 0.2 不等于 0.3)。改成"两边差额的绝对值小于 0.01 就算一致",避免把一分钱的误差报成差异。
C. 网页三方核对(练第七部分)
用练习场里的 虚拟台账:用 启动新的浏览器 打开它,选一个单元格元素,用 获取元素文本 读出内容,再把网页上的数与你本地 Excel 的某个数比对。这一步专门练元素选取和漏选/错选的修法。
  1. 选做 A:先建空字典,遍历银行流水把"订单号 → 金额"装进去;把内层 For Each 换成一次字典查找,再跑第 2、3 关的验证。期望:结论与原来完全一致,但代码更快、更短。
  2. 选做 B:把金额比较改成"两边差额的绝对值 < 0.01 视为一致"。期望:D003(80 vs 88)仍被报为不一致;如果把某笔改成只差 0.005,则不再报差异。
  3. 选做 C:启动浏览器打开练习页,选一个单元格用 获取元素文本 读出数值。常见报错:"找不到元素" → 元素选错或页面没加载完,重新选取并加等待。
验收:做完 A 或 B,对账结果必须和第 3、4 关完全一致(优化不能改变结论);做完 C,能稳定读到网页上的数值。(该练习页内容每次刷新会变,读到什么都算成功,只要不报"找不到元素"。)

四、两个项目一起看

把项目 1 和项目 2 放在一起,你会看到 RPA 的通用骨架:读数据 → 逻辑处理 → 产出 + 通知。区别只在于"逻辑处理"这一段的形状。

能力项目 1(绩效通知)项目 2(对账)
主结构单层循环 + 生成文件双层循环 + 标志变量
核心难点Word 标记填充、路径拼接变量作用范围、比对逻辑
数据结构二维数组遍历二维数组 + 字典(进阶)
产出一叠 Word一张差异报告 + 邮件
共同点都是"读 Excel → 逻辑处理 → 产出 + 通知",这正是 RPA 的通用骨架

五、卡住时怎么办

  1. 把流程缩小到这个最小例子:只有 2 行系统数据、2 行银行数据,手工算一遍预期输出。
  2. 在关键位置加 输出调试信息,打印 订单号、找到 的值——看它是不是你以为的那样。
  3. 比较金额时若结果诡异,先把两边都 输出调试信息 出来,确认读到的到底是数字还是文字。
  4. 还是不通,把代码 + 实际输出 + 你的预期三样发我。

对账类逻辑的两个致命坑:① 标志变量 找到 没有在外层每轮重置,导致"上一行找到过"污染"这一行";② 金额一边是数字一边是文字,<> 比较永远为真,把每笔都报成不一致。

六、技术点索引

用到的东西复习哪节
二维数组、数组追加、长度第 6 课
双层 For Each、标志变量第 5 课
If / ElseIf、比较运算符第 4 课
读取区域 / 写入区域 / 新建文件Excel 命令速查
SMTP 发邮件、授权码Email 命令速查
元素选取、漏选/错选网页自动化速查

项目复盘

你真正学会的能力

对账 两表交叉核对 双层循环 外层行、内层找 标志变量 记录找到与否 单边账 一方有另一方无 数组追加 往尾部加一行 写入区域 一次性写多格 字段容差 允许微小误差 字典查找 一次命中替代整扫

结课自测

不看上面,凭记忆作答。答错不要紧,解析会告诉你为什么。

精读一手来源

对账里涉及的命令细节以官方文档为准:《来也开发者指南》与命令手册。 建议按需回查——Excel 的读写与新建看"表格/Excel"分类,字典看"数据处理/字典",网页核对看"浏览器"分类;命令名或参数不确定时,一律以命令手册当前版本为准。第 6 关 C 的练习页见练习场 · 虚拟台账。