Cómo utilizar el plugin Anti-Captcha en Puppeteer o Selenium
Puppeteer y Selenium son los dos motores principales para la automatización del navegador y nuestro plugin se integra perfectamente a ellos. En este artículo, mostraremos cómo usarlo en Puppeteer y Selenium para los lenguajes NodeJS and Python respectivamente. Si debes elegir entre los dos, te recomendamos NodeJS+Puppeteer como su entorno nativo.
1. Instale las dependencias. Para NodeJS, simplemente instala los paquetes npm que encontrará a continuación. Para Python, descarga e instala los ejecutables "chromedriver" desde esta página. La versión del controlador debe coincidir con la del Chrome instalado en su sistema.
npm install adm-zip puppeteer puppeteer-extra puppeteer-extra-plugin-stealth
pip install selenium
2. Descargue la versión ZIP del plugin para Chrome y descomprímalo en la carpeta de su proyecto. Puede encontrar la más actualizada aquí. También puedes hacerlo mediante programación:
//npm install adm-zip
const https = require('https')
const fs = require('fs');
const AdmZip = require("adm-zip");
const pluginURL = 'https://antcpt.com/anticaptcha-plugin.zip';
(async () => {
// descarga el plugin
await new Promise((resolve) => {
https.get(pluginURL, resp => resp.pipe(fs.createWriteStream('./plugin.zip').on('close', resolve)));
})
// Descomprimelo
const zip = new AdmZip("./plugin.zip");
await zip.extractAllTo("./plugin/", true);
})();
import urllib.request
import zipfile
url = 'https://antcpt.com/anticaptcha-plugin.zip'
# descarga el plugin
filehandle, _ = urllib.request.urlretrieve(url)
# Descomprimelo
with zipfile.ZipFile(filehandle, "r") as f:
f.extractall("plugin")
3. A continuación, configura su clave API en el archivo en ./plugin/js/config_ac_api_key.js. Puede encontrar su clave API en área de clientes. Necesitarás un saldo positivo para que funcione.
const apiKey = 'API_KEY_32_BYTES';
if (fs.existsSync('./plugin/js/config_ac_api_key.js')) {
let confData = fs.readFileSync('./plugin/js/config_ac_api_key.js', 'utf8');
confData = confData.replace(/antiCapthaPredefinedApiKey = ''/g, `antiCapthaPredefinedApiKey = '${apiKey}'`);
fs.writeFileSync('./plugin/js/config_ac_api_key.js', confData, 'utf8');
} else {
console.error('plugin configuration not found!')
}
from pathlib import Path
import zipfile
# establece la clave API en configuración
api_key = "API_KEY_32_BYTES"
file = Path('./plugin/js/config_ac_api_key.js')
file.write_text(file.read_text().replace("antiCapthaPredefinedApiKey = ''", "antiCapthaPredefinedApiKey = '{}'".format(api_key)))
# regresa el directorio zip al plugin.zip
zip_file = zipfile.ZipFile('./plugin.zip', 'w', zipfile.ZIP_DEFLATED)
for root, dirs, files in os.walk("./plugin"):
for file in files:
path = os.path.join(root, file)
zip_file.write(path, arcname=path.replace("./plugin/", ""))
zip_file.close()
4. Inicialice el navegador con el plugin. Para Puppeteer recomendamos el plugin 'puppeteer-extra-plugin-stealth' para el paquete 'puppeteer-extra', que oculta todos los recursos de la web automatizada del navegador Chromium.
//npm install puppeteer puppeteer-extra puppeteer-extra-plugin-stealth
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
(async () => {
const browser = await puppeteer.launch({
headless: false,
ignoreDefaultArgs: [
"--disable-extensions",
"--enable-automation"
],
args: [
'--disable-web-security',
'--disable-features=IsolateOrigins,site-per-process',
'--allow-running-insecure-content',
'--disable-blink-features=AutomationControlled',
'--no-sandbox',
'--mute-audio',
'--no-zygote',
'--no-xshm',
'--window-size=1920,1080',
'--no-first-run',
'--no-default-browser-check',
'--disable-dev-shm-usage',
'--disable-gpu',
'--enable-webgl',
'--ignore-certificate-errors',
'--lang=en-US,en;q=0.9',
'--password-store=basic',
'--disable-gpu-sandbox',
'--disable-software-rasterizer',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--disable-infobars',
'--disable-breakpad',
'--disable-canvas-aa',
'--disable-2d-canvas-clip-aa',
'--disable-gl-drawing-for-tests',
'--enable-low-end-device-mode',
'--disable-extensions-except=./plugin',
'--load-extension=./plugin'
]
});
const page = await browser.newPage();
})();
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_extension('./plugin.zip')
browser = webdriver.Chrome('./chromedriver', options=options)
5. Navega a la página destino y completa un formulario si es requerido. El plugin reconocerá el Recaptcha automáticamente y comenzará a resolverlo.
(async () => {
const url = 'https://anti-captcha.com/demo/?page=recaptcha_v2_textarea';
const login = 'Test login';
const password = 'Test password';
try {
await page.goto(url, {
waitUntil: "networkidle0"
});
} catch (e) {
console.error('err while loading the page: '+e);
}
// inhabilita los errores de tiempo de espera
await page.setDefaultNavigationTimeout(0);
await page.$eval('#login', (element, login) => {
element.value = login;
}, login);
await page.$eval('#password', (element, password) => {
element.value = password;
}, password);
})();
browser.get('https://anti-captcha.com/demo/?page=recaptcha_v2_textarea')
# filling form
browser.find_element_by_css_selector('#login').send_keys('Test login')
browser.find_element_by_css_selector('#password').send_keys('Test password')
6. Lo siguiente puede ser algo complicado. Algunos formularios web requieren que el usuario presione un botón de envío luego de resolver el Recaptcha, otros devuelven la llamada y las envían automáticamente. En el primer caso, queremos presionar el botón de envío una vez resuelto el Recaptcha. Para hacerlo, solo debes esperar a que aparezca el selector .antigate_solver.solved y luego presione el botón enviar.
// espera a que aparezca el botón "solved"
await page.waitForSelector('.antigate_solver.solved').catch(error => console.log('failed to wait for the selector'));
console.log('resuelve el recaptcha');
// presiona el botón enviar
await Promise.all([
page.click('#submitButton'),
page.waitForNavigation({ waitUntil: "networkidle0" })
]);
console.log('tarea completada, formulario con recaptcha omitido');
# espera a que aparezca el botón "solved"
webdriver.support.wait.WebDriverWait(browser, 120).until(lambda x: x.find_element_by_css_selector('.antigate_solver.solved'))
# presiona el botón enviar
browser.find_element_by_css_selector('#submitButton').click()
Y así, el formulario se llena, el Recaptcha es resuelto y omitido. Ejemplos de código completos:
// first run the following to install required npm packages:
//
// npm install adm-zip follow-redirects puppeteer puppeteer-extra puppeteer-extra-plugin-stealth
//
//
const https = require('follow-redirects').https;
const fs = require('fs');
const AdmZip = require("adm-zip");
const apiKey = 'YOUR_API_KEY_HERE!';
const pluginURL = 'https://antcpt.com/anticaptcha-plugin.zip';
const url = 'https://anti-captcha.com/demo/?page=recaptcha_v2_textarea';
const login = 'Test login';
const password = 'Test password';
let page = null;
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
(async () => {
// descarga el plugin
await new Promise((resolve) => {
https.get(pluginURL, resp => resp.pipe(fs.createWriteStream('./plugin.zip').on('close', resolve)));
})
// Descomprimelo
const zip = new AdmZip("./plugin.zip");
await zip.extractAllTo("./plugin/", true);
// establece la clave API en configuración
await new Promise((resolve, reject) => {
if (fs.existsSync('./plugin/js/config_ac_api_key.js')) {
let confData = fs.readFileSync('./plugin/js/config_ac_api_key.js', 'utf8');
confData = confData.replace(/antiCapthaPredefinedApiKey = ''/g, `antiCapthaPredefinedApiKey = '${apiKey}'`);
fs.writeFileSync('./plugin/js/config_ac_api_key.js', confData, 'utf8');
resolve();
} else {
console.error('plugin configuration not found!')
reject();
}
});
// configura las opciones de inicio del navegador
const options = {
headless: false,
ignoreDefaultArgs: [
"--disable-extensions",
"--enable-automation"
],
args: [
'--disable-web-security',
'--disable-features=IsolateOrigins,site-per-process',
'--allow-running-insecure-content',
'--disable-blink-features=AutomationControlled',
'--no-sandbox',
'--mute-audio',
'--no-zygote',
'--no-xshm',
'--window-size=1920,1080',
'--no-first-run',
'--no-default-browser-check',
'--disable-dev-shm-usage',
'--disable-gpu',
'--enable-webgl',
'--ignore-certificate-errors',
'--lang=en-US,en;q=0.9',
'--password-store=basic',
'--disable-gpu-sandbox',
'--disable-software-rasterizer',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--disable-infobars',
'--disable-breakpad',
'--disable-canvas-aa',
'--disable-2d-canvas-clip-aa',
'--disable-gl-drawing-for-tests',
'--enable-low-end-device-mode',
'--disable-extensions-except=./plugin',
'--load-extension=./plugin'
]
}
try {
// inicia el navegador con el plugin
const browser = await puppeteer.launch();
page = await browser.newPage();
} catch (e) {
console.log('could not launch browser: '+e.toString())
return;
}
// Ingresa a la página de destino
try {
await page.goto(url, {
waitUntil: "networkidle0"
});
} catch (e) {
console.error('err while loading the page: '+e);
}
// inhabilita los errores de tiempo de espera
await page.setDefaultNavigationTimeout(0);
// completa el formulario
await page.$eval('#login', (element, login) => {
element.value = login;
}, login);
await page.$eval('#password', (element, password) => {
element.value = password;
}, password);
// espera a que aparezca el botón "solved"
await page.waitForSelector('.antigate_solver.solved').catch(error => console.log('failed to wait for the selector'));
console.log('resuelve el recaptcha');
// presiona el botón enviar
await Promise.all([
page.click('#submitButton'),
page.waitForNavigation({ waitUntil: "networkidle0" })
]);
console.log('resuelve el recaptcha');
})();
import urllib.request
import zipfile
import os
from pathlib import Path
from selenium import webdriver
# descarga el plugin
url = 'https://antcpt.com/anticaptcha-plugin.zip'
filehandle, _ = urllib.request.urlretrieve(url)
# Descomprimelo
with zipfile.ZipFile(filehandle, "r") as f:
f.extractall("plugin")
# establece la clave API en configuración
api_key = "YOUR_API_KEY_HERE!"
file = Path('./plugin/js/config_ac_api_key.js')
file.write_text(file.read_text().replace("antiCapthaPredefinedApiKey = ''", "antiCapthaPredefinedApiKey = '{}'".format(api_key)))
# regresa el directorio zip al plugin.zip
zip_file = zipfile.ZipFile('./plugin.zip', 'w', zipfile.ZIP_DEFLATED)
for root, dirs, files in os.walk("./plugin"):
for file in files:
path = os.path.join(root, file)
zip_file.write(path, arcname=path.replace("./plugin/", ""))
zip_file.close()
# configura las opciones de inicio del navegador
options = webdriver.ChromeOptions()
options.add_extension('./plugin.zip')
# configura las opciones de inicio del navegador
browser = webdriver.Chrome('./chromedriver', options=options)
# Ingresa a la página de destino
browser.get('https://anti-captcha.com/demo/?page=recaptcha_v2_textarea')
# completa el formulario
browser.find_element_by_css_selector('#login').send_keys('Test login')
browser.find_element_by_css_selector('#password').send_keys('Test password')
# espera a que aparezca el botón "solved"
webdriver.support.wait.WebDriverWait(browser, 120).until(lambda x: x.find_element_by_css_selector('.antigate_solver.solved'))
# presiona el botón enviar
browser.find_element_by_css_selector('#submitButton').click()
Bonus: hay un truco para ejecutar el plugin en modo sin encabezado, ya que Chrome no admite la automatización del navegador con plugins. Puedes usar la herramienta Xvfb que proporciona un escritorio virtual para la aplicación.
# instala el paquete
apt-get install -y xvfb
# establece variables de visualización
export DISPLAY=:0
# Inicia el Xvfb daemon en segundo plano (solo una vez)
/usr/bin/Xvfb :0 -screen 0 1024x768x24 &
# espera un poco a que aparezca (solo una vez)
sleep 5
# agrega el prefijo "xvfb-run" a "node" o "python" script
xvfb-run node myscript.js
# o
xvfb-run python myscript.py