From 669e761bcb42c7ba50bfb38fc3c2905fc187c146 Mon Sep 17 00:00:00 2001 From: spiduler Date: Sat, 10 Oct 2020 01:06:58 +0900 Subject: [PATCH] resolve captcha --- package.json | 1 + src/component/SeleniumBrowser.js | 92 ++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index bc8b9cc..414ad8b 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "express-logging": "^1.1.1", "http-status-codes": "^1.4.0", "logops": "^2.1.1", + "node-fetch": "^2.6.1", "puppeteer-cluster": "^0.22.0", "puppeteer-core": "^1.9.0", "selenium-webdriver": "^4.0.0-alpha.7" diff --git a/src/component/SeleniumBrowser.js b/src/component/SeleniumBrowser.js index 38d49c0..ade850f 100644 --- a/src/component/SeleniumBrowser.js +++ b/src/component/SeleniumBrowser.js @@ -1,6 +1,8 @@ const logger = require("logops") , config = require('../../config') , { Builder, Capabilities, By, Key, until } = require('selenium-webdriver') + , url = require('url') + , fetch = require('node-fetch') , { Options } = require('selenium-webdriver/chrome'); class SeleniumBrowser { @@ -9,6 +11,8 @@ class SeleniumBrowser { this.driver = null this.config = { useHub: true, browser: 'chrome' } this.capabilities = Capabilities.chrome() + this.sleep = m => new Promise(r => setTimeout(r, m)) + this.isRecaptchaReseponseEmpty = false } async setDriver() { @@ -34,19 +38,87 @@ class SeleniumBrowser { opts.addArguments(this.getChromeArgs()) // opts.setChromeBinaryPath('/usr/bin/chromedriver') return new Builder().forBrowser(this.config.browser).setChromeOptions(opts).build(); - // let driver = new webdriver.Builder().forBrowser('chrome').setChromeOptions(this.getChromeArgs()).build(); + // let driver = new + // webdriver.Builder().forBrowser('chrome').setChromeOptions(this.getChromeArgs()).build(); } async request(uri) { - logger.info('Request URL %s', this.website + uri) - return this.driver.get(this.website + uri).then(d => this.driver.findElement(By.css('body')).getAttribute('innerHTML')) - // .then(html => { - // // solve the captcha with API - // const token = await solveCaptcha(params, api) - // }) - // return await driver.findElement(By.css('body')).getAttribute('innerHTML') - //.sendKeys('webdriver', Key.RETURN); - // await driver.wait(until.titleIs('webdriver - www.real.de'), 1000); + if (this.isRecaptchaReseponseEmpty) { + return '' + } else { + logger.info('Request URL %s', this.website + uri) + return this.driver.get(this.website + uri).then(d => this.driver.findElement(By.css('body')).getAttribute('innerHTML')) + .then(html => this.getHtml(html)) + // return await + // driver.findElement(By.css('body')).getAttribute('innerHTML') + // .sendKeys('webdriver', Key.RETURN); + /// await driver.wait(until.titleIs('webdriver - www.real.de'), 1000); + } + } + + async getHtml(html) { + // return html + // check if it's forbbidden page + if (html.indexOf('grecaptcha') > -1 || html.indexOf('www.google.com/recaptcha/api2/anchor') > -1) { + this.isRecaptchaReseponseEmpty = true + let iframeSrc = await this.driver.findElement(By.css('#grecaptcha iframe')).getAttribute('src') + let captcha2Params = { + "key": "62fc5ef52fd4befe266d224796a7ea6f", + "method": "userrecaptcha", + "googlekey": url.parse(iframeSrc, true).query.k, + "pageurl": await this.driver.getCurrentUrl(), + "json": 1 + } + let requestUrl = new url.URL('https://2captcha.com/in.php') + requestUrl.search = new url.URLSearchParams(captcha2Params).toString(); + fetch(requestUrl).then(res => res.json()).then(res => { + logger.info('2captcha IN-request response : %j', res) + if (!res.hasOwnProperty('request')) { + throw new Error('2captcha IN-request response has no data request id : ' + JSON.stringify(res)) + } + return res.request + }).then(async requestId => { + let res = { request: null } + do { + res = await this.requestCaptchaResult(res, requestId) + } while (res.request == 'CAPCHA_NOT_READY') + return res + }).then(res => { + logger.info('2captcha solved : %j', res) + // this.driver.findElement(By.css('#g-recaptcha-response')).setAttribute('innerHTML', res.request) + this.driver.executeScript('captchaCallback("' + res.request + '")') + this.driver.wait(10000).then(d => { + this.driver.findElement(By.css('#g-recaptcha-response')).then(function (webElement) { + logger.error(res, 'Failed to overcome recaptcha') + }, function (err) { + // if (err.state && err.state === 'no such element') { + // console.log('Element not found'); + // } else { + // webdriver.promise.rejected(err); + // } + logger.info('Success to overcome recaptcha') + this.isRecaptchaReseponseEmpty = false + }) + }) + }).catch(error => { + logger.error({ message: error.message }, 'Error occured while process with 2captcha') + }) + return '' + } else { + return html + } + } + + async requestCaptchaResult(res, requestId) { + let requestUrl = 'https://2captcha.com/res.php?key=62fc5ef52fd4befe266d224796a7ea6f&json=1&action=get&id=' + requestId + if (res.request == 'CAPCHA_NOT_READY') { + logger.info('2captcha still working so request solving result after 5 senconds') + await this.sleep(1000 * 5) + return fetch(requestUrl).then(res => res.json()) + } + logger.info('Request 2captcha solving result after 20 senconds') + await this.sleep(1000 * 20) + return fetch(requestUrl).then(res => res.json()) } async close() {