Frontend Development 12 min read

Bypassing Slide Captcha with Puppeteer: A Step‑by‑Step Guide

This article explains how to use the Node.js‑based Puppeteer library to automate the solving of slide‑captcha challenges by opening the target page, extracting canvas data, calculating the missing piece position, simulating a human‑like drag motion, and verifying the result, while comparing Puppeteer with Selenium/WebDriver.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Bypassing Slide Captcha with Puppeteer: A Step‑by‑Step Guide

The author, Liu Guanyu, a senior front‑end engineer at 360 Qiwuchuan, introduces a practical method for cracking slide captchas using the popular Puppeteer automation tool, contrasting it with the WebDriver standard and Selenium framework.

Puppeteer, a Node.js package maintained by Google, communicates directly with Chrome via the DevTools Protocol, offering faster and more straightforward APIs than Selenium, which implements the language‑agnostic WebDriver protocol.

The solution follows three main steps: (1) identify the target position of the captcha gap, (2) perform a drag operation that mimics human behavior, and (3) verify the outcome and handle failures.

Step 1 – Open the page and prepare the environment

const URL = "http://www.geetest.com/type/";
let browser;
const init = async () => {
  if (browser) { return; }
  browser = await puppeteer.launch({ "headless": false, "args": ["--start-fullscreen"] });
};

const configPage = async (page) => {
  await page.setViewport({ width: 1280, height: 1040 });
};

const toRightPage = async (page) => {
  await page.goto(URL);
  await page.evaluate(_ => {
    let rect = document.querySelector(".products-content").getBoundingClientRect();
    window.scrollTo(0, rect.top - 30);
  });
  await page.waitFor(1000);
  await page.click(".products-content li:nth-child(2)");
};

(async () => {
  await configPage(page);
  await toRightPage(page);
})();

The script launches a non‑headless Chrome, navigates to the captcha page, and scrolls to the relevant element.

Step 2 – Extract canvas data to locate the missing piece

The captcha consists of two canvas elements: .geetest_canvas_bg (the visible background with a gap) and .geetest_canvas_fullbg (the full background). By injecting a helper script that reads pixel data via getImageData , the code obtains the color matrices of both canvases.

const injectedScript = `
  const getCanvasValue = (selector) => {
    let canvas = document.querySelector(selector);
    let ctx = canvas.getContext('2d');
    let [width, height] = [canvas.width, canvas.height];
    let rets = [...Array(height)].map(_ => [...Array(width)].map(_ => 0));
    for (let i = 0; i < height; ++i) {
      for (let j = 0; j < width; ++j) {
        rets[i][j] = Object.values(ctx.getImageData(j,i,1,1).data);
      }
    }
    return rets;
  }
`;
await page.addScriptTag({ content: injectedScript });
const full = await page.evaluate(() => getCanvasValue('.geetest_canvas_fullbg'));
const bg = await page.evaluate(() => getCanvasValue('.geetest_canvas_bg'));

After obtaining the two pixel arrays, the script compares them pixel by pixel, using a threshold (e.g., 70) to tolerate minor color differences, and records the coordinates where the arrays diverge. The left‑most differing x‑coordinate is the target drag distance.

const THRESHOLD = 70;
const _equals = (a, b) => {
  if (a.length !== b.length) return false;
  for (let i = 0; i < a.length; ++i) {
    if (Math.abs(a[i] - b[i]) > THRESHOLD) return false;
  }
  return true;
};

const _differentSet = (a1, a2) => {
  let rets = [];
  a1.forEach((el, y) => {
    el.forEach((el2, x) => {
      if (!_equals(el2, a2[y][x])) {
        rets.push({ x, y, v: el2, v2: a2[y][x] });
      }
    });
  });
  return rets;
};

const diff = _differentSet(full, bg);
const target = diff.reduce((min, cur) => cur.x < min.x ? cur : min, diff[0]);

The starting point is always the slider button .geetest_slider_button located at the left edge.

Step 3 – Simulate a human‑like drag

Puppeteer does not provide a direct drag API, but it allows low‑level mouse control. The script obtains the slider’s bounding box, moves the mouse to the button, presses down, and then moves the mouse along a trajectory generated by a generator that follows a uniformly accelerated motion (S = ½ a t²).

let _moveTrace = function*(dis) {
  let trace = [];
  let t0 = 0.2, curr = 0, step = 0, a = 0.8;
  while (curr < dis) {
    let t = t0 * ++step;
    curr = parseFloat(((0.5 * a * t * t)).toFixed(2));
    trace.push(curr);
  }
  for (let i = 0; i < trace.length; ++i) {
    yield trace[i];
  }
};

let slider = await page.waitFor('.geetest_slider_button');
let sliderInfo = await slider.boundingBox();
let m = page.mouse;
await m.move(sliderInfo.x + 5, sliderInfo.y + 6);
await m.down();
let gen = _moveTrace(target.x);
for (let offset of gen) {
  await m.move(sliderInfo.x + offset, sliderInfo.y + 6);
}
await m.up();

After the drag, the script checks whether the success animation element .geetest_success_animate appears to determine if the captcha was solved. If not, it can retry or refresh the page.

let isSuccess = await page.evaluate(() => !!document.querySelector('.geetest_success_animate'));
if (!isSuccess) {
  // retry logic here
}

Finally, the author saves the script and runs it, observing the automated browser solving the slide captcha successfully.

Overall, the guide demonstrates a complete pipeline—from page loading, canvas data extraction, target calculation, realistic drag simulation, to result verification—showcasing how Puppeteer can be leveraged for web‑automation tasks that involve visual challenges.

PuppeteerNode.jsbrowser-automationSeleniumWeb AutomationSlide Captchawebdriver
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.