前言:什么是 RPA?
可以先想象一下,你身边有个“超级勤快、从不抱怨、不会摸鱼”的小同事:
每天帮你打开各种系统、点各种按钮、抄各种数据,干的都是最枯燥的流程性工作,你只负责告诉 TA 规则,然后坐在一旁看着进度条走就行了。
这就是 RPA(Robotic Process Automation,机器人流程自动化)要做的事——只不过这个“小同事”是软件机器人:
- 从本质上看:RPA 是一套用程序模拟人类操作各类系统(网页、客户端、Office 等)的技术;
- 从使用方式看:它像搭“乐高积木”一样,把一个个固定、可复用的操作步骤拼成自动化流程;
- 从价值上看:RPA 不会替你思考业务规则,但可以替你做所有“又机械又耗时间”的那部分。
和传统“改系统、写接口”的方式比,RPA 有三个很讨喜的特点:
- 够轻:很多场景下不用大动干戈改系统,只要机器人会“点鼠标、敲键盘”就能上;
- 够快:流程改动时,经常只是改脚本和配置,不需要再走一遍漫长的需求评审和上线流程;
- 够接地气:做的就是一线同事每天在做的事,只是把“人肉流水线”换成了“机器人流水线”。
在税务、财务、人力、运营这些“规则多、节奏快、表格多”的领域,大量流程天然适合 RPA——
先把手从鼠标上解放出来,再慢慢把脑子从流程里解放出来。
一、背景:为什么要让“机器人”帮我们登录?
先从一个大家最熟的动作说起:登录。
在一个典型的税务 / 财务业务场景里,一线人员每天可能要重复很多次类似的动作:
- 打开客户端或浏览器;
- 登录某个业务系统;
- 等待系统加载完各种首页、公告、提示框;
- 根据当前账号,确认绑定关系、权限信息,再决定能不能继续后续操作。
这些动作有什么特点?
- 路径固定:每次点的地方都差不多;
- 步骤稳定:顺序清晰,很少需要“灵机一动”;
- 频率极高:一天要来回好几轮,甚至几百次调用;
- 但又不能省略:不登录、不检查,就没法往后走。
这对人来说是“消耗心情”的重复劳动,对机器人来说却是“天然主场”。
所以本文就聚焦在 RPA 流程中的一个关键环节:“登录 + 前置校验”。
我们会基于一个真实项目抽象出的架构,看看如何用前端页面 + 本地客户端函数 + 后端接口,让“登录”这件事从此变成机器人的一键小任务。
二、整体架构:从“浏览器里的脚本”到“桌面上的机器人”
结合整个前端项目和桌面端 RPA 服务,可以把这套方案抽成一个很好理解的“四层三明治”:
- 第 1 层:浏览器端脚本层(Pages & Scripts)
负责和网页打交道,分两类:- 页面脚本:负责渲染结果页、登录页等(比如登录结果展示页),像是“舞台布景”;
- 功能脚本:负责自动登录、列表查询、任务跳转等,像是“在舞台上表演的演员”;
- 第 2 层:客户端桥接层(Native Bridge)
负责和本地客户端说话,通过类似NativeBridge/NativeBridgeSync的接口:- 读本地配置、账号信息;
- 写日志文件;
- 把结果回传给 RPA Worker;
- 第 3 层:后端服务层(HTTP API)
负责所有“问后端要答案”的动作,通过一个统一的 HTTP 封装:- 获取 RSA 公钥;
- 获取登录 UUID;
- 执行登录;
- 查询默认身份、任务列表等;
- 第 4 层:桌面 Worker 调度层(RpaWorker)
负责“管机器人上班打卡”的那个人:- 通过类似
autoService的配置,管理有哪些任务、多久跑一次; - 定时打开对应的 RPA 页面(登录、同步、审核、验证……);
- 汇总每次执行结果,并决定下一步怎么跑。
- 通过类似
如果把这四层串起来,一次完整的端到端 RPA 流程大概长这样:
- 桌面 Worker 按计划发起任务:
看配置文件,决定现在该跑哪个任务(比如“xx同步”、“xx更新”等),然后打开对应的 HTML 页面; - 页面加载 & 登录脚本注入:
页面加载完后,由“注入脚本”清理掉不需要的脚本节点,再动态插入真正负责业务登录的脚本; - 脚本桥接客户端 + 调后端接口:
- 从本地客户端拿到登录信息、账号标识、服务端baseURL;
- 调用后端一系列接口(取公钥、取 UUID、执行登录、查默认身份、查任务列表等),直到登录彻底打通;
- 在浏览器里模拟人操作:
功能脚本通过 DOM 查询、iframe访问、第三方 UI 组件等,执行“点击按钮、切 Tab、输入搜索条件、打开任务详情”等动作; - 结果打包回传,等待下一轮调度:
本轮场景执行完毕后,把“成功 / 失败 + 消息 + 关键参数”打包,通过本地桥接回传给 RPA Worker,日志里也记上一笔,等下一个周期再来一轮。
后面几个小节会分别用“登录入口页”和“任务调度配置”这两个切片,拆给你看。
三、核心页面结构示例
登录场景的 RPA 入口页本质上是一个简单的 HTML 页面,分为三个展示区域:
- 获取账号绑定信息的结果;
- 系统登录结果;
- RPA 脚本注册结果。
下面是一个脱敏后的结构示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>自动登录示例(RPA)</title>
</head>
<body>
<div class="result">
<div class="binding-info">
<h2>获取账号绑定信息</h2>
<div class="code">
<span>成功状态:</span>
<span id="binding-code"></span>
</div>
<div class="msg">
<span>失败消息:</span>
<span id="binding-msg"></span>
</div>
</div>
<div class="login">
<h2>系统登录结果</h2>
<div class="code">
<span>成功状态:</span>
<span id="login-code"></span>
</div>
<div class="msg">
<span>失败消息:</span>
<span id="login-msg"></span>
</div>
</div>
<div class="rpa-script">
<h2>RPA 脚本注册</h2>
<div class="code">
<span>成功状态:</span>
<span id="rpa-code"></span>
</div>
<div class="msg">
<span>失败消息:</span>
<span id="rpa-msg"></span>
</div>
</div>
</div>
<script type="text/javascript" src="./rpa-login.js"></script>
</body>
</html>
页面本身非常“傻”,主要由脚本来驱动逻辑,DOM 只承担结果展示的职责。
四、核心脚本逻辑:从页面加载到结果回传
你可以把 脚本 想象成一个“自启动的小机器人”,页面刚加载完,它就开始自言自语地说道:
- “先记个日志,证明我真的开始干活啦”;
- “去问问本地:我是谁,我在哪呢”;
- “再去问问后端:我这个账号到底合不合规呀”;
- “最后把结果打包丢回宿主系统,本次任务结束咯”。
1. 脚本整体结构
document.addEventListener('DOMContentLoaded', function () {
try {
// 1. 记录开始日志(通过本地客户端桥接)
window.NativeBridge('LogInfo', JSON.stringify({
fileName: 'rpa-login.log',
msg: '开始执行自动登录流程'
}), '');
// 2. 获取当前账号
var accountId = window.NativeBridgeSync('GetLocalAccount');
if (!accountId) {
handleScene('fail', '本地账号为空,无法继续处理', null);
return;
}
// 3. 获取服务端基础地址
var serviceBaseUrl = window.NativeBridgeSync('GetServiceBaseURL');
if (!serviceBaseUrl) {
handleScene('fail', '服务端基础地址为空,无法继续处理', null);
return;
}
// 4. 向后端请求账号绑定信息
fetch(serviceBaseUrl + '/api/binding/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ accountId: accountId })
})
.then(function (response) {
return response.text();
})
.then(function (resText) {
if (!resText) {
handleScene('fail', '接口返回为空', null);
return;
}
var res = JSON.parse(resText);
if (res.code !== 'SUCCESS') {
handleScene('fail', '查询绑定信息接口调用失败', null);
return;
}
if (!res.data) {
handleScene('fail', '查询绑定信息返回数据为空', null);
return;
}
// 假设后端在 data 中返回认证结果码
if (res.data.authResultCode === '00000') {
// 将关键数据编码后通过参数回传给宿主 RPA
var encodedParams = window.btoa(
encodeURIComponent(JSON.stringify(res.data))
);
handleScene('success', '获取绑定信息并校验通过', encodedParams);
} else {
handleScene(
'fail',
'认证未通过:' + res.data.authResultMessage + '(' + res.data.authResultCode + ')',
null
);
}
})
.catch(function (error) {
handleScene('fail', '调用接口异常:' + error.toString(), null);
});
} catch (e) {
console.error(e);
handleScene('fail', '自动登录流程执行异常', null);
}
/**
* 统一场景处理函数
* @param {'success' | 'fail'} code
* @param {string | null} message
* @param {string | null} parameters 已编码的参数
*/
function handleScene(code, message, parameters) {
// 1. 页面展示
document.getElementById('binding-code').innerText = code;
document.getElementById('binding-msg').innerText = message || '';
// 2. 本地日志
window.NativeBridge('LogInfo', JSON.stringify({
fileName: 'rpa-login.log',
msg: message
}), '');
// 3. 将结果结构化回传给宿主 RPA 框架
window.NativeBridge('InitParametersResult', JSON.stringify({
code: code,
msg: message,
parameters: parameters
}), '');
}
/**
* 用于展示后续步骤(如真正的登录、脚本注册)的结果
* @param {'login' | 'rpa'} type
* @param {'success' | 'fail'} code
* @param {string} message
*/
window.showResult = function (type, code, message) {
if (type === 'login') {
document.getElementById('login-code').innerText = code;
document.getElementById('login-msg').innerText = message;
}
if (type === 'rpa') {
document.getElementById('rpa-code').innerText = code;
document.getElementById('rpa-msg').innerText = message;
}
};
});
五、设计要点拆解
1. 本地桥接:让前端“说得懂”客户端
在很多桌面型场景中,前端页面并不是跑在“浏览器地址栏”里,而是嵌在某种 WebView / CEF 容器中。
此时,页面就像是住进了客户端的一间“房间”,需要通过事先约定好的“对讲机”(比如 window.NativeBridge / window.NativeBridgeSync)跟外界交流:
- 写入本地日志文件,便于现场排查;
- 获取当前操作员或账号 ID;
- 读取本地配置(比如服务端地址、代理配置等)。
这样一来,RPA 逻辑就可以复用客户端现有能力,而无需在脚本中硬编码环境信息啦。
2. 接口调用:让业务判断尽量留在后端
登录这件事,一旦牵涉到风控、权限、认证结果,就需要跟后端打很多交道。
在这套实现里,前端脚本的姿态非常简单粗暴,只做这几件事:
- 组织好请求参数(如账号 ID);
- 调用后端统一入口(
/api/binding/query一类); - 解析结果并根据成功 / 失败走不同分支。
业务规则尽量放在后端,例如:
- 账号与业务系统之间的绑定关系;
- 是否已通过某种实名认证;
- 返回给前端的业务结果码和中文提示。
前端只负责“选择哪条路走”,而不负责“规则本身是什么”。
这样,规则变了动后端,流程变了动前端,分工足够清晰。
3. 统一场景处理:handleScene 的价值
handleScene 可以理解为一个“统一出口的值班前台”,所有情况最后都由它来接待:
- 更新页面展示,方便人工观察;
- 记录本地日志,便于运维与排查;
- 通过统一结构把结果回传给宿主 RPA 引擎。
这样,无论在哪个环节翻车(本地信息为空、接口失败、业务未通过、脚本异常),
最终都会“汇聚”到这一个出口,而不是在代码各个角落散落一地 的alert、console.log 和“随手一抛的错误”。
4. 结果透传:为后续 RPA 步骤提供“燃料”
当认证通过时,示例中会把 res.data 编码后放到 parameters 字段中回传。
在实际项目中,你可以根据需要:
- 只回传最关键的几个字段;
- 或者回传整个数据结构,在后续流程中进行二次拆解和使用。
关键在于:RPA 的每个子步骤都要有清晰的输入和输出。
只有这样,才能像搭积木一样,把多个小机器人串起来,变成一条真正可靠的自动化生产线。
六、工程化实践:不仅是一段“脚本”,而是一个“项目”
在工程层面,这类 RPA 脚本完全可以、也应该享受现代前端工程体系的加成,而不是停留在“桌面上一堆 .js 文件”的野生时代:
- 使用构建工具(如 webpack)进行多入口打包;
- 使用 Babel 处理兼容性问题;
- 使用 ESLint 等工具统一代码风格;
- 使用 NPM 脚本统一构建命令,例如:
npm run build
这样做的收益是:
- 可维护:接口变更、字段调整时,能快速定位并修改;
- 可扩展:在现有框架上增加新的 RPA 场景页面,不断扩展自动化版图;
- 可协作:多开发者可以在统一规范下并行推进,而不是各写各的“个人脚本”。
七、任务调度与多场景编排:从“一个脚本”到“一个机器人工人”
在真实桌面环境里,几乎不会只有一个“登录机器人”。
更多时候,你需要的是一整套“机器人工人队伍”(可以理解为一个 RpaWorker 集群),在不同时间点,自动去执行不同的业务脚本。
一个很实用的做法,是用一个独立的配置文件(例如某个 autoService.json)来描述所有可调度的任务。
对于每个任务,你只需要关心几件事:
- 任务编码:
code,用于唯一标识某个自动化任务; - 任务名称:
name,用于给业务人员看的中文描述; - 命令编号:
commandId,通常与客户端或调度器内部的指令一一对应; - 页面路径:
URLPath,指向对应的 RPA 页面,例如某个同步、更新或交互场景; - 启动延迟:
DelayTime,单位秒,表示客户端启动后多久开始首次执行该任务; - 默认间隔:
DefaultInterval,单位秒,表示两次自动执行之间的时间间隔。
一个经过脱敏的任务配置示例如下:
[
{
"code": "T01",
"name": "同步某类业务",
"commandId": "1",
"URLPath": "syncTask.html?type=001",
"DelayTime": "1800",
"DefaultInterval": "7200"
},
{
"code": "T02",
"name": "更新某类业务",
"commandId": "2",
"URLPath": "updateTask.html?type=002",
"DelayTime": "1800",
"DefaultInterval": "7200"
},
{
"code": "T03",
"name": "创建xx任务",
"commandId": "3",
"URLPath": "create.html",
"DelayTime": "1800",
"DefaultInterval": "7200"
}
]
在实际运行时,桌面端会启动一个常驻的“RPA 工人”进程,像一个守在机房里的调度小哥,小哥会执行这样的任务:
- 读取上述配置,按
DelayTime和DefaultInterval定时打开对应的 RPA 页面; - 每个页面内部用类似前文的方式(本地桥接 + 后端接口)完成一次完整的自动化流程;
- 执行完毕后,将结果回传给宿主并写入日志,等待下一次调度。
这种“配置驱动 + 多场景页面 + 统一脚本框架”的方式,有几个非常接地气的好处:
- 扩展新场景很简单:大部分时候只是新增一个页面 + 一条配置;
- 部署与灰度方便:可以在不同环境/机构下,通过不同的配置组合启用不同的任务;
- 业务可见性更强:业务人员可以通过任务列表直观看到当前有哪些机器人任务在运行。
从工程视角看,RPA 页面 + Worker 调度 + autoService 配置 组合起来,
就不再是“某个开发偷偷写的小脚本”,而是一套真正可运营、可演进的机器人体系!
八、结语:从一个登录页面开始的 RPA 之路
一个看似不起眼的“自动登录 + 绑定校验”页面,
其实已经悄悄具备了一个成熟 RPA 体系所需的很多关键要素:
- 与本地客户端的能力集成;
- 与后端业务的接口协同;
- 统一的结果处理与日志体系;
- 工程化的构建与部署方式。
从这样一个小小的登录场景做起,你可以逐步:
- 把更多重复流程交给机器人;
- 把更多时间还给真正需要人思考的工作;
- 让自己从“流程执行者”变成“流程指挥者”。
如果你正准备在税务 / 财务 / 政务等领域实践 RPA,
希望我深夜码的文章能成为你搭建“第一支机器人小队”的起点。