const logger = require("logops") , config = require('../../config') , { By, until } = require('selenium-webdriver') , url = require('url') , poolingService = require('../service/PoolingService') , fetch = require('node-fetch') class SeleniumBrowser { constructor() { this.sleep = m => new Promise(r => setTimeout(r, m)) this.pool = poolingService.pool } async request(params) { let uri = params.uri logger.info('URL %s', uri) if (uri.indexOf('://') > 3) { return this.pool.acquire() .then(async driver => { let html = await driver.get(uri) .then(() => driver.findElement(By.css('body'))) .then(body => body.getAttribute('innerHTML')) let htmlPromise = this.isCaptchaPage(html) ? this.resolveCaptcha(driver) : this.getHtml(driver, html, params) html = await htmlPromise this.pool.destroy(driver) return html }) } else { throw new Error('Invalid URI - ' + uri) } } isCaptchaPage(html) { return html.indexOf('grecaptcha') > -1 || html.indexOf('www.google.com/recaptcha/api2/anchor') > -1 } getCaptchaRequestUri(id) { return 'https://2captcha.com/res.php?key=62fc5ef52fd4befe266d224796a7ea6f&json=1&action=get&id=' + id } getHtml(driver, html, params) { if (params.waitElements) { return driver.get(params.uri) .then(() => Promise.all(params.waitElements.map(s => driver.wait(until.elementLocated(By.css(s)), 10000)))) .then(() => driver.findElement(By.css('body'))) .then(body => body.getAttribute('innerHTML')) .then(html => { return html }) } else { return html } } resolveCaptcha(driver) { return driver.findElement(By.css('#grecaptcha iframe')).getAttribute('src') .then(async src => { return { "key": "62fc5ef52fd4befe266d224796a7ea6f", "method": "userrecaptcha", "googlekey": url.parse(src, true).query.k, "pageurl": await driver.getCurrentUrl(), "json": 1 } }) .then(params => { let requestUrl = new url.URL('https://2captcha.com/in.php') requestUrl.search = new url.URLSearchParams(params).toString(); return fetch(requestUrl).then(res => res.json()).then(res => { logger.debug(res, '2captcha IN-request response') if (!res.hasOwnProperty('request')) { throw new Error('2captcha IN-request response has no data request id : ' + JSON.stringify(res)) } return res.request }) }) .then(async id => { logger.info('Request 2captcha solving result after 20 senconds') await this.sleep(1000 * 20) let res = await fetch(this.getCaptchaRequestUri(id)).then(res => res.json()) let maxRetry = 10 while (res.request == 'CAPCHA_NOT_READY') { await this.sleep(1000 * 5) maxRetry = maxRetry - 1 logger.info('2captcha still working so request solving result after 5 senconds') res = await fetch(this.getCaptchaRequestUri(id)).then(res => res.json()) if (maxRetry == 0) break } return res }) .then(res => { return driver.executeScript('captchaCallback("' + res.request + '")').then(() => this.sleep(1000 * 5)) }) } close() { return this.pool.drain() } } module.exports = new SeleniumBrowser