rea实战:用脚本自动化浏览器重复操作,打造高效流程
首先要跟看到这个标题的朋友解释一下我平时写自动化脚本经常要给临时项目起个随手能打的代号rea就是从里面蹦出来的三个字母。它的全称被我私下写成 Repeat Everything Automatically——听起来有点中二实际上做的事情特别接地气把那些每天都要在浏览器里重复点的按钮、重复填的表单、重复下载的报表交给一段脚本去跑。这个项目解决的痛点很明确你以为点几下鼠标不算累但当这种“点几下”每天要出现十几次甚至几十次而且必须保持顺序不错、速度不慢的时候人就会开始出错、烦躁、摸鱼。而脚本不会。它适合谁适合所有工作里被网页后台折磨的人比如运营、财务、人事、客服、数据分析岗也适合想用浏览器自动化做点效率工具的开发者。读完这篇文章你不需要完全掌握编程只要照着抄就能跑通第一个属于你自己的自动操作流程。1. 为什么我会把一个自动化工具叫 rea1.1 一个反复出现的真实痛点我第一次萌生写 rea 的念头是因为某一个普通周四下午。当时我在处理一个每周都要重复的任务登录某个后台 → 进列表页 → 设置筛选条件 → 点查询 → 勾选所有结果 → 点批量导出 → 等文件生成 → 下载 → 重命名。整套操作大概需要八到十分钟如果中途网络卡一下或者某一步点早了就得重来。连续做了两个月之后我发现自己看到那个列表页都想绕路走。更让人烦躁的是这种流程一旦涉及“必须按顺序执行”人工操作就天然不可靠。你可能在等待下载时切到别的窗口回来忘了刚才点没点也可能因为多选了一个不该选的对象导致整份报表需要重新生成。这类问题不是靠“细心”能解决的因为人的注意力本身就是稀缺资源。所以我把自己的需求拆了一下第一步把固定操作录下来第二步把重复流程参数化比如日期、关键词、筛选条件第三步让脚本按步骤执行并把每一步的结果记录下来。这就是 rea 最初的雏形。1.2 为什么不自接用现成的自动化平台有人可能会问市面上不是有很多 RPA机器人流程自动化工具吗下载一个、拖拽流程、运行不也能做到类似效果确实可以但我在实际对比之后还是决定自建。原因有三点。一是成本很多 RPA 工具按控制端数量或运行次数收费个人或小团队用起来不划算而自己用开源浏览器自动化库写脚本跑多少遍都不额外收费。二是灵活度RPA 工具的可视化编排对于简单流程很好用但一旦要写条件分支、循环嵌套、错误重试反而要绕很多弯不如代码直接。三是调试体验脚本出问题的时候代码方式可以打日志、截图、查看调用栈而可视化平台往往只给你一个“执行失败”的提示排查起来非常抓狂。当然我并不是说自建一定适合所有人。完全没有代码基础的话直接学 HTML 结构、选择器、等待条件门槛确实比拖拽高。但如果你恰好懂一点编程或者愿意花两天时间补个基础那 t自建脚本得到的控制力是 RPA 工具很难给的。另外还有一个很实际的理由很多后台系统的界面长年不变但又有大量重复操作。这种场景用代码写一次几年都能一直复用边际成本几乎为零。1.3 rea 的三大模块录制、回放、校验我最早想做成“录制”工具后来发现纯录制并不可靠因为真实页面存在各种变化。最后把 rea 拆成了三个功能模块回放核心负责按顺序执行每一条操作指令打开页面、输入内容、点击按钮、等待结果。配置驱动操作过程不硬编码在脚本里而是抽成一个步骤清单用 JSON 或简单数组描述方便修改和扩展。结果校验每一步执行后都要确认页面真的发生了变化比如某个元素出现、某段文本更新、下载任务完成而不是“点击成功”就算完事。这三个模块听起来简单却是处理复杂网页的关键。录制只解决“第一步怎么开始”真正让脚本能长期稳定运行靠的是校验。没有校验的自动化脚本就像闭着眼睛走路运气好能到终点运气不好直接撞墙。2. 核心技术点拆解让脚本像真人一样“找得到、等得起、信得过”2.1 元素定位三重武器和一条优先级铁律一个网页自动化脚本运行失败十有八九是元素定位出了问题。页面上那个按钮明明在那里但脚本就是找不到或者找到了多个。我常用的定位方式有三种。第一种是 CSS 选择器比如input[namekeyword]、.btn-primary胜在简洁适合有明显特征的元素。第二种是可见文本比如button:has-text(查询)适合按钮上的文字会变化、但核心功能不变的场景。第三种是 XPath比如//div[classresult and contains(text(),明细)]适合页面结构复杂、没有额外标记的情况。这三者不是平等关系我总结出一条优先级铁律能加>[ { id: open_page, type: goto, url: https://example.com/admin/list, waitUntil: domcontentloaded }, { id: fill_keyword, type: fill, selector: input[namekeyword], value: {{keyword}} }, { id: click_search, type: click, selector: button:has-text(查询) }, { id: wait_result, type: waitFor, selector: .result-item, timeout: 10000 } ]这个设计最大的好处是用户不需要了解代码细节也能通过改配置来调整流程。{{keyword}}是一种占位符运行时从外部参数或环境变量中取值。这样一来同样的流程今天跑关键词 A明天跑关键词 B脚本主体一行不用改。做一个好的配置驱动结构关注点不是怎么写配置文件而是怎么把“易变的部分”和“稳定的部分”分开。易变的部分包括页面地址、搜索关键词、导出文件格式、日期范围。稳定的部分包括固定表单结构、操作顺序、校验条件。把它们分开脚本才能长期省心。3. 从零跑通第一个 rea 脚本3.1 准备环境和安装依赖我一般用 Node.js 生态来写这类脚本因为浏览器自动化库对它支持最好安装起来也快。如果你对 Python 更熟也可以用对应版本思路完全一样。安装步骤同样简单开一个终端依次执行npm init -y npm install playwright npx playwright install chromium第一条命令初始化项目第二条安装浏览器自动化库第三条下载一个可独立运行的浏览器内核。很多人会漏掉第三条导致运行时报“找不到浏览器”所以这里先打个预防针。顺便说一句安装过程可能需要一点磁盘空间浏览器内核大概几百 MB。如果你在公司内网网络受限可以找运维开下载白名单。这个环节最不起眼却是新手第一个容易卡住的地方。3.2 最小脚本登录、查询、导出跑通一个最小的 rea 脚本我拿“登录后查询并导出报表”来演示。别看流程简单它已经覆盖了日常自动化的高频操作填表、点击、等待、下载。先看代码const { chromium } require(playwright); (async () { const browser await chromium.launch({ headless: false }); const page await browser.newPage(); await page.goto(https://example.com/login, { waitUntil: domcontentloaded }); await page.fill(#username, process.env.REA_USER || demo); await page.fill(#password, process.env.REA_PASS || changeme); await page.click(button[typesubmit]); await page.waitForURL(**/dashboard); await page.fill(input[namekeyword], 2025-01); await page.click(button:has-text(查询)); await page.waitForSelector(.result-item); const downloadPromise page.waitForEvent(download); await page.click(a.btn-export); const download await downloadPromise; await download.saveAs(./reports/report- new Date().toISOString().slice(0, 10) .xlsx); await browser.close(); })();这段代码的逻辑很直白打开登录页、填账号密码、点登录、等跳转、填查询条件、点查询、等结果出现、触发下载、保存文件。里面几乎每一行都有对应目的没有冗余。你可能注意到我用了process.env.REA_USER这是从环境变量读取账号信息避免把敏感内容写死在代码里。如果你只是本地测试也可以直接写变量值但上传代码库时要小心。3.3 常用加固登录态复用、失败重试、截图日志基础脚本能跑通之后你需要考虑的不是“怎么跑一次”而是“怎么跑一千次”。我强烈建议优先做三件事。第一登录态复用。很多后台系统登录一次后会话能维持一段时间。每次脚本启动都重新走一遍登录流程既慢又容易触发安全策略。更好的做法是第一次登录成功后把会话状态保存下来后续运行直接加载// 保存会话 await context.storageState({ path: auth.json }); // 下次直接使用 const context await browser.newContext({ storageState: auth.json }); const page await context.newPage();这里有一点要注意不同浏览器的 storageState 格式基本是标准 JSON可以跨脚本复用。如果遇到登录状态过期顶多重新登录一次再刷新保存文件便好。第二失败重试。网络抖动、后台偶发报错都会导致脚本中断。我通常给每个关键步骤包一个重试包装器失败后等两秒最多重试三次。重试时最好换一种等待策略而不是无脑重复同样操作。第三截图和日志。这是很多新手最容易忽略的。在每一步关键动作之后截图存盘甚至直接用 trace 录制功能事后排查的效率高得多。脚本运行完自动生成一个带时间戳的目录里面放着截图、日志、下载记录比任何“到底哪里错了”的脑内复盘都管用。3.4 处理 iframe 和动态弹窗这两个糟心问题实际项目中我碰到最多的两个“非标准场景”是 iframe 和动态弹窗。iframe 可以理解成页面里嵌了一个独立的子页面。直接在外层页面定位 iframe 里的元素十有八九找不到因为脚本默认只在主文档里搜索。处理方式是先切换到对应框架再在里面操作const frame page.frame({ url: /\/admin\/approve\// }); await frame.locator(input[nameapproveComment]).fill(已通过); await frame.locator(button:has-text(确认)).click();动态弹窗则是另一个常见坑。有些弹窗不是一开始就在页面里的而是等几秒后才出现直接点击大概率会落空。我的建议是弹窗类的点击前先等待它出现并且优先使用“可见状态”而非“存在状态”因为有时候元素在 DOM 里存在但被 CSS 隐藏着点了和没点一样。这些细节看上去琐碎却是决定脚本“是玩具还是工具”的分水岭。能处理这些真实页面问题等于真正掌握了 rea 的精髓。4. 常见问题与排查技巧4.1 运行时报错的排查速查表我把这段时间踩过的坑汇总成一张速查表基本覆盖了新手最常见的上报错类型。每次脚本异常时先别急着改代码对应下面的情况逐条排查。错误表现最常见原因处理方向找不到元素页面还在加载 / 选择器变了 / 层级不对加显式等待换>