目录
最近写的RPA脚本经常遇到登录时,需要进行滑块验证的情况,分享下如何处理这种情况,以某个网站为例:
一、实现思路
滑块验证要做的有两点:1、把滑块移动到底;2、控制滑动速度,模拟手动滑动的情况。
1、把滑块移动到底
为了实现第一点,我们首先需要获取滑块。先打开控制台,获取滑块元素的id及相关信息。
这里我们可以看到,滑块本身的id为 nc_1_n1z,利用document?.querySelector("#nc_1_n1z")就能获取到滑块的DOM。另外,还需要获取滑块组件的宽度,直接选中元素看他的宽度就可以。这里的滑块组件宽度为300px。
接下来,我们可以调用getBoundingClientRect()方法来从代码层面获取滑块的宽高。
并用相应变量接收宽高的值。
getBoundingClientRect()
是一个 JavaScript 中的 DOM API,用于获取元素相对于浏览器视口(viewport)的位置和大小信息。它返回一个DOMRect
对象,这个对象包含了元素的left
(元素左边界距离视口左边界的距离)、top
(元素上边界距离视口上边界的距离)、right
(元素右边界距离视口左边界的距离)、bottom
(元素下边界距离视口上边界的距离)、width
(元素的宽度)和height
(元素的高度)等属性。
现在我们已经有了滑块DOM及滑块的宽高值。只需要定义鼠标按下mousedown、鼠标移动mousemove、鼠标松开mouseup事件并调用即可。
2、控制滑动速度,模拟手动滑动的情况
手动滑动滑块通常不是匀速,一般开始慢,中间快,结尾慢。因此,我们利用0.5x^3来实现模拟前半段运动,利用0.5((x - 2)^3 + 2)来模拟后半段运动。示例:
javascript
function easeInOutCubic(t) {
t *= 2;
if (t < 1) return 0.5 * t * t * t;
t -= 2;
return 0.5 * (t * t * t + 2);
}
除了模拟运动过程,还要指定运动时间,给个合理的时间来完成整个滑动过程。
二、实现代码示例
javascript
/*
* 验证滑块滑动
*/
function sliderMoveByAnimation(targetElement, distance = 0, duration = 400) {
console.log(targetElement)
const rect = targetElement.getBoundingClientRect();
const startMouseX = rect.left + rect.width / 2;
const startMouseY = rect.top + rect.height / 2;
function easeInOutCubic(t) {
t *= 2;
if (t < 1) return 0.5 * t * t * t;
t -= 2;
return 0.5 * (t * t * t + 2);
}
const mouseDownEvent = new MouseEvent("mousedown", { bubbles: true, clientX: startMouseX, clientY: startMouseY });
targetElement.dispatchEvent(mouseDownEvent);
const startTime = performance.now();
function animate() {
const currentTime = performance.now();
const elapsed = currentTime - startTime;
if (elapsed < duration) {
const progress = elapsed / duration;
const newPosition = distance * easeInOutCubic(progress);
console.log(progress)
const mouseMoveEvent = new MouseEvent("mousemove", { bubbles: true, clientX: startMouseX + newPosition, clientY: startMouseY });
targetElement.dispatchEvent(mouseMoveEvent);
requestAnimationFrame(animate);
} else {
const mouseUpEvent = new MouseEvent("mouseup", { bubbles: true, clientX: startMouseX + distance, clientY: startMouseY });
targetElement.dispatchEvent(mouseUpEvent);
}
}
animate();
};
三、示例函数分析
1、函数总体功能
- 这里定义了一个名为
sliderMoveByAnimation
的函数,用于通过动画方式移动滑块(slider)。它模拟了鼠标按下、移动和抬起的操作来实现滑块的移动。
2、函数定义和参数
- 函数定义如下:
javascript
function sliderMoveByAnimation(targetElement, distance = 0, duration = 400) {
// 函数体
}
targetElement
:要移动的目标元素。distance
:滑块要移动的距离,默认为 0。duration
:动画的持续时间,默认为 400 毫秒。
3、函数体内部结构
- 获取目标元素的位置信息
javascript
const rect = targetElement.getBoundingClientRect();
const startMouseX = rect.left + rect.width / 2;
const startMouseY = rect.top + rect.height / 2;
首先,通过getBoundingClientRect
方法获取目标元素的边界矩形信息。
然后,计算出鼠标起始位置(startMouseX
和startMouseY
),这是通过将元素的中心位置作为鼠标的起始位置来计算的
- 定义缓动函数
javascript
function easeInOutCubic(t) {
t *= 2;
if (t < 1) return 0.5 * t * t * t;
t -= 2;
return 0.5 * (t * t * t + 2);
}
这个函数easeInOutCubic
是一个缓动函数,用于计算动画的进度。它根据传入的时间参数t
(0 到 1 之间)计算出一个经过缓动处理的值,使得动画在开始和结束时速度较慢,中间速度较快。利用0.5x^3来实现模拟前半段运动,利用0.5((x - 2)^3 + 2)来模拟后半段运动。
- 模拟鼠标按下事件
javascript
const mouseDownEvent = new MouseEvent("mousedown", { bubbles: true, clientX: startMouseX, clientY: startMouseY });
targetElement.dispatchEvent(mouseDownEvent);
创建一个mousedown
鼠标按下事件,并将其触发在目标元素上,模拟鼠标按下操作。
- 开始动画循环
javascript
const startTime = performance.now();
function animate() {
const currentTime = performance.now();
const elapsed = currentTime - startTime;
if (elapsed < duration) {
const progress = elapsed / duration;
const newPosition = distance * easeInOutCubic(progress);
console.log(progress);
const mouseMoveEvent = new MouseEvent("mousemove", { bubbles: true, clientX: startMouseX + newPosition, clientY: startMouseY });
targetElement.dispatchEvent(mouseMoveEvent);
requestAnimationFrame(animate);
} else {
const mouseUpEvent = new MouseEvent("mouseup", { bubbles: true, clientX: startMouseX + distance, clientY: startMouseY });
targetElement.dispatchEvent(mouseUpEvent);
}
}
animate();
首先,记录动画开始时间startTime
。
在animate
函数中:
计算当前时间currentTime
和已经过去的时间elapsed
。
如果elapsed
小于duration
(动画未完成):
计算动画进度progress
。
根据progress
和distance
计算滑块的新位置newPosition
。
创建并触发mousemove
鼠标移动事件,更新滑块位置。
通过requestAnimationFrame
请求下一帧动画。
如果elapsed
大于等于duration
(动画完成):
创建并触发mouseup
鼠标抬起事件
四、总结
按照上述步骤,可以应对绝多数滑块验证的场景。可以直接复制那个示例函数,然后只需要传入滑块DOM,定义滑动距离和时间就好了。
另外,需要注意有些登录框放在iframe里,获取滑块DOM的时候需要先拿到iframe,然后从iframe里面获取滑块,例如
javascript
document.querySelector('iframe:is(#alibaba-login-box)')?.contentWindow.document.querySelector("#nc_1_n1z")
如果有特殊情况,欢迎在评论区探讨