anti-captchap-romisiffied
Version:
Promissified Captcha solver provider for the anti-captcha service
412 lines (347 loc) • 10.9 kB
JavaScript
const connectionTimeout = 20;
const firstAttemptWaitingInterval = 5;
const normalWaitingInterval = 2;
class AntiCaptcha {
constructor(clientKey) {
this.params = {
host: 'api.anti-captcha.com',
port: 80,
clientKey: clientKey,
// reCAPTCHA 2
websiteUrl: null,
websiteKey: null,
websiteSToken: null,
proxyType: 'http',
proxyAddress: null,
proxyPort: null,
proxyLogin: null,
proxyPassword: null,
userAgent: '',
cookies: '',
// FunCaptcha
websitePublicKey: null,
// image
phrase: null,
case: null,
numeric: null,
math: null,
minLength: null,
maxLength: null,
// CustomCaptcha
imageUrl: null,
assignment: null,
forms: null,
softId: null,
languagePool: null
};
}
getBalance() {
return new Promise((resolve, reject) => {
const postData = { clientKey: this.params.clientKey };
this.jsonPostRequest('getBalance', postData, (err, jsonResult) => {
if (err) {
return reject({ err, res: null, jsonResult });
}
return resolve({ err: null, res: jsonResult.balance, jsonResult });
});
});
};
createTask(type, taskData) {
return new Promise((resolve, reject) => {
type = typeof type == 'undefined' ? 'NoCaptchaTask' : type;
const task = this.getPostData(type);
task.type = type;
const postData = {
clientKey: this.params.clientKey,
task: { ...task, ...taskData },
softId: this.params.softId !== null ? this.params.softId : 0
};
if (this.params.languagePool !== null) {
postData.languagePool = this.params.languagePool;
}
this.jsonPostRequest('createTask', postData, (err, jsonResult) => {
if (err) {
return reject({ err, res: null, jsonResult });
}
return resolve({ err: null, res: jsonResult.taskId, jsonResult });
});
});
};
createTaskProxyless() {
return this.createTask('NoCaptchaTaskProxyless');
};
createFunCaptchaTask() {
return this.createTask('FunCaptchaTask');
};
createFunCaptchaTaskProxyless() {
return this.createTask('FunCaptchaTaskProxyless');
};
createImageToTextTask(taskData) {
return this.createTask('ImageToTextTask', taskData);
};
createCustomCaptchaTask() {
return this.createTask('CustomCaptchaTask');
};
getTaskRawResult(jsonResult) {
if (typeof jsonResult.solution.gRecaptchaResponse != 'undefined') {
return jsonResult.solution.gRecaptchaResponse;
} else if (typeof jsonResult.solution.token != 'undefined') {
return jsonResult.solution.token;
} else if (typeof jsonResult.solution.answers != 'undefined') {
return jsonResult.solution.answers;
} else {
return jsonResult.solution.text;
}
}
getTaskSolution(taskId, currentAttempt, tickCb) {
return new Promise((resolve, reject) => {
currentAttempt = currentAttempt || 0;
const postData = {
clientKey: this.params.clientKey,
taskId: taskId
};
let waitingInterval;
if (currentAttempt == 0) {
waitingInterval = firstAttemptWaitingInterval;
} else {
waitingInterval = normalWaitingInterval;
}
console.log('Waiting %s seconds', waitingInterval);
setTimeout(() => {
this.jsonPostRequest('getTaskResult', postData, (err, jsonResult) => {
if (err) {
return reject({ err, res: null, jsonResult });
}
if (jsonResult.status == 'processing') {
// Every call I'm ticki-ing
if (tickCb) {
tickCb();
}
return this.getTaskSolution(taskId, currentAttempt + 1, tickCb);
} else if (jsonResult.status == 'ready') {
return resolve({
err: null,
res: this.getTaskRawResult(jsonResult),
jsonResult
});
}
});
}, waitingInterval * 1000);
});
};
getPostData(type) {
switch (type) {
case 'CustomCaptchaTask':
return {
imageUrl: this.params.imageUrl,
assignment: this.params.assignment,
forms: this.params.forms
};
case 'ImageToTextTask':
return {
phrase: this.params.phrase,
case: this.params.case,
numeric: this.params.numeric,
math: this.params.math,
minLength: this.params.minLength,
maxLength: this.params.maxLength
};
break;
case 'NoCaptchaTaskProxyless':
return {
websiteURL: this.params.websiteUrl,
websiteKey: this.params.websiteKey,
websiteSToken: this.params.websiteSToken
};
break;
case 'FunCaptchaTask':
return {
websiteURL: this.params.websiteUrl,
websitePublicKey: this.params.websitePublicKey,
proxyType: this.params.proxyType,
proxyAddress: this.params.proxyAddress,
proxyPort: this.params.proxyPort,
proxyLogin: this.params.proxyLogin,
proxyPassword: this.params.proxyPassword,
userAgent: this.params.userAgent,
cookies: this.params.cookies
};
break;
case 'FunCaptchaTaskProxyless':
return {
websiteURL: this.params.websiteUrl,
websitePublicKey: this.params.websitePublicKey,
};
default: // NoCaptchaTask
return {
websiteURL: this.params.websiteUrl,
websiteKey: this.params.websiteKey,
websiteSToken: this.params.websiteSToken,
proxyType: this.params.proxyType,
proxyAddress: this.params.proxyAddress,
proxyPort: this.params.proxyPort,
proxyLogin: this.params.proxyLogin,
proxyPassword: this.params.proxyPassword,
userAgent: this.params.userAgent,
cookies: this.params.cookies
};
}
};
jsonPostRequest(methodName, postData, cb) {
if (typeof process === 'object' && typeof require === 'function') { // NodeJS
const http = require('http');
// http request options
const options = {
hostname: this.params.host,
port: this.params.port,
path: '/' + methodName,
method: 'POST',
headers: {
'accept-encoding': 'gzip,deflate',
'content-type': 'application/json; charset=utf-8',
'accept': 'application/json',
'content-length': Buffer.byteLength(JSON.stringify(postData))
}
};
// console.log(options);
// console.log(JSON.stringify(postData));
const req = http.request(options, (response) => { // on response
let str = '';
// another chunk of data has been recieved, so append it to `str`
response.on('data', (chunk) => {
str += chunk;
});
// the whole response has been recieved, so we just print it out here
response.on('end', () => {
// console.log(str);
let jsonResult = null;
try {
jsonResult = JSON.parse(str);
} catch (err) {
return cb(err);
}
if (jsonResult.errorId) {
return cb(new Error(jsonResult.errorDescription, jsonResult.errorCode), jsonResult);
}
return cb(null, jsonResult);
});
});
// send post data
req.write(JSON.stringify(postData));
req.end();
// timeout in milliseconds
req.setTimeout(connectionTimeout * 1000);
req.on('timeout', () => {
console.log('timeout');
req.abort();
});
// After timeout connection throws Error, so we have to handle it
req.on('error', (err) => {
console.log('error');
return cb(err);
});
return req;
} else if ((typeof window !== 'undefined' || typeof chrome === 'object') && typeof $ == 'function') { // in browser or chrome extension with jQuery
$.ajax(
(window.location.protocol == 'https:' ? 'https:' : 'http:') + '//'
+ this.params.host
+ (window.location.protocol != 'https:' ? ':' + this.params.port : '')
+ '/' + methodName,
{
method: 'POST',
data: JSON.stringify(postData),
dataType: 'json',
success: (jsonResult) => {
if (jsonResult && jsonResult.errorId) {
return cb(new Error(jsonResult.errorDescription, jsonResult.errorCode), jsonResult);
}
cb(false, jsonResult);
},
error: (jqXHR, textStatus, errorThrown) => {
cb(new Error(textStatus != 'error' ? textStatus : 'Unknown error, watch console')); // should be errorThrown
}
}
);
} else {
console.error('Application should be run either in NodeJs environment or has jQuery to be included');
}
};
setClientKey(value) {
this.params.clientKey = value;
};
//proxy access parameters
setWebsiteURL(value) {
this.params.websiteUrl = value;
};
setWebsiteKey(value) {
this.params.websiteKey = value;
};
setWebsiteSToken(value) {
this.params.websiteSToken = value;
};
setWebsitePublicKey(value) {
this.params.websitePublicKey = value;
};
setProxyType(value) {
this.params.proxyType = value;
};
setProxyAddress(value) {
this.params.proxyAddress = value;
};
setProxyPort(value) {
this.params.proxyPort = value;
};
setProxyLogin(value) {
this.params.proxyLogin = value;
};
setProxyPassword(value) {
this.params.proxyPassword = value;
};
setUserAgent(value) {
this.params.userAgent = value;
};
setCookies(value) {
this.params.cookies = value;
};
// image
setPhrase(value) {
this.params.phrase = value;
};
setCase(value) {
this.params.case = value;
};
setNumeric(value) {
this.params.numeric = value;
};
setMath(value) {
this.params.math = value;
};
setMinLength(value) {
this.params.minLength = value;
};
setMaxLength(value) {
this.params.maxLength = value;
};
setImageUrl(value) {
this.params.imageUrl = value;
};
setAssignment(value) {
this.params.assignment = value;
};
setForms(value) {
this.params.forms = value;
};
setSoftId(value) {
this.params.softId = value;
};
setLanguagePool(value) {
this.params.languagePool = value;
};
setHost(value) {
this.params.host = value;
};
setPort(value) {
this.params.port = value;
};
}
module.exports = AntiCaptcha;