Files
puppeteerjs/src/workers/GeoCaptchaSolver.js
T

135 lines
4.6 KiB
JavaScript

const axios = require("axios");
const PLAY_AUDIO_BTN_ID = ".audio-captcha-play-button"
const wget = require('node-wget');
const crypto = require('crypto');
const fs = require("fs");
const homedir = require('os').homedir();
const dest_dir = homedir + "/wavs/"
const AUDIO_CAPTCHA_TRACK = ".audio-captcha-track";
const CAPTCHA_CONTAINER = "#captcha-container";
const WAV_URL_REGEX = "https:.+.wav";
const re = new RegExp(WAV_URL_REGEX);
function delay(delayInMs) {
return new Promise(resolve => {
setTimeout(() => {
resolve(2);
}, delayInMs);
});
}
function getRandom() {
return Math.floor(Math.random() * 3);
}
function getRandomWaitTime() {
return getRandom() * 1000
}
async function sendRequest(fileName, callback) {
const fileStream = fs.createReadStream(fileName);
let response = await axios.post('http://127.0.0.1:8000', fileStream, {
headers: {
'Content-Type': 'wav'
}
})
if (response.status === 200) {
let result = response.data;
console.log(result);
await callback(result);
console.log("will delete wav file: " + fileName);
await fs.unlink(fileName, (err) => {
if (err) throw err;
console.log(fileName + ' was deleted');
})
} else {
console.log("error");
await callback([]);
console.log("will delete wav file: " + fileName);
}
}
class GeoCaptchaSolver {
constructor(page, device) {
this.page = page;
this.device = device;
}
async solve(onResult) {
console.log("solve() called.")
console.log("play audio")
let iframeHandler = await this.page.frameLocator("body > iframe");
let playAudioBtn = await iframeHandler.locator(PLAY_AUDIO_BTN_ID);
playAudioBtn.click();
await delay(5000 + getRandomWaitTime());
let captcha_container = await iframeHandler.locator(CAPTCHA_CONTAINER)
let html = await captcha_container.innerHTML()
console.log("audio_tag: " + html);
if (!html.includes("You have been blocked")) {
// find wav from html
await this.findTextFromWavFile(html, async (number_list) => {
for (let i = 1; i <= number_list.length; i++) {
let selector = "#captcha__audio > div.audio-captcha-input-container > input:nth-child(" + i + ")"
// console.log("selector is " + selector)
await iframeHandler.locator(selector).focus()
await iframeHandler.locator(selector).fill("" + number_list[i - 1])
// fieldInputs[i].value = number_list[i];
await delay(800 + getRandomWaitTime());
}
try {
if (number_list.length === 0) {
onResult(false)
} else {
onResult(true)
}
} catch (e) {
console.log(e)
}
}
)
} else {
await this.device.screenshot({path: crypto.randomUUID() + '.png'});
await this.resetBrowser()
onResult(false)
}
}
async findTextFromWavFile(html, callback) {
let result = re.exec(html);
//create the directory if not exist
await fs.promises.mkdir(dest_dir, {recursive: true});
if (result) {
let audioUrl = result[0];
let fileName = crypto.randomUUID() + ".wav";
wget({url: audioUrl, dest: dest_dir + fileName}, async function (error, response, body) {
if (error) {
console.log('--- error:');
console.log(error); // error encountered
} else {
console.log('download the file successfully');
// send request to get numbers
await sendRequest(dest_dir + fileName, callback);
}
})
}
}
async resetBrowser() {
console.log("will reset browser")
await this.device.shell("pm clear com.android.chrome")
await delay(1000)
await this.device.shell("am set-debug-app --persistent com.android.chrome")
await delay(1000)
await this.device.shell("pm am start -n com.android.chrome/com.google.android.apps.chrome.Main")
await delay(1000)
this.isTerminated = true
}
}
module.exports = GeoCaptchaSolver
// sendRequest("/Users/lpan/wavs/42f90d53-17c0-4a9b-a585-59eaa737a80d.wav").then(r => {
// console.log(r)
// })