滑动验证码是一种常见的验证码形式,通过拖动滑块将缺失的拼图块对准原图中的空缺位置来验证用户操作。本文将介绍如何使用JavaScript中的OpenCV进行模板匹配,并结合Puppeteer实现自动化破解滑动验证码的过程。
所需技术
OpenCV模板匹配:用于识别滑块在背景图中的正确位置。
JavaScript:主要编程语言。
Puppeteer:用于浏览器自动化,模拟用户操作。
破解过程概述
获取验证码图像:
下载背景图和滑块图。
进行必要的图像预处理。
模板匹配:
使用OpenCV的模板匹配算法,计算滑块在背景图中的最佳匹配位置。
模拟滑动:
生成模拟人类滑动的轨迹,避免被识别为机器人。
使用Puppeteer模拟滑动操作。
实现步骤
1. 设置环境
首先,我们需要设置Node.js环境并安装相关的依赖包。
sh
npm init -y
npm install puppeteer opencv4nodejs
2. 获取并预处理验证码图像
接下来,编写JavaScript代码,下载验证码的背景图和滑块图,并对图像进行预处理。
javascript
const puppeteer = require('puppeteer');
const cv = require('opencv4nodejs');
const fs = require('fs');
const axios = require('axios');
async function getImages(bgUrl, sliderUrl) {
const bgResponse = await axios.get(bgUrl, { responseType: 'arraybuffer' });
const sliderResponse = await axios.get(sliderUrl, { responseType: 'arraybuffer' });
fs.writeFileSync('background.png', bgResponse.data);
fs.writeFileSync('slider.png', sliderResponse.data);
}
function preprocessImages() {
const bgImg = cv.imread('background.png');
const sliderImg = cv.imread('slider.png', cv.IMREAD_GRAYSCALE);
return { bgImg, sliderImg };
}
在上述代码中,我们下载并保存验证码图像,然后将滑块图转换为灰度图进行处理。
3. 模板匹配
使用OpenCV的模板匹配算法来确定滑块在背景图中的正确位置。
javascript
function findSliderPosition(bgImg, sliderImg) {
const result = bgImg.matchTemplate(sliderImg, cv.TM_CCOEFF_NORMED);
const minMax = result.minMaxLoc();
const { maxLoc: top_left } = minMax;
return top_left.x;
}
(async () => {
const bgUrl = 'background_image_url';
const sliderUrl = 'slider_image_url';
await getImages(bgUrl, sliderUrl);
const { bgImg, sliderImg } = preprocessImages();
const sliderPosition = findSliderPosition(bgImg, sliderImg);
console.log('Slider Position:', sliderPosition);
})();
这里我们使用TM_CCOEFF_NORMED算法进行匹配,并找到最佳匹配位置的坐标。
4. 模拟滑动操作
通过生成一条模拟人类滑动的轨迹,并使用Puppeteer模拟滑动操作。
javascript
function generateTrack(distance) {
const track = [];
let current = 0;
const mid = distance * 4 / 5;
let t = 0.2;
let v = 0;
while (current < distance) {
let a = current < mid ? 2 : -3;
let v0 = v;
v = v0 + a * t;
let move = v0 * t + 0.5 * a * t * t;
current += move;
track.push(Math.round(move));
}
return track;
}
async function simulateSliderMove(page, slider, track) {
await page.click(slider, { delay: 200 });
const sliderHandle = await page.$(slider);
const boundingBox = await sliderHandle.boundingBox();
await page.mouse.move(
boundingBox.x + boundingBox.width / 2,
boundingBox.y + boundingBox.height / 2
);
await page.mouse.down();
for (const move of track) {
await page.mouse.move(
boundingBox.x + move,
boundingBox.y + boundingBox.height / 2,
{ steps: 10 }
);
await page.waitForTimeout(20 + Math.random() * 10);
}
await page.mouse.up();
}
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('your_target_website_with_captcha');
const slider = 'your_slider_css_selector';
const sliderPosition = 100; // Assume we got this from the template matching
const track = generateTrack(sliderPosition);
await simulateSliderMove(page, slider, track);
await browser.close();
})();