Skip to content

Commit 9e75fe2

Browse files
Merge pull request #13 from 2captcha/RC-2646
RC-2646 Add Grid method
2 parents 6ea78f5 + e03686c commit 9e75fe2

12 files changed

+226
-34
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ The easiest way to quickly integrate the [2Captcha](https://2captcha.com/) captc
2525
- [MTCaptcha](#mtcaptcha)
2626
- [Friendly Captcha](#friendly-captcha)
2727
- [Bounding Box Method](#bounding-box-method)
28+
- [Grid](#grid)
2829
- [Other methods](#other-methods)
2930
- [goodReport](#goodreport)
3031
- [badReport](#badreport)
@@ -440,7 +441,7 @@ solver.coordinates({
440441
})
441442
```
442443

443-
### Bounding Box Method:
444+
### Bounding Box Method
444445

445446
<sup>[API method description.](https://2captcha.com/2captcha-api#bounding_box)</sup>
446447

@@ -462,6 +463,28 @@ solver.boundingBox({
462463
})
463464
```
464465

466+
### Grid
467+
468+
<sup>[API method description.](https://2captcha.com/2captcha-api#grid)</sup>
469+
470+
This method allows to solve any captcha where image can be divided into equal parts like reCAPTCHA V2 or hCaptcha. A grid is applied above the image. And you receive the numbers clicked boxes.
471+
472+
> [!IMPORTANT]
473+
> You must to send instruction `imginstructions` or `textinstructions`.
474+
475+
```js
476+
solver.grid({
477+
body: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAR4AAACwCAIAAAB...",
478+
textinstructions: "Select cars in the image"
479+
})
480+
.then((res) => {
481+
console.log(res);
482+
})
483+
.catch((err) => {
484+
console.log(err);
485+
})
486+
```
487+
465488
## Other methods
466489

467490
### goodReport

examples/boundingBox.js

Lines changed: 8 additions & 6 deletions
Large diffs are not rendered by default.

examples/grid.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const TwoCaptcha = require("../dist/index.js");
2+
require('dotenv').config();
3+
const APIKEY = process.env.APIKEY
4+
const solver = new TwoCaptcha.Solver(APIKEY);
5+
const fs = require('fs')
6+
const imageBase64 = fs.readFileSync("./media/recaptchaGrid3x3.jpg", "base64")
7+
8+
solver.grid({
9+
body: imageBase64,
10+
textinstructions: "Select cars in the image"
11+
})
12+
.then((res) => {
13+
console.log(res);
14+
})
15+
.catch((err) => {
16+
console.log(err);
17+
})

examples/grid_options.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const TwoCaptcha = require("../dist/index.js");
2+
require("dotenv").config();
3+
const APIKEY = process.env.APIKEY;
4+
const solver = new TwoCaptcha.Solver(APIKEY);
5+
const fs = require("fs");
6+
const imageBase64 = fs.readFileSync("./media/recaptchaGrid4x4.jpg", "base64");
7+
const imageInstructionsBase64 = fs.readFileSync("./media/recaptchaGridImginstructions4x4.jpg", "base64");
8+
9+
solver.grid({
10+
body: imageBase64,
11+
textinstructions: "Select all squares with stairs",
12+
imginstructions: imageInstructionsBase64,
13+
cols: 4,
14+
rows: 4,
15+
minClicks: 2,
16+
maxClicks: 6,
17+
lang: "en",
18+
canSkip: 1,
19+
// pingback: '123.123.123.123' /* More info about pingback https://2captcha.com/setting/pingback */
20+
// previousId: '123456789'
21+
})
22+
.then((res) => {
23+
console.log(res);
24+
})
25+
.catch((err) => {
26+
console.log(err);
27+
});

examples/media/boundingBox.jpg

66.4 KB
Loading
16.7 KB
Loading

examples/media/recaptchaGrid3x3.jpg

65.4 KB
Loading

examples/media/recaptchaGrid4x4.jpg

351 KB
Loading
Loading

src/structs/2captcha.ts

Lines changed: 100 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as utils from "../utils/generic"
44
import getProviderData from "./providers/providers"
55
import { softId } from "./constants/constants"
66
import checkCaptchaParams from "../utils/checkCaptchaParams"
7+
import renameParams from "../utils/renameParams"
78

89

910
const provider = getProviderData ()
@@ -44,15 +45,15 @@ export interface paramsHCaptcha {
4445

4546
// FixMe:data[key] - how to send this parameter
4647
export interface paramsFunCaptcha {
47-
publickey: string,
48-
pageurl: string,
49-
surl?: string,
50-
header_acao?: boolean,
51-
pingback?: string,
52-
proxy?: string,
53-
proxytype?: string,
54-
userAgent?: string,
55-
data?: string
48+
publickey: string,
49+
pageurl: string,
50+
surl?: string,
51+
header_acao?: boolean,
52+
pingback?: string,
53+
proxy?: string,
54+
proxytype?: string,
55+
userAgent?: string,
56+
data?: string
5657
}
5758

5859
export interface paramsImageCaptcha {
@@ -221,6 +222,21 @@ export interface paramsBoundingBox {
221222
imginstructions?: string,
222223
}
223224

225+
export interface paramsGrid {
226+
body: string,
227+
recaptcha: 1,
228+
rows?: number
229+
cols?: number
230+
minСlicks?: number,
231+
maxСlicks?: number,
232+
previousId?: string,
233+
textinstructions?: string,
234+
imginstructions?: string,
235+
canSkip?: number,
236+
lang?: string,
237+
pingback?: string,
238+
}
239+
224240
/**
225241
* An object containing properties of the captcha solution.
226242
* @typedef {Object} CaptchaAnswer
@@ -398,7 +414,7 @@ export class Solver {
398414
}
399415

400416
/**
401-
* Solves a hCaptcha, returning the result as a string.
417+
* ### Solves a hCaptcha
402418
*
403419
* [Read more about other hCaptcha parameters](https://2captcha.com/2captcha-api#solving_hcaptcha).
404420
*
@@ -452,7 +468,9 @@ export class Solver {
452468
}
453469

454470
/**
455-
* Solves a GeeTest Captcha. [Read more about parameters and solving for Geetest captcha](https://2captcha.com/2captcha-api#solving_geetest).
471+
* ### Solves a GeeTest Captcha.
472+
*
473+
* [Read more about parameters and solving for Geetest captcha](https://2captcha.com/2captcha-api#solving_geetest).
456474
*
457475
* @param {{ gt, challenge, api_server, offline, new_captcha,
458476
* pageurl, pingback, proxy, proxytype, userAgent }} params
@@ -529,7 +547,6 @@ export class Solver {
529547
/**
530548
* ### Solves a GeeTest V4 Captcha.
531549
*
532-
*
533550
* This method accepts an object with the following fields: `pageurl`, `captcha_id`, `pingback`, `proxy`, `proxytype`, `userAgent`.
534551
* The `pageurl` and `captcha_id` fields are required.
535552
*
@@ -581,7 +598,8 @@ export class Solver {
581598
}
582599

583600
/**
584-
* Method for sending Yandex Smart Captcha.
601+
* ### Method for sending Yandex Smart Captcha.
602+
*
585603
* This method accepts an object with the following fields: `pageurl`, `sitekey`, `pingback`, `proxy`, `proxytype`.
586604
* The `pageurl` and `sitekey` fields are required.
587605
*
@@ -633,7 +651,9 @@ export class Solver {
633651
}
634652

635653
/**
636-
* Solves a image-based captcha. [Read more about parameters for image captcha](https://2captcha.com/2captcha-api#solving_normal_captcha).
654+
* ### Solves a image-based captcha.
655+
*
656+
* [Read more about parameters for image captcha](https://2captcha.com/2captcha-api#solving_normal_captcha).
637657
*
638658
* @param {{ body,
639659
* phrase,
@@ -984,17 +1004,6 @@ export class Solver {
9841004
}
9851005
}
9861006

987-
/**
988-
* pageurl: string,
989-
captchakey: string,
990-
api_server?: string,
991-
version?: string,
992-
header_acao?: boolean,
993-
pingback?: string,
994-
proxy?: string,
995-
proxytype?: string,
996-
*/
997-
9981007
/**
9991008
* ### Solves Capy Puzzle captcha
10001009
*
@@ -1342,6 +1351,72 @@ public async boundingBox(params: paramsBoundingBox): Promise<CaptchaAnswer> {
13421351
}
13431352
}
13441353

1354+
1355+
/**
1356+
* ### Grid method
1357+
*
1358+
* The method can be used to bypass tasks where a grid is applied to an image and you need to click on grid tiles, like reCAPTCHA or hCaptcha images.
1359+
*
1360+
* @param {{ body, textinstructions, imginstructions, rows, cols, minСlicks, maxСlicks, previousId, canSkip, lang, pingback}} params Parameters Grid Method as an object.
1361+
* @param {string} params.body `Base64`- encoded captcha image.
1362+
* @param {string} params.textinstructions Text will be shown to worker to help him to select object on the image correctly. For example: "*Select cars in the image*". **Optional parameter**, if the instruction already exists in the form of the `imginstructions`.
1363+
* @param {string} params.imginstructions Image with instruction for worker to help him to select object on the image correctly. The image must be encoded in `Base64` format. **Optional parameter**, if the instruction already exists in the form of the `textinstructions`.
1364+
* @param {number} params.rows Number of rows in grid captcha.
1365+
* @param {number} params.cols Number of columns in grid captcdha.
1366+
* @param {number} params.minСlicks The minimum number of tiles that must be selected. Can't be more than `rows` * `cols`.
1367+
* @param {number} params.maxСlicks The maximum number of tiles that can be selected on the image.
1368+
* @param {string} params.previousId Id of your previous request with the same captcha challenge.
1369+
* @param {number} params.canSkip Set the value to `1` only if it's possible that there's no images matching to the instruction. We'll provide a button "No matching images" to worker and you will receive `No_matching_images` as answer.
1370+
* @param {string} params.lang Language code. [See the list of supported languages](https://2captcha.com/2captcha-api#language).
1371+
* @param {string} params.pingback params.pingback URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. [More info here](https://2captcha.com/2captcha-api#pingback).
1372+
*
1373+
* @example
1374+
* solver.grid({
1375+
* body: 'iVBORw0KGgoAAAANSUhEUgAAAcIA...',
1376+
* textinstructions: "Select cars in the image",
1377+
* imginstructions: '/9j/4AAQSkZJRgABAQEA...'
1378+
* })
1379+
* .then((res) => {
1380+
* console.log(res);
1381+
* })
1382+
* .catch((err) => {
1383+
* console.log(err);
1384+
* })
1385+
*/
1386+
public async grid(params: paramsGrid): Promise<CaptchaAnswer> {
1387+
checkCaptchaParams(params, "grid")
1388+
1389+
params = await renameParams(params)
1390+
1391+
const payload = {
1392+
...params,
1393+
method: "base64",
1394+
recaptcha: 1,
1395+
...this.defaultPayload,
1396+
}
1397+
1398+
const URL = this.in
1399+
const response = await fetch(URL, {
1400+
body: JSON.stringify( payload ),
1401+
method: "post",
1402+
headers: {'Content-Type': 'application/json'}
1403+
})
1404+
const result = await response.text()
1405+
1406+
let data;
1407+
try {
1408+
data = JSON.parse(result)
1409+
} catch {
1410+
throw new APIError(result)
1411+
}
1412+
1413+
if (data.status == 1) {
1414+
return this.pollResponse(data.request)
1415+
} else {
1416+
throw new APIError(data.request)
1417+
}
1418+
}
1419+
13451420
/**
13461421
* Reports a captcha as correctly solved.
13471422
*

src/utils/checkCaptchaParams.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Captcha methods for which parameter checking is available
22
const supportedMethods = ["userrecaptcha", "hcaptcha", "geetest", "geetest_v4","yandex","funcaptcha","lemin","amazon_waf",
3-
"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha']
3+
"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid']
44

55
// Names of required fields that must be contained in the parameters captcha
66
const recaptchaRequiredFields = ['pageurl','googlekey']
@@ -20,6 +20,7 @@ const сyberSiARARequiredFields = ['pageurl', 'master_url_id', 'userAgent']
2020
const mtСaptchaRequiredFields = ['pageurl', 'sitekey']
2121
const boundingBoxRequiredFields = ['image'] // and textinstructions or imginstructions
2222
const friendlyCaptchaFields = ['pageurl','sitekey']
23+
const gridRequiredFields = ['body'] // and textinstructions or imginstructions
2324

2425
/**
2526
* Getting required arguments for a captcha.
@@ -61,6 +62,9 @@ const getRequiredFildsArr = (method: string):Array<string> => {
6162
case "base64":
6263
requiredFieldsArr = base64RequiredFields
6364
break;
65+
case "grid":
66+
requiredFieldsArr = gridRequiredFields
67+
break;
6468
case "capy":
6569
requiredFieldsArr = capyPuzzleRequiredFields
6670
break;
@@ -116,7 +120,16 @@ export default function checkCaptchaParams(params: Object, method: string) {
116120
isCorrectCaptchaParams = true
117121
} else {
118122
isCorrectCaptchaParams = false
119-
throw new Error(`Error when check params captcha.\nNot found "textinstructions" or "imginstructions" field in the Object. One of this field is required for "bounding_box" method. Please add field "textinstructions" or "imginstructions" in object and try again.\nPlease correct your code for the "bounding_box" method according to the code examples`)
123+
throw new Error(`Error when check params captcha.\nNot found "textinstructions" or "imginstructions" field in the Object. One of this field is required for "bounding_box" method. Please add field "textinstructions" or "imginstructions" in object and try again.\nPlease correct your code for the "bounding_box" method according to the code examples.`)
124+
}
125+
}
126+
127+
if(method === "grid") {
128+
if(params.hasOwnProperty('textinstructions') || params.hasOwnProperty('imginstructions')) {
129+
isCorrectCaptchaParams = true
130+
} else {
131+
isCorrectCaptchaParams = false
132+
throw new Error(`Error when check params captcha.\nNot found "textinstructions" or "imginstructions" field in the Object. One of this field is required for "Grid" method. Please add field "textinstructions" or "imginstructions" in object and try again.\nPlease correct your code for the "Grid" method according to the code examples.`)
120133
}
121134
}
122135

src/utils/renameParams.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
*
3+
* ### Renaming captcha parameters
4+
*
5+
* Description: parameter names used in the API may differ from those used in the library, in such cases parameter names are renamed in accordance with those used in the API.
6+
*
7+
* @param params - captcha parameters as an object
8+
* @returns returns new object with renamed params
9+
*
10+
*/
11+
export default function renameParams(params: any) {
12+
let newParams: any = new Object();
13+
14+
/**
15+
* Captcha parameters that need to be renamed before sent to the API.
16+
*/
17+
const replaceParams: any = {
18+
"cols" : "recaptchacols",
19+
"rows" : "recaptcharows",
20+
"minClicks" : "min_clicks",
21+
"maxClicks" : "max_clicks",
22+
"canSkip" : "can_no_answer",
23+
"previousId" : "previousID"
24+
}
25+
26+
for(let key in params) {
27+
if(replaceParams.hasOwnProperty(key)) {
28+
newParams[replaceParams[key]] = params[key]
29+
} else {
30+
newParams[key] = params[key]
31+
}
32+
}
33+
34+
return newParams
35+
}

0 commit comments

Comments
 (0)