【日期选择】网页自动化,不一定非要“操作网页”:从一个日期选择器,聊聊直接修改前端状态
评论
收藏

【日期选择】网页自动化,不一定非要“操作网页”:从一个日期选择器,聊聊直接修改前端状态

经验分享
p
python自动化
2026-09-11 13:00·浏览量:369
p
python自动化
影刀中级开发者
发布于 2026-08-31 12:27更新于 2026-09-11 13:00369浏览

当 UI 操作走不通的时候,别忘了:你还可以直接改数据

先回应一个评论区里比较常见的观点:

“传统 RPA 本来就是给小白用的,应该坚持所见即所得。如果开始研究路由、组件、Vue 内部状态,学习成本就高了,也就失去了 RPA 的意义。”

这句话我理解,但我并不完全认同。

传统 RPA 的确应该尽可能让小白能够通过“看得见、点得到”的方式解决问题。

这一点没有问题。

但我觉得这里容易把两个概念混在一起:

“RPA 应该让小白容易上手” ≠ “RPA 只能停留在小白能理解的层次”。


先说说这次为什么又聊到了日期选择器

其实上一篇我已经发过一个腾讯/微信日期选择器的案例。

当时遇到的是一个看起来非常普通的:

请选择发表时间

但实际上它:

  • 在 Shadow DOM 里面

  • input 本身是 readonly

  • 直接修改 input.value 没用

  • 模拟 click 也没有正常弹出

  • 页面本身又是 Vue 组件

最后没有点击日期,也没有模拟鼠标键盘输入,而是顺着网页结构往下找,最终找到了这个日期选择器对应的 Vue 组件实例。

再往里面看,发现日期选择器真正维护的是自己的状态。

最后直接修改组件状态,就让它显示成了目标日期。

这件事本身其实没什么好炫耀的。

因为日期选择器只是一个非常典型的例子。

真正值得讨论的,是我们解决网页自动化问题时,到底应该把目光放在哪一层。


我其实以前就遇到过一个更典型的例子:商品图片排序

这个案例和这次的日期选择器,其实是同一个思路。

当时做商品自动化上架,需要批量上传商品图片。

图片在上传之前其实已经按照顺序命名好了:

1.jpg
2.jpg
3.jpg
4.jpg
5.jpg

我们的预期当然是上传之后:

1
2
3
4
5

但实际做自动化的时候,事情没有这么理想。

因为图片上传往往是异步的。

你让程序依次发起上传,并不代表页面最终一定会严格按照这个顺序把图片插进去。

于是就可能出现:

3
1
5
2
4

这时候需求就来了:

把图片重新调整成 1、2、3、4、5。

如果按照传统 RPA 的思路,第一反应就是:

找到第 3 张
↓
鼠标按住
↓
拖动
↓
移动到第 1 张的位置
↓
松开
↓
再处理下一张

听起来很简单。

但真正做起来就会发现,这其实是一个很麻烦的问题。

你需要考虑:

到底拖到哪里?
↓
什么时候触发排序?
↓
鼠标移动多少距离?
↓
页面有没有滚动?
↓
图片位置有没有变化?
↓
拖动过程中有没有误触发?
↓
不同分辨率是否还能稳定?

最后你会发现一个很有意思的问题:

我明明只是想让图片按照数字顺序排列,为什么最后变成了研究“鼠标应该怎么拖”?

后来我没有继续死磕拖动。

而是换了一个问题:

“这些图片为什么会按照现在这个顺序显示?”

继续往下找,发现页面 window 下面存在对应的图片数据结构。

而图片在页面上的顺序,本质上就是:

这个数据结构里面数组元素的顺序。

于是问题一下就变了。

原来:

鼠标拖动图片

变成:

读取图片数据
↓
按照文件名数字排序
↓
调整数组顺序
↓
让页面按照新的数据重新渲染

最终得到的还是:

1
2
3
4
5

但整个过程中:

没有拖图片。

这个案例给我的启发其实非常大。

因为你如果一直盯着 UI:

“我要怎么把第 3 张拖到第 1 张?”

这个问题可能很难。

但如果往下追:

“第 3 张为什么是第 3 张?”

问题就可能变成:

“哦,原来只是数组里的第 3 个元素。”

UI 操作就这样被转换成了数据操作。


UI 其实只是数据的一种表现形式

一个日期选择器表面上看是:

2026-09-10 12:15

一个商品图片列表表面上看是:

图片1
图片2
图片3
图片4
图片5

但从程序的角度,它们背后都不是凭空出现的。

日期可能来自:

字符串
Date 对象
时间戳
JavaScript 对象
Vue data
React state
组件 model
Store

图片列表可能来自:

数组
对象
组件状态
window 下的数据
Store
接口返回的数据

最终才变成我们看到的 UI。

也就是说:

数据
 ↓
组件
 ↓
UI

我们平时模拟人工操作,其实是在反方向走:

UI
 ↓
点击 / 输入 / 拖动
 ↓
事件
 ↓
组件
 ↓
数据

那么问题来了:

既然最终目的只是让数据变成某个状态,为什么一定要模拟人把整个过程走一遍?

如果我们已经能够找到那个真正控制 UI 的数据对象:

直接修改它,不也是一种自动化吗?


这两个案例,其实是同一种思路

日期选择器:

“怎么点到这个日期?”
        ↓
“日期数据在哪里?”
        ↓
找到 Vue 组件状态
        ↓
直接修改状态

商品图片:

“怎么把图片拖到这个位置?”
        ↓
“图片顺序由什么数据决定?”
        ↓
找到 window 下的数据结构
        ↓
直接调整数组顺序

你会发现,表面上是两个完全不同的问题:

日期选择
图片排序

但底层思路完全一致:

不要只研究 UI 怎么操作,要看看 UI 背后的数据是什么。

这也是我现在做网页自动化时越来越喜欢的一种思路。


很多人做自动化,思维一直停留在“怎么操作”

我们最开始接触 RPA,通常都是:

图像识别
↓
坐标点击
↓
键盘输入

后来开始使用:

元素定位
↓
Web 元素
↓
Windows 元素
↓
XPath
↓
CSS

再往后可能接触:

JavaScript
↓
DOM
↓
Shadow DOM
↓
Vue / React
↓
组件
↓
状态
↓
数据模型
↓
接口

这其实就是一个不断向下深入的过程。

但很多时候,我们遇到问题之后,还是习惯在当前这一层不断死磕。

比如:

“这个日期框怎么点?”

然后开始研究:

怎么定位?
怎么点击?
怎么模拟鼠标?
怎么模拟键盘?
怎么让它弹出来?

又比如:

“图片怎么拖过去?”

然后开始研究:

鼠标坐标
拖动距离
拖动速度
目标位置
滚动

如果一直走这条路,问题就会越来越复杂。

但换一个思路:

我为什么一定要操作这个 UI?

这个问题一变,思路就完全不一样了。


这并不是说“以后 RPA 都别点了”

恰恰相反。

如果一个按钮:

定位
↓
点击
↓
完成

那当然直接点击。

如果一个输入框:

定位
↓
输入
↓
提交

那当然直接输入。

能简单解决的问题,就简单解决。

我并不是鼓励大家为了炫技,做一个简单的事情非要研究 Vue、React、组件源码。

真正有价值的是:

当你用常规方法解决不了的时候,你有没有意识到“解决问题的层级”还可以继续往下走。


这也是我不太认同“这样就失去 RPA 意义”的原因

如果按照:

“RPA 就应该面向小白,所以不要研究底层。”

这个逻辑继续推下去,其实会非常有意思。

那为什么影刀还要提供:

运行 JS 代码

为什么还要允许:

捕获元素
↓
操作 Web 元素
↓
写 XPath
↓
写表达式
↓
运行 JS
↓
调用接口
↓
处理数据

因为现实中的网页根本不可能永远保持:

一个按钮
↓
点一下
↓
完成

总会碰到:

元素抓不到
↓
Shadow DOM
↓
readonly
↓
组件封装
↓
复杂事件
↓
页面状态不同步

这时候如果只会:

“点一下”

那问题确实到头了。

但如果你知道:

网页还有更深的一层。

问题就可能从:

“怎么点?”

变成:

“它的数据在哪里?”

再进一步:

“这个数据是怎么驱动 UI 的?”

甚至:

“我能不能直接控制这个状态?”

当然,直接修改状态也不是万能的

这里也必须把话说完整。

评论里有一点我不反对:

“你看起来可能只是一个日期框,但你点击的时候,它会触发其他的数据响应。”

完全正确。

一个日期选择器可能不仅仅是在修改日期。

点击之后可能还有:

修改日期
↓
修改时间
↓
触发 watcher
↓
重新计算状态
↓
更新其他字段
↓
执行校验
↓
生成提交参数

如果你只是粗暴修改一个变量:

date = "2026-09-10"

但没有触发组件需要的其他逻辑,就可能出现:

页面看起来改了,真正提交的时候却没生效。

所以:

直接修改状态不是传统 RPA 的替代品。

它只是多了一层选择。

这也是为什么这次日期选择器最后并不是简单地:

input.value = "2026-09-10 12:15"

而是需要找到真正的 Vue 组件状态,并按照这个组件本身的数据逻辑去修改。

你越往下面走,越不能只靠“赋值”两个字解决问题。

你需要理解这个页面的数据模型。


接口也是一样

有人会说:

“有技术的人直接抓接口发请求不就完了?”

有时候确实如此。

但你首先得知道:

接口在哪里?
↓
参数是什么?
↓
请求怎么构造?
↓
鉴权怎么处理?
↓
哪些字段必须带?

而有些时候,网页已经把你需要的数据放在组件状态里面了。

这时候:

读取组件状态
↓
修改组件状态

反而比:

抓包
↓
分析接口
↓
分析参数
↓
处理鉴权
↓
重新构造请求

简单。

所以不存在一种方法永远最好。

真正重要的是,你知道自己现在处于哪一层,以及还有哪些层可以继续往下走。


我觉得自动化真正应该培养的是这种“换层思维”

以后再遇到一个问题:

这个控件点不了
这个输入框输不进去
这个日期选择器很难操作
这个下拉框怎么都定位不到
这个图片怎么拖都不稳定

不要马上把问题定义成:

“这个元素操作不了。”

可以换一个定义:

“我要让这个控件最终处于某个状态。”

然后开始思考:

正常操作
↓
DOM
↓
JavaScript
↓
组件
↓
状态
↓
数据模型
↓
接口

当然,并不是每个问题都要一路走到底。

能用第一层解决,就别折腾第二层。

但如果第一层解决不了:

你至少应该知道第二层存在。


这其实也是技术成长的一部分

刚开始学自动化:

拖模块
↓
点击
↓
输入

很正常。

后来:

元素捕获
↓
XPath
↓
CSS

再后来:

JavaScript
↓
DOM
↓
Shadow DOM

再往后:

Vue
↓
React
↓
组件
↓
状态
↓
数据模型
↓
接口

这不是:

“越来越不像 RPA 了。”

而是:

“越来越理解自己正在自动化的东西。”

RPA 对小白友好,这是好事。

但:

“小白能用”不应该变成“使用者永远只能停留在小白层次”。


所以我真正想表达的,其实不是“日期选择器应该怎么做”

日期选择器只是这次案例的载体。

商品图片排序也只是另一个载体。

真正值得留下的是一种解决问题的思路。

当你发现:

元素抓不到

不要只想:

“换个定位方法。”

当你发现:

input 是 readonly

不要只想:

“怎么强行输入?”

当你发现:

点击也没有反应

不要只想:

“怎么模拟得更像人?”

当你发现:

图片拖动很不稳定

也不要只想:

“怎么把鼠标拖得更准?”

你还可以继续问:

“这个 UI 背后的数据是什么?”

然后:

“这个数据在哪里?”

再然后:

“我能不能直接修改这个数据?”

这时候你解决的已经不再只是一个日期选择器,也不只是一个图片排序问题。

而是一类问题:

当 UI 层解决不了的时候,能不能跳过 UI,直接控制驱动 UI 的数据。


最后

我一直觉得:

技术不是为了让我们永远像一个小白一样操作软件。

技术的成长,本来就是不断从:

会操作

走向:

理解为什么能操作

再走向:

知道不操作也能解决

所以我并不认为:

“研究组件、研究 Vue、研究状态,就不属于 RPA 了。”

恰恰相反。

我觉得这只是:

RPA 从“模拟人的操作”,逐渐走向“理解并控制软件”。

以后遇到难题的时候,除了问:

“这个东西怎么点?”

不妨再问一句:

“如果我不点它,我能不能直接改变它的数据?”

有时候,真正高效的自动化,不是把人的操作模拟得越来越像。

而是:

发现这一步,其实根本不需要操作。

收藏4
全部评论(1)
最新
发布评论
评论