Skip to content

Commit 8441e06

Browse files
committed
1.2.1
Python: [+] Added soft_id support for 2captcha [+] Added text-image captcha support [+] Updated documentation [-] Removed redundant unnecessary exception handling code
1 parent e06b698 commit 8441e06

File tree

7 files changed

+114
-47
lines changed

7 files changed

+114
-47
lines changed

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ pip3 install captchatools
1212
```python
1313
pip3 install -U captchatools
1414
```
15-
1615
# How to use
16+
### Getting reCAPTCHA Tokens
1717
```python
1818
import captchatools
1919
solver = captchatools.captcha_harvesters(solving_site="capmonster", api_key="YOUR API KEY", sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-", captcha_url="https://www.google.com/recaptcha/api2/demo")
@@ -26,6 +26,14 @@ solver = captcha_harvesters(solving_site=1, api_key="YOUR API KEY", sitekey="6Le
2626
captcha_answer = solver.get_token()
2727
```
2828

29+
### Getting Normal Captcha Tokens
30+
```python
31+
import captchatools
32+
solver = captchatools.captcha_harvesters(solving_site=2, captcha_type="normal", api_key="YOUR API KEY HERE")
33+
url = "https://www.scienceabc.com/wp-content/uploads/ext-www.scienceabc.com/wp-content/uploads/2016/07/Captcha-ex.jpg-.jpg"
34+
text_cap_answer = solver.get_normal(url)
35+
```
36+
2937
| Parameter | Required | Type | Default | Description|
3038
| :-------------: |:-------------:| :-----:| :-----:| :-----:|
3139
| api_key | true | String| -| The API Key for the captcha solving site|
@@ -46,8 +54,8 @@ captcha_answer = solver.get_token()
4654
##### Site-Specific Support:
4755
| Site |Site ID| Captcha Types Supported | Task Types Supported|
4856
| :-------------: |:-------------:|:-------------:| :-----:|
49-
| Capmonster |1| Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | RecaptchaV2TaskProxyless,<br />RecaptchaV3TaskProxyless,<br />HCaptchaTaskProxyless |
50-
| Anticaptcha |2| Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | RecaptchaV2TaskProxyless,<br />RecaptchaV3TaskProxyless,<br />HCaptchaTaskProxyless |
57+
| Capmonster |1| Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | RecaptchaV2TaskProxyless,<br />RecaptchaV3TaskProxyless,<br />HCaptchaTaskProxyless, <br />ImageToTextTask<br />|
58+
| Anticaptcha |2| Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | RecaptchaV2TaskProxyless,<br />RecaptchaV3TaskProxyless,<br />HCaptchaTaskProxyless <br />ImageToTextTask<br />|
5159
| 2Captcha |3| Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | - |
5260

5361

@@ -63,6 +71,8 @@ captcha_answer = solver.get_token()
6371
| `WrongAPIKeyExceptionException` | Incorrect API Key for captcha solving site|
6472
| `WrongSitekeyException` | Incorrect sitekey |
6573
| `NoHarvesterException` | When the user did not / incorrectly chose a captcha harvester. Refer to the [guide](https://github.com/Matthew17-21/Captcha-Tools#how-to-use) |
74+
| `CaptchaIMGTooBig` | The size of the captcha image is too big for the solving service. |
75+
| `FailedToGetCapIMG`| Failed to get the captcha image from the URL. <br />**Tries 3 times before getting thrown.**<br />
6676

6777
```python
6878
from captchatools import captcha_harvesters, exceptions as captchaExceptions

captchatools-go/anticaptcha.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package captchatoolsgo
33
import (
44
"bytes"
55
"encoding/json"
6-
"fmt"
76
"io/ioutil"
87
"net/http"
98
"time"
@@ -72,7 +71,6 @@ func (t *Anticaptcha) getCaptchaAnswer() (string, error) {
7271
// Parse Response
7372
body, _ := ioutil.ReadAll(resp.Body)
7473
resp.Body.Close()
75-
fmt.Println(string(body))
7674
json.Unmarshal(body, response)
7775
if response.Status == "ready" {
7876
return response.Solution.GRecaptchaResponse, nil

captchatools/anticaptcha.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ def __init__(self, parent:object):
1616

1717
def get_token(self) -> str:
1818
return self.get_answer( self.get_id() )
19+
20+
def get_normal(self, cap_pic_url) -> str:
21+
return self.get_answer(self.get_id(cap_pic_url), True)
1922

20-
def get_id(self) -> int:
23+
def get_id(self, cap_pic_url=None) -> int:
2124
'''
2225
Method to get Queue ID from the API.
2326
'''
@@ -44,6 +47,10 @@ def get_id(self) -> int:
4447

4548
elif self.user_data.captcha_type == "hcap" or self.user_data.captcha_type == "hcaptcha":
4649
payload["task"]["type"] = "HCaptchaTaskProxyless"
50+
51+
elif self.user_data.captcha_type == "normal":
52+
payload["task"]["type"] = "ImageToTextTask"
53+
payload["task"]["body"] = self.user_data.get_cap_img(cap_pic_url)
4754

4855
# Get the Queue ID b sending a POST request to their API
4956
while True:
@@ -61,16 +68,13 @@ def get_id(self) -> int:
6168
elif resp["errorCode"] == "ERROR_KEY_DOES_NOT_EXIST":
6269
# Throw Exception
6370
raise captchaExceptions.WrongAPIKeyException()
64-
except captchaExceptions.NoBalanceException:
65-
raise captchaExceptions.NoBalanceException()
66-
except captchaExceptions.WrongSitekeyException:
67-
raise captchaExceptions.WrongSitekeyException()
68-
except captchaExceptions.WrongAPIKeyException:
69-
raise captchaExceptions.WrongAPIKeyException()
70-
except Exception:
71+
72+
elif resp["errorCode"] == "ERROR_TOO_BIG_CAPTCHA_FILESIZE":
73+
raise captchaExceptions.CaptchaIMGTooBig()
74+
except requests.RequestException:
7175
pass
7276

73-
def get_answer(self, queue_id) -> str:
77+
def get_answer(self, queue_id, isTextCap=False) -> str:
7478
'''
7579
This method gets the captcha token from the API
7680
'''
@@ -84,8 +88,10 @@ def get_answer(self, queue_id) -> str:
8488
}
8589

8690
answer = requests.post(BASEURL + "/getTaskResult", json=payload_getAnswer).json()
87-
if answer["status"] == "ready":
91+
if answer["status"] == "ready" and not isTextCap:
8892
return answer["solution"]["gRecaptchaResponse"]
93+
elif answer["status"] == "ready" and isTextCap:
94+
return answer["solution"]["text"]
8995

9096
elif answer["errorId"] == 12 or answer["errorId"] == 16:
9197
# Captcha unsolvable || TaskID doesn't exist

captchatools/capmonster.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ def __init__(self, parent:object):
1616

1717
def get_token(self) -> str:
1818
return self.get_answer( self.get_id() )
19+
20+
def get_normal(self, path_to_img) -> str:
21+
return self.get_answer(self.get_id(path_to_img), True)
1922

20-
def get_id(self) -> int:
23+
def get_id(self, cap_pic_url=None) -> int:
2124
'''
2225
Method to get Queue ID from the API.
2326
'''
@@ -43,6 +46,11 @@ def get_id(self) -> int:
4346
payload["task"]["pageAction"] = self.user_data.action
4447
elif self.user_data.captcha_type == "hcap" or self.user_data.captcha_type == "hcaptcha":
4548
payload["task"]["type"] = "HCaptchaTaskProxyless"
49+
50+
elif self.user_data.captcha_type == "normal":
51+
payload["task"]["type"] = "ImageToTextTask"
52+
payload["task"]["body"] = self.user_data.get_cap_img(cap_pic_url)
53+
4654

4755
# Get the Queue ID b sending a POST request to their API
4856
while True:
@@ -62,30 +70,27 @@ def get_id(self) -> int:
6270
elif resp["errorCode"] == "ERROR_KEY_DOES_NOT_EXIST":
6371
# Throw Exception
6472
raise captchaExceptions.WrongAPIKeyException()
65-
66-
except captchaExceptions.NoBalanceException:
67-
raise captchaExceptions.NoBalanceException()
68-
except captchaExceptions.WrongSitekeyException:
69-
raise captchaExceptions.WrongSitekeyException()
70-
except captchaExceptions.WrongAPIKeyException:
71-
raise captchaExceptions.WrongAPIKeyException()
72-
except Exception:
73+
74+
elif resp["errorCode"] == "ERROR_TOO_BIG_CAPTCHA_FILESIZE":
75+
raise captchaExceptions.CaptchaIMGTooBig()
76+
except requests.RequestException:
7377
pass
7478

75-
def get_answer(self, queue_id) -> str:
79+
def get_answer(self, queue_id, isTextCap=False) -> str:
7680
'''
7781
This method gets the captcha token from the API
7882
'''
83+
payload_getAnswer = {
84+
"clientKey":self.user_data.api_key,
85+
"taskId": queue_id
86+
}
7987
while True:
8088
try:
81-
payload_getAnswer = {
82-
"clientKey":self.user_data.api_key,
83-
"taskId": queue_id
84-
}
85-
8689
answer = requests.post(BASEURL + "/getTaskResult", json=payload_getAnswer).json()
87-
if answer["status"] == "ready":
90+
if answer["status"] == "ready" and not isTextCap:
8891
return answer["solution"]["gRecaptchaResponse"]
92+
elif answer["status"] == "ready" and isTextCap:
93+
return answer["solution"]["text"]
8994

9095
elif answer["errorId"] == 12 or answer["errorId"] == 16:
9196
# Captcha unsolvable || TaskID doesn't exist

captchatools/exceptions.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
import requests.exceptions
22
class WrongAPIKeyException(Exception):
33
'''
44
This exception gets thrown when the user provides a wrong API Key
@@ -27,4 +27,18 @@ class NoHarvesterException(Exception):
2727
This exception gets thrown when a user doesn't properly set a harvester.
2828
'''
2929
def __init__(self, message="[captchatools] No captcha harvester selected"):
30-
super(NoHarvesterException, self).__init__(message)
30+
super(NoHarvesterException, self).__init__(message)
31+
32+
class CaptchaIMGTooBig(Exception):
33+
'''
34+
This exception gets thrown when the filesize of the captcha image is too big for the solving site.
35+
'''
36+
def __init__(self, message="[captchatools] Size of the captcha image is too big."):
37+
super(CaptchaIMGTooBig, self).__init__(message)
38+
39+
class FailedToGetCapIMG(Exception):
40+
'''
41+
This exception gets thrown when the program fails to get the captcha image after 3 tries
42+
'''
43+
def __init__(self, message="[captchatools] Failed to fetch captcha image."):
44+
super(FailedToGetCapIMG, self).__init__(message)

captchatools/harvesters.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from .twocap import Twocap
22
from .anticaptcha import Anticap
33
from .capmonster import Capmonster
4-
from .exceptions import NoHarvesterException
5-
4+
from .exceptions import NoHarvesterException, FailedToGetCapIMG
5+
import requests
6+
import base64
67
class captcha_harvesters:
78
def __init__( self, solving_site=1,
89
api_key="Key the site gave you to solve captchas",
@@ -40,6 +41,37 @@ def __init__( self, solving_site=1,
4041

4142
def get_token(self):
4243
'''
43-
Returns a captcha token for the provided details
44+
Returns a recaptcha token for the provided details
4445
'''
4546
return self.harvester.get_token()
47+
48+
def get_normal(self, path_to_image):
49+
'''
50+
This method will handle returning text from 'Normal Captchas.'
51+
52+
As per 2captcha,
53+
"Normal Captcha is an image that contains distored but human-readable text. To solve the captcha user have to type the text from the image."
54+
55+
56+
Parameters:
57+
- path_to_image
58+
- The path where the captcha is located (you must download the image yourself and then pass it in)
59+
'''
60+
return self.harvester.get_normal(path_to_image)
61+
62+
@staticmethod
63+
def get_cap_img(img_url:str) -> str:
64+
'''
65+
This function tries 3 times to get the captcha image.
66+
67+
If successful, it returns the base64 encoded image.
68+
If not successful, raises a FailedToGetCapIMG exception
69+
'''
70+
for _ in range(3):
71+
try:
72+
response = requests.get(img_url)
73+
b64response = base64.b64encode(response.content).decode("utf-8")
74+
return b64response
75+
except:
76+
pass
77+
raise FailedToGetCapIMG()

captchatools/twocap.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ def __init__(self, parent:object):
1616
def get_token(self) -> str:
1717
return self.get_answer( self.get_id() )
1818

19-
def get_id(self) -> int:
19+
def get_normal(self, cap_pic_url) -> str:
20+
return self.get_answer( self.get_id(cap_pic_url) )
21+
22+
def get_id(self, cap_pic_url=None) -> int:
2023
payload = {
2124
"key": self.user_data.api_key,
2225
"method": "userrecaptcha", # Because V2 recaptcha is defaulted on init, I'll leave this
@@ -42,9 +45,12 @@ def get_id(self) -> int:
4245
payload.pop("googlekey")
4346
payload["sitekey"] = self.user_data.sitekey
4447

48+
elif self.user_data.captcha_type == "normal":
49+
payload["method"] = "base64"
50+
payload["body"] = self.user_data.get_cap_img(cap_pic_url)
4551
while True:
4652
try:
47-
resp = requests.post(BASEURL, json=payload).json()
53+
resp = requests.post(BASEURL, data=payload).json()
4854
if resp["status"] == 1:
4955
return resp["request"] # Return the queue ID
5056

@@ -59,16 +65,12 @@ def get_id(self) -> int:
5965
elif resp["request"] == "ERROR_WRONG_USER_KEY" or resp["request"] == "ERROR_KEY_DOES_NOT_EXIST":
6066
# Throw Exception
6167
raise captchaExceptions.WrongAPIKeyException()
68+
69+
elif resp["request"] == "ERROR_TOO_BIG_CAPTCHA_FILESIZE":
70+
raise captchaExceptions.CaptchaIMGTooBig()
6271
break
6372

64-
except captchaExceptions.NoBalanceException:
65-
raise captchaExceptions.NoBalanceException()
66-
except captchaExceptions.WrongSitekeyException:
67-
raise captchaExceptions.WrongSitekeyException()
68-
except captchaExceptions.WrongAPIKeyException:
69-
raise captchaExceptions.WrongAPIKeyException()
70-
71-
except Exception:
73+
except requests.RequestException:
7274
pass
7375

7476
def get_answer(self, queue_id) -> str:
@@ -88,4 +90,4 @@ def get_answer(self, queue_id) -> str:
8890
except KeyError:
8991
self.get_token()
9092
except Exception:
91-
pass
93+
pass

0 commit comments

Comments
 (0)