滑块自动验证实现

目录

一、实现思路

1、把滑块移动到底

2、控制滑动速度,模拟手动滑动的情况

二、实现代码示例

三、示例函数分析

1、函数总体功能

2、函数定义和参数

3、函数体内部结构

四、总结


最近写的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方法获取目标元素的边界矩形信息。

然后,计算出鼠标起始位置(startMouseXstartMouseY),这是通过将元素的中心位置作为鼠标的起始位置来计算的

  • 定义缓动函数
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

根据progressdistance计算滑块的新位置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")

如果有特殊情况,欢迎在评论区探讨

相关推荐
cnsxjean2 小时前
Vue教程|搭建vue项目|Vue-CLI2.x 模板脚手架
javascript·vue.js·ui·前端框架·npm
web组态软件2 小时前
BY组态-低代码web可视化组件
前端·低代码
react_in2 小时前
webpack 题目
前端·webpack
MarisolHu2 小时前
前端学习笔记-Vue篇-02
前端·vue.js·笔记·学习
学前端的小朱2 小时前
Webpack的基础配置
前端·webpack·node.js
小小优化师 anny2 小时前
JS +CSS @keyframes fadeInUp 来定义载入动画
javascript·css·css3
小周同学_丶3 小时前
解决el-select数据量过大的3种方法
前端·vue.js·elementui
先知demons3 小时前
uniapp开发微信小程序笔记10-触底加载
前端·笔记·微信小程序·小程序·uni-app
每一天,每一步4 小时前
react antd不在form表单中提交表单数据,而是点查询按钮时才将form表单数据和其他查询条件一起触发一次查询,避免重复触发请求
前端·javascript·react.js
NoneCoder4 小时前
HTML5系列(9)-- Web Components
前端·html·html5