async function recaptchaV2({ domain, proxy, siteKey, action = "submit", isInvisible = false }, page) {
if (!domain) throw new Error("Missing domain parameter");
if (!siteKey) throw new Error("Missing siteKey parameter");
const timeout = global.timeOut || 60000;
let isResolved = false;
const cl = setTimeout(async () => {
if (!isResolved) {
throw new Error("Timeout Error");
}
}, timeout);
try {
if (proxy?.username && proxy?.password) {
await page.authenticate({
username: proxy.username,
password: proxy.password,
});
}
const htmlContent = `
reCAPTCHA v2 Solver
reCAPTCHA v2 Solver
SiteKey: ${siteKey}
${isInvisible ? '
' : ''}
Waiting for reCAPTCHA...
`;
// Setup request interception
await page.setRequestInterception(true);
page.removeAllListeners("request");
page.on("request", async (request) => {
const url = request.url();
// Handle main document request
if ([domain, domain + "/"].includes(url) && request.resourceType() === "document") {
await request.respond({
status: 200,
contentType: "text/html",
body: htmlContent,
});
}
// Block unnecessary resources untuk mempercepat
else if (request.resourceType() === 'image' ||
request.resourceType() === 'stylesheet' ||
request.resourceType() === 'font') {
await request.abort();
}
else {
await request.continue();
}
});
// Navigate ke page
await page.goto(domain, {
waitUntil: "domcontentloaded",
timeout: timeout
});
// Tunggu reCAPTCHA container load
await page.waitForSelector('.g-recaptcha', { timeout: 10000 });
// Tunggu token tersedia dengan multiple strategies
const token = await page.waitForFunction(() => {
// Cek dari hidden input
const input = document.querySelector('#recaptcha-token-input');
if (input && input.value && input.value.length > 10) {
return input.value;
}
// Cek dari localStorage
const stored = localStorage.getItem('recaptcha_token');
if (stored && stored.length > 10) {
return stored;
}
// Cek dari global variable
if (window.recaptchaToken && window.recaptchaToken.length > 10) {
return window.recaptchaToken;
}
return null;
}, { timeout, polling: 100 });
const tokenValue = await token.jsonValue();
isResolved = true;
clearTimeout(cl);
if (!tokenValue || tokenValue.length < 10) {
throw new Error("Failed to get valid reCAPTCHA token");
}
console.log('Successfully obtained reCAPTCHA token');
return { token: tokenValue, type: 'recaptcha_v2' };
} catch (error) {
clearTimeout(cl);
// Fallback: coba ambil token dengan method lain
try {
const fallbackToken = await page.evaluate(() => {
const input = document.querySelector('#recaptcha-token-input');
return input ? input.value : null;
});
if (fallbackToken && fallbackToken.length > 10) {
return { token: fallbackToken, type: 'recaptcha_v2' };
}
} catch (e) {
// Ignore fallback error
}
throw new Error(`reCAPTCHA solving failed: ${error.message}`);
}
}
module.exports = recaptchaV2;