clicks-recaptcha-solver
Version:
A powerful automation tool for solving Google reCAPTCHA challenges using Playwright and Puppeteer. This package intelligently detects and simulates human-like interactions, including mouse movements and precise clicks, to bypass reCAPTCHA v2 and other sim
103 lines (95 loc) • 4.98 kB
text/typescript
import type { CaptchaParams } from '@/types';
/**
* Initializes a custom function within the captcha iframe to extract parameters.
*
* This function injects a script that extracts the required parameters from the captcha page.
* It creates a canvas to work with captcha images, extracts image tiles, and provides metadata like
* rows, columns, and a base64-encoded image of the current captcha state.
*
* @async
* @function initCaptchaParamsExtractor
* @param {import('puppeteer').Frame} frame - A Puppeteer frame representing the reCAPTCHA iframe.
* @returns {Promise<void>} This function doesn't return a value itself but adds a function (`getRecaptchaParams`)
* into the frame context to extract captcha parameters.
* @throws Will reject the promise if reCAPTCHA elements cannot be found on the page.
*/
export const initCaptchaParamsExtractor = async function (frame: any): Promise<void> {
await frame.evaluate(() => {
(window as any).getRecaptchaParams = (): Promise<CaptchaParams> => {
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) {
reject('Failed to get canvas rendering context');
return;
}
const commentElement = document.querySelector('.rc-imageselect-desc-wrapper');
const comment = commentElement
? commentElement.textContent?.replaceAll('\n', ' ') || ''
: '';
const img4x4 = document.querySelector<HTMLImageElement>('img.rc-image-tile-44');
if (!img4x4) {
const table3x3 = document.querySelector(
'table.rc-imageselect-table-33 > tbody'
);
if (!table3x3) {
reject('Cannot find reCAPTCHA elements');
return;
}
const initial3x3img =
table3x3.querySelector<HTMLImageElement>('img.rc-image-tile-33');
if (!initial3x3img) {
reject('Cannot find initial 3x3 image');
return;
}
canvas.width = initial3x3img.naturalWidth;
canvas.height = initial3x3img.naturalHeight;
ctx.drawImage(initial3x3img, 0, 0);
const updatedTiles =
document.querySelectorAll<HTMLImageElement>('img.rc-image-tile-11');
if (updatedTiles.length > 0) {
const pos = [
{ x: 0, y: 0 },
{ x: ctx.canvas.width / 3, y: 0 },
{ x: (ctx.canvas.width / 3) * 2, y: 0 },
{ x: 0, y: ctx.canvas.height / 3 },
{ x: ctx.canvas.width / 3, y: ctx.canvas.height / 3 },
{ x: (ctx.canvas.width / 3) * 2, y: ctx.canvas.height / 3 },
{ x: 0, y: (ctx.canvas.height / 3) * 2 },
{ x: ctx.canvas.width / 3, y: (ctx.canvas.height / 3) * 2 },
{ x: (ctx.canvas.width / 3) * 2, y: (ctx.canvas.height / 3) * 2 }
];
updatedTiles.forEach((t) => {
const parentElement = t.parentElement?.parentElement
?.parentElement as HTMLElement | null;
if (parentElement && parentElement.tabIndex >= 3) {
const ind = parentElement.tabIndex - 3;
if (ind >= 0 && ind < pos.length) {
ctx.drawImage(t, pos[ind].x, pos[ind].y);
}
}
});
}
resolve({
rows: 3,
columns: 3,
type: 'GridTask',
comment,
body: canvas.toDataURL().replace(/^data:image\/?[A-z]*;base64,/, '')
});
} else {
canvas.width = img4x4.naturalWidth;
canvas.height = img4x4.naturalHeight;
ctx.drawImage(img4x4, 0, 0);
resolve({
rows: 4,
columns: 4,
comment,
body: canvas.toDataURL().replace(/^data:image\/?[A-z]*;base64,/, ''),
type: 'GridTask'
});
}
});
};
});
};