Documentation menu

How to use Anti-Captcha plugin in Puppeteer or Selenium

Puppeteer and Selenium are two main engines for browser automation and our plugin integrates seamlessly into them. In this article we'll show how to use it in Puppeteer and Selenium for NodeJS and Python programming languages respectively. If you choose between two, we strongly recommend NodeJS+Puppeteer for it's native environment.

1. Install dependencies. For NodeJS just install given npm packages below, for Python install packages and download "chromedriver" executable from this page. The driver version should match the Chrome version installed on your system.

NodeJS
          npm install adm-zip puppeteer puppeteer-extra puppeteer-extra-plugin-stealth
        
Python
          pip install selenium
        

2. Download plugin in ZIP version for Chrome, unzip it to your project folder. Actual versions are located here. You can also do it programmatically:

NodeJS
          //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 () => {
    // download the plugin
    await new Promise((resolve) => {
        https.get(pluginURL, resp => resp.pipe(fs.createWriteStream('./plugin.zip').on('close', resolve)));
    })
    // unzip it
    const zip = new AdmZip("./plugin.zip");
    await zip.extractAllTo("./plugin/", true);
})();
        
Python
          import urllib.request
import zipfile

url = 'https://antcpt.com/anticaptcha-plugin.zip'
# download the plugin
filehandle, _ = urllib.request.urlretrieve(url)
# unzip it
with zipfile.ZipFile(filehandle, "r") as f:
    f.extractall("plugin")
        

3. Next, configure your API key in ./plugin/js/config_ac_api_key.js file. You can find your API key in the customers area. You'll need some positive balance in order to get it working.

NodeJS
          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!')
}
        
Python
          from pathlib import Path
import zipfile

# set API key in configuration file
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)))

# zip plugin directory back to 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. Initialize browser with the plugin. For Puppeteer we recommend plugin 'puppeteer-extra-plugin-stealth' for 'puppeteer-extra' package, which hides all signs of web-automated Chromium browser.

NodeJS
          //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();
})();
        
Python
          from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_extension('./plugin.zip')

browser = webdriver.Chrome('./chromedriver', options=options)
        

5. Navigate to a target page and fill a form if required. The plugin will pick up Recaptcha automatically and start solving it.

NodeJS
          (async () => {
    const url = 'https://anti-captcha.com/tutorials/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);
    }
    // disable navigation timeout errors
    await page.setDefaultNavigationTimeout(0);

    await page.$eval('#login', (element, login) => {
        element.value = login;
    }, login);
    await page.$eval('#password', (element, password) => {
        element.value = password;
    }, password);

})();
        
Python
          browser.get('https://anti-captcha.com/tutorials/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. Next is a bit tricky part. Some web forms require user to press a submit button after solving Recaptcha, others utilise callbacks and submit them automatically. In the first case we want to press submit button right after Recaptcha was solved. To do that at the right time, simply wait for selector .antigate_solver.solved to come up and then press submit button.

NodeJS
          // wait for "solved" selector to come up
await page.waitForSelector('.antigate_solver.solved').catch(error => console.log('failed to wait for the selector'));
console.log('recaptcha solved');

// press submit button
await Promise.all([
    page.click('#submitButton'),
    page.waitForNavigation({ waitUntil: "networkidle0" })
]);
console.log('task completed, form with recaptcha bypassed');
        
Python
          # wait for "solved" selector to come up
webdriver.support.wait.WebDriverWait(browser, 120).until(lambda x: x.find_element_by_css_selector('.antigate_solver.solved'))
# press submit button
browser.find_element_by_css_selector('#submitButton').click()
        

That's it, form is filled, Recaptcha is solved and bypassed. Full code samples:

NodeJS
          // 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/tutorials/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 () => {
    // download the plugin
    await new Promise((resolve) => {
        https.get(pluginURL, resp => resp.pipe(fs.createWriteStream('./plugin.zip').on('close', resolve)));
    })
    // unzip it
    const zip = new AdmZip("./plugin.zip");
    await zip.extractAllTo("./plugin/", true);

    // set API key in configuration file
    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();
        }
    });

    // set browser launch options
    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 {
        // launch browser with the plugin
        const browser = await puppeteer.launch();
        page = await browser.newPage();
    } catch (e) {
        console.log('could not launch browser: '+e.toString())
        return;
    }

    // navigate to the target page
    try {
        await page.goto(url, {
            waitUntil: "networkidle0"
        });
    } catch (e) {
        console.error('err while loading the page: '+e);
    }

    // disable navigation timeout errors
    await page.setDefaultNavigationTimeout(0);

    // fill the form
    await page.$eval('#login', (element, login) => {
        element.value = login;
    }, login);
    await page.$eval('#password', (element, password) => {
        element.value = password;
    }, password);

    // wait for "solved" selector to come up
    await page.waitForSelector('.antigate_solver.solved').catch(error => console.log('failed to wait for the selector'));
    console.log('recaptcha solved');

    // press submit button
    await Promise.all([
        page.click('#submitButton'),
        page.waitForNavigation({ waitUntil: "networkidle0" })
    ]);
    console.log('recaptcha solved');

})();
        
Python
          import urllib.request
import zipfile
import os
from pathlib import Path
from selenium import webdriver

# download the plugin
url = 'https://antcpt.com/anticaptcha-plugin.zip'
filehandle, _ = urllib.request.urlretrieve(url)
# unzip it
with zipfile.ZipFile(filehandle, "r") as f:
    f.extractall("plugin")

# set API key in configuration file
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)))

# zip plugin directory back to 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()

# set browser launch options
options = webdriver.ChromeOptions()
options.add_extension('./plugin.zip')

# set browser launch options
browser = webdriver.Chrome('./chromedriver', options=options)

# navigate to the target page
browser.get('https://anti-captcha.com/tutorials/v2-textarea')

# fill the form
browser.find_element_by_css_selector('#login').send_keys('Test login')
browser.find_element_by_css_selector('#password').send_keys('Test password')

# wait for "solved" selector to come up
webdriver.support.wait.WebDriverWait(browser, 120).until(lambda x: x.find_element_by_css_selector('.antigate_solver.solved'))

# press submit button
browser.find_element_by_css_selector('#submitButton').click()
        

Bonus: there's a trick to run the plugin in a headless mode, as Chrome does not support browser automation with plugins. Use utility called Xvfb which provides virtual desktop for your application.

bash
          # install the package
apt-get install -y xvfb

# set display variable
export DISPLAY=:0

# start Xvfb daemon in the background (only once)
/usr/bin/Xvfb :0 -screen 0 1024x768x24 &

# wait a bit to let it come up (only once)
sleep 5

# add prefix "xvfb-run" to "node" or "python" script
xvfb-run node myscript.js
# or
xvfb-run python myscript.py