Cendertron,动态爬虫的滑动验证码绕过策略

Cendertron,动态爬虫的滑动验证码绕过策略

Cendertron 安全动态爬虫系列中我们依次介绍了安全爬虫的设计、爬虫的集群搭建,本篇则是讨论有关于滑动验证码的绕过策略。

本文采用的策略与代码来自 How to bypass “slider CAPTCHA” with JS and Puppeteer 一文。

爬虫中滑动验证的绕过

验证是常见的反爬虫策略之一,在现在的很多站点中我们会引入滑动验证的方式,来校验访问者的真实性。譬如下面著名的 jQuery 滑动插件:

在模拟登陆时,我们往往需要绕过这样的滑动验证,而基于 Puppeteer 的动态爬虫也给予了便利;往往我们需要进行以下步骤:移动到滑条中间,按下鼠标,移动鼠标,释放鼠标。

const puppeteer = require('puppeteer');

async function run() {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: { width: 1366, height: 768 }
  });
  const page = await browser.newPage();

  await page.goto('http://kthornbloom.com/slidetosubmit/');
  await page.type('input[name="name"]', 'Puppeteer Bot');
  await page.type('input[name="email"]', 'js@automation.com');

  let sliderElement = await page.$('.slide-submit');
  let slider = await sliderElement.boundingBox();

  let sliderHandle = await page.$('.slide-submit-thumb');
  let handle = await sliderHandle.boundingBox();

  await page.mouse.move(
    handle.x + handle.width / 2,
    handle.y + handle.height / 2
  );
  await page.mouse.down();
  await page.mouse.move(handle.x + slider.width, handle.y + handle.height / 2, {
    steps: 10
  });
  await page.mouse.up();

  await page.waitFor(3000);

  // success!

  await browser.close();
}

run();

在实际的案例中,我们可以以淘宝的注册界面为例:

const puppeteer = require('puppeteer');

async function run() {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: { width: 1366, height: 768 }
  });
  const page = await browser.newPage();

  await page.evaluateOnNewDocument(() => {
    Object.defineProperty(navigator, 'webdriver', {
      get: () => false
    });
  });

  await page.goto('https://world.taobao.com/markets/all/sea/register');

  let frame = page.frames()[1];
  await frame.waitForSelector('.nc_iconfont.btn_slide');

  const sliderElement = await frame.$('.slidetounlock');
  const slider = await sliderElement.boundingBox();

  const sliderHandle = await frame.$('.nc_iconfont.btn_slide');
  const handle = await sliderHandle.boundingBox();
  await page.mouse.move(
    handle.x + handle.width / 2,
    handle.y + handle.height / 2
  );
  await page.mouse.down();
  await page.mouse.move(handle.x + slider.width, handle.y + handle.height / 2, {
    steps: 50
  });
  await page.mouse.up();

  await page.waitFor(3000);

  // success!

  await browser.close();
}

run();

另一种常见的滑块则是如下这种拼图性质的滑块:

const puppeteer = require('puppeteer');
const Rembrandt = require('rembrandt');

async function run() {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: { width: 1366, height: 768 }
  });
  const page = await browser.newPage();

  let originalImage = '';

  await page.setRequestInterception(true);
  page.on('request', request => request.continue());
  page.on('response', async response => {
    if (response.request().resourceType() === 'image')
      originalImage = await response.buffer().catch(() => {});
  });

  await page.goto('https://monoplasty.github.io/vue-monoplasty-slide-verify/');

  const sliderElement = await page.$('.slide-verify-slider');
  const slider = await sliderElement.boundingBox();

  const sliderHandle = await page.$('.slide-verify-slider-mask-item');
  const handle = await sliderHandle.boundingBox();

  let currentPosition = 0;
  let bestSlider = {
    position: 0,
    difference: 100
  };

  await page.mouse.move(
    handle.x + handle.width / 2,
    handle.y + handle.height / 2
  );
  await page.mouse.down();

  while (currentPosition < slider.width - handle.width / 2) {
    await page.mouse.move(
      handle.x + currentPosition,
      handle.y + handle.height / 2 + Math.random() * 10 - 5
    );

    let sliderContainer = await page.$('.slide-verify');
    let sliderImage = await sliderContainer.screenshot();

    const rembrandt = new Rembrandt({
      imageA: originalImage,
      imageB: sliderImage,
      thresholdType: Rembrandt.THRESHOLD_PERCENT
    });

    let result = await rembrandt.compare();
    let difference = result.percentageDifference * 100;

    if (difference < bestSlider.difference) {
      bestSlider.difference = difference;
      bestSlider.position = currentPosition;
    }

    currentPosition += 5;
  }

  await page.mouse.move(
    handle.x + bestSlider.position,
    handle.y + handle.height / 2,
    { steps: 10 }
  );
  await page.mouse.up();

  await page.waitFor(3000);

  // success!

  await browser.close();
}

run();

这里我们采用了简单的图片对比的方式,即在滑动过程中,如果发现了有符合阈值的差异,则认为是已经滑动成功。

Spider 配置

Cendertron 中,提供了一类特殊的 Slider Captcha Monkey,在传入的 SpiderOption 中添加如下参数即可:

export interface SpiderOption {
  allowRedirect: boolean;
  depth: number;
  // 页面插件
  monkies?: {
    sliderCaptcha: {
      sliderElementSelector: string;
      sliderHandleSelector: string;
    };
  };
}

延伸阅读

您可以通过以下任一方式阅读笔者的系列文章,涵盖了技术资料归纳、编程语言与理论、Web 与大前端、服务端开发与基础架构、云计算与大数据、数据科学与人工智能、产品设计等多个领域:

  • 在 Gitbook 中在线浏览,每个系列对应各自的 Gitbook 仓库。
Awesome Lists Awesome CheatSheets Awesome Interviews Awesome RoadMaps Awesome-CS-Books-Warehouse
编程语言理论 Java 实战 JavaScript 实战 Go 实战 Python 实战 Rust 实战
软件工程、数据结构与算法、设计模式、软件架构 现代 Web 开发基础与工程实践 大前端混合开发与数据可视化 服务端开发实践与工程架构 分布式基础架构 数据科学,人工智能与深度学习 产品设计与用户体验

某熊的全栈之路
知识,应该在它该在的地方。一个热爱代码,热爱新技术的程序熊。

爱代码 爱生活 希望成为全栈整合师

22.4k 声望
8.5k 粉丝
0 条评论
推荐阅读
2022-某熊的技术 & 产品成长之路:重启的第二曲线
在过去的 2022 年,伴随着经济寒冬感觉技术也进入了静默期,除了 AI 领域之外少了许多令人激动的技术突破、发现。在过去十年里因为各种新技术、新框架的出现、发展而诞生的各种技术造轮子、布道及各种新 KPI 的机...

王下邀月熊_Chevalier2阅读 1k评论 1

封面图
从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木75阅读 7.1k评论 16

从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木45阅读 8.6k评论 6

从零搭建 Node.js 企业级 Web 服务器(二):校验
校验就是对输入条件的约束,避免无效的输入引起异常。Web 系统的用户输入主要为编辑与提交各类表单,一方面校验要做在编辑表单字段与提交的时候,另一方面接收表单的接口也要做足校验行为,通过前后端共同控制输...

乌柏木35阅读 6.7k评论 10

从零搭建 Node.js 企业级 Web 服务器(五):数据库访问
回顾 从零搭建 Node.js 企业级 Web 服务器(一):接口与分层,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,控制层与服务层实现了业务处理过程,模型层定义了业务实体并以 对象-关系...

乌柏木34阅读 5.1k评论 9

2022大前端总结和2023就业分析
我在年前给掘金平台分享了《2022年热点技术盘点》的前端热点,算是系统性的梳理了一下我自己对前端一整年的总结。年后,在知乎上看到《前端的就业行情怎么样?》,下面都是各种唱衰前端的论调,什么裁员,外包化...

i5ting27阅读 2.3k评论 4

封面图
从零搭建 Node.js 企业级 Web 服务器(十三):断点调试与性能分析
Node.js 官方提供了断点调试机制,出于安全性考虑默认为关闭状态,可以通过 node 参数 --inspect 或 --inspect-brk 开启,配合 IDE 能够非常方便地调试代码,本章就上一章已完成的项目 licg9999/nodejs-server-ex...

乌柏木31阅读 4.2k评论 9

爱代码 爱生活 希望成为全栈整合师

22.4k 声望
8.5k 粉丝
宣传栏