一、极验验证码破解概述
极验验证码的破解难点主要在于其复杂的参数和混淆的代码。我们需要绕过这些难点,利用图像处理技术和模拟人类操作的方法来完成破解。
二、环境准备
首先,我们需要安装以下JavaScript库:
Puppeteer
Jimp
可以通过npm在项目中添加这些依赖:
sh
npm install puppeteer jimp
三、浏览器爬虫的破解思路
相比传统爬虫,浏览器爬虫更加直观和有效。浏览器爬虫的思路如下:
图像识别,找到滑块和缺口的位置;
模拟鼠标拖动,将滑块拖到缺口位置。
接下来,我们详细实现这个思路。
四、验证码图片处理
1. 解析图片位置
验证码图片是乱序的,需要根据CSS样式还原。首先,我们抓取验证码图片并解析位置。
javascript
const puppeteer = require('puppeteer');
const Jimp = require('jimp');
async function getImage(url) {
const image = await Jimp.read(url);
return image;
}
async function mergeImage(image, css) {
const width = 260;
const height = 116;
const mergedImage = new Jimp(width, height);
css.forEach((pos, index) => {
const [x, y] = pos.replace('px', '').split(' ').map(Number);
const piece = image.clone().crop(x, y, 10, 58);
mergedImage.composite(piece, (index % 26) * 10, Math.floor(index / 26) * 58);
});
return mergedImage;
}
async function getOffset(image, bgImage) {
for (let x = 0; x < image.bitmap.width; x++) {
for (let y = 0; y < image.bitmap.height; y++) {
const pixel = Jimp.diff(image, bgImage).image.getPixelColor(x, y);
if (pixel !== 0x00000000) {
return x;
}
}
}
return -1;
}
五、模拟滑块拖动
有了滑块偏移量后,我们可以通过Puppeteer模拟拖动滑块。
javascript
async function dragAndDrop(page, offset) {
const slider = await page.$('.gt_slider_knob');
const boundingBox = await slider.boundingBox();
await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
await page.mouse.down();
for (let move = 0; move < offset; move += 10) {
await page.mouse.move(boundingBox.x + boundingBox.width / 2 + move, boundingBox.y + boundingBox.height / 2);
await page.waitForTimeout(100);
}
await page.mouse.move(boundingBox.x + boundingBox.width / 2 + offset, boundingBox.y + boundingBox.height / 2);
await page.mouse.up();
}
六、实现人性化的拖动轨迹
为了模拟更自然的拖动行为,我们引入缓动函数(Easing Functions)。
javascript
function easeOutQuad(x) {
return 1 - (1 - x) * (1 - x);
}
function easeOutExpo(x) {
return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);
}
function getTracks(distance, seconds, easingFunc) {
const tracks = [];
const offsets = [];
for (let t = 0.0; t < seconds; t += 0.1) {
let offset;
if (easingFunc === 'easeOutQuad') {
offset = Math.round(easeOutQuad(t / seconds) * distance);
} else if (easingFunc === 'easeOutExpo') {
offset = Math.round(easeOutExpo(t / seconds) * distance);
}
tracks.push(offset - (offsets[offsets.length - 1] || 0));
offsets.push(offset);
}
return tracks;
}
七、综合实现
我们可以将以上各个部分组合起来,完成对极验验证码的破解。
javascript
const puppeteer = require('puppeteer');
const Jimp = require('jimp');
async function main() {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://account.ch.com/NonRegistrations-Regist');
// 模拟用户行为,点击并输入信息
// 省略相关代码...
// 获取验证码图片
const image = await getImage('https://static.geetest.com/pictures/gt/3999642ae/3999642ae.webp');
const bgImage = await getImage('https://static.geetest.com/pictures/gt/3999642ae/bg/fbdb18152.webp');
// 解析CSS并还原图片
const css = [
'0px 0px', '10px 0px', '20px 0px', '30px 0px', '40px 0px', '50px 0px', '60px 0px', '70px 0px',
// ...
];
const mergedImage = await mergeImage(image, css);
const mergedBgImage = await mergeImage(bgImage, css);
// 计算偏移量
const offset = await getOffset(mergedImage, mergedBgImage);
// 模拟滑块拖动
await dragAndDrop(page, offset);
await browser.close();
}
main();
更多内容联系1436423940