diff --git a/README.md b/README.md
index 633483e..45dd102 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,8 @@ pip3 install captchatools
```python
pip3 install -U captchatools
```
-
# How to use
+### Getting reCAPTCHA Tokens
```python
import captchatools
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
captcha_answer = solver.get_token()
```
+### Getting Normal Captcha Tokens
+```python
+import captchatools
+solver = captchatools.captcha_harvesters(solving_site=2, captcha_type="normal", api_key="YOUR API KEY HERE")
+url = "https://www.scienceabc.com/wp-content/uploads/ext-www.scienceabc.com/wp-content/uploads/2016/07/Captcha-ex.jpg-.jpg"
+text_cap_answer = solver.get_normal(url)
+```
+
| Parameter | Required | Type | Default | Description|
| :-------------: |:-------------:| :-----:| :-----:| :-----:|
| api_key | true | String| -| The API Key for the captcha solving site|
@@ -46,8 +54,8 @@ captcha_answer = solver.get_token()
##### Site-Specific Support:
| Site |Site ID| Captcha Types Supported | Task Types Supported|
| :-------------: |:-------------:|:-------------:| :-----:|
-| Capmonster |1| Recaptcha V2,
Recaptcha V3,
HCaptcha | RecaptchaV2TaskProxyless,
RecaptchaV3TaskProxyless,
HCaptchaTaskProxyless |
-| Anticaptcha |2| Recaptcha V2,
Recaptcha V3,
HCaptcha | RecaptchaV2TaskProxyless,
RecaptchaV3TaskProxyless,
HCaptchaTaskProxyless |
+| Capmonster |1| Recaptcha V2,
Recaptcha V3,
HCaptcha | RecaptchaV2TaskProxyless,
RecaptchaV3TaskProxyless,
HCaptchaTaskProxyless,
ImageToTextTask
|
+| Anticaptcha |2| Recaptcha V2,
Recaptcha V3,
HCaptcha | RecaptchaV2TaskProxyless,
RecaptchaV3TaskProxyless,
HCaptchaTaskProxyless
ImageToTextTask
|
| 2Captcha |3| Recaptcha V2,
Recaptcha V3,
HCaptcha | - |
@@ -63,6 +71,8 @@ captcha_answer = solver.get_token()
| `WrongAPIKeyExceptionException` | Incorrect API Key for captcha solving site|
| `WrongSitekeyException` | Incorrect sitekey |
| `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) |
+| `CaptchaIMGTooBig` | The size of the captcha image is too big for the solving service. |
+| `FailedToGetCapIMG`| Failed to get the captcha image from the URL.
**Tries 3 times before getting thrown.**
```python
from captchatools import captcha_harvesters, exceptions as captchaExceptions
diff --git a/captchatools-go/anticaptcha.go b/captchatools-go/anticaptcha.go
index d77cae5..3321033 100644
--- a/captchatools-go/anticaptcha.go
+++ b/captchatools-go/anticaptcha.go
@@ -3,7 +3,6 @@ package captchatoolsgo
import (
"bytes"
"encoding/json"
- "fmt"
"io/ioutil"
"net/http"
"time"
@@ -72,7 +71,6 @@ func (t *Anticaptcha) getCaptchaAnswer() (string, error) {
// Parse Response
body, _ := ioutil.ReadAll(resp.Body)
resp.Body.Close()
- fmt.Println(string(body))
json.Unmarshal(body, response)
if response.Status == "ready" {
return response.Solution.GRecaptchaResponse, nil
diff --git a/captchatools/anticaptcha.py b/captchatools/anticaptcha.py
index 430209d..bfd4b60 100644
--- a/captchatools/anticaptcha.py
+++ b/captchatools/anticaptcha.py
@@ -16,8 +16,11 @@ def __init__(self, parent:object):
def get_token(self) -> str:
return self.get_answer( self.get_id() )
+
+ def get_normal(self, cap_pic_url) -> str:
+ return self.get_answer(self.get_id(cap_pic_url), True)
- def get_id(self) -> int:
+ def get_id(self, cap_pic_url=None) -> int:
'''
Method to get Queue ID from the API.
'''
@@ -44,6 +47,10 @@ def get_id(self) -> int:
elif self.user_data.captcha_type == "hcap" or self.user_data.captcha_type == "hcaptcha":
payload["task"]["type"] = "HCaptchaTaskProxyless"
+
+ elif self.user_data.captcha_type == "normal":
+ payload["task"]["type"] = "ImageToTextTask"
+ payload["task"]["body"] = self.user_data.get_cap_img(cap_pic_url)
# Get the Queue ID b sending a POST request to their API
while True:
@@ -61,16 +68,13 @@ def get_id(self) -> int:
elif resp["errorCode"] == "ERROR_KEY_DOES_NOT_EXIST":
# Throw Exception
raise captchaExceptions.WrongAPIKeyException()
- except captchaExceptions.NoBalanceException:
- raise captchaExceptions.NoBalanceException()
- except captchaExceptions.WrongSitekeyException:
- raise captchaExceptions.WrongSitekeyException()
- except captchaExceptions.WrongAPIKeyException:
- raise captchaExceptions.WrongAPIKeyException()
- except Exception:
+
+ elif resp["errorCode"] == "ERROR_TOO_BIG_CAPTCHA_FILESIZE":
+ raise captchaExceptions.CaptchaIMGTooBig()
+ except requests.RequestException:
pass
- def get_answer(self, queue_id) -> str:
+ def get_answer(self, queue_id, isTextCap=False) -> str:
'''
This method gets the captcha token from the API
'''
@@ -84,8 +88,10 @@ def get_answer(self, queue_id) -> str:
}
answer = requests.post(BASEURL + "/getTaskResult", json=payload_getAnswer).json()
- if answer["status"] == "ready":
+ if answer["status"] == "ready" and not isTextCap:
return answer["solution"]["gRecaptchaResponse"]
+ elif answer["status"] == "ready" and isTextCap:
+ return answer["solution"]["text"]
elif answer["errorId"] == 12 or answer["errorId"] == 16:
# Captcha unsolvable || TaskID doesn't exist
diff --git a/captchatools/capmonster.py b/captchatools/capmonster.py
index 2de8487..8ef4058 100644
--- a/captchatools/capmonster.py
+++ b/captchatools/capmonster.py
@@ -16,8 +16,11 @@ def __init__(self, parent:object):
def get_token(self) -> str:
return self.get_answer( self.get_id() )
+
+ def get_normal(self, path_to_img) -> str:
+ return self.get_answer(self.get_id(path_to_img), True)
- def get_id(self) -> int:
+ def get_id(self, cap_pic_url=None) -> int:
'''
Method to get Queue ID from the API.
'''
@@ -43,6 +46,11 @@ def get_id(self) -> int:
payload["task"]["pageAction"] = self.user_data.action
elif self.user_data.captcha_type == "hcap" or self.user_data.captcha_type == "hcaptcha":
payload["task"]["type"] = "HCaptchaTaskProxyless"
+
+ elif self.user_data.captcha_type == "normal":
+ payload["task"]["type"] = "ImageToTextTask"
+ payload["task"]["body"] = self.user_data.get_cap_img(cap_pic_url)
+
# Get the Queue ID b sending a POST request to their API
while True:
@@ -62,30 +70,27 @@ def get_id(self) -> int:
elif resp["errorCode"] == "ERROR_KEY_DOES_NOT_EXIST":
# Throw Exception
raise captchaExceptions.WrongAPIKeyException()
-
- except captchaExceptions.NoBalanceException:
- raise captchaExceptions.NoBalanceException()
- except captchaExceptions.WrongSitekeyException:
- raise captchaExceptions.WrongSitekeyException()
- except captchaExceptions.WrongAPIKeyException:
- raise captchaExceptions.WrongAPIKeyException()
- except Exception:
+
+ elif resp["errorCode"] == "ERROR_TOO_BIG_CAPTCHA_FILESIZE":
+ raise captchaExceptions.CaptchaIMGTooBig()
+ except requests.RequestException:
pass
- def get_answer(self, queue_id) -> str:
+ def get_answer(self, queue_id, isTextCap=False) -> str:
'''
This method gets the captcha token from the API
'''
+ payload_getAnswer = {
+ "clientKey":self.user_data.api_key,
+ "taskId": queue_id
+ }
while True:
try:
- payload_getAnswer = {
- "clientKey":self.user_data.api_key,
- "taskId": queue_id
- }
-
answer = requests.post(BASEURL + "/getTaskResult", json=payload_getAnswer).json()
- if answer["status"] == "ready":
+ if answer["status"] == "ready" and not isTextCap:
return answer["solution"]["gRecaptchaResponse"]
+ elif answer["status"] == "ready" and isTextCap:
+ return answer["solution"]["text"]
elif answer["errorId"] == 12 or answer["errorId"] == 16:
# Captcha unsolvable || TaskID doesn't exist
diff --git a/captchatools/exceptions.py b/captchatools/exceptions.py
index b0606b4..ae91df5 100644
--- a/captchatools/exceptions.py
+++ b/captchatools/exceptions.py
@@ -1,4 +1,4 @@
-
+import requests.exceptions
class WrongAPIKeyException(Exception):
'''
This exception gets thrown when the user provides a wrong API Key
@@ -27,4 +27,18 @@ class NoHarvesterException(Exception):
This exception gets thrown when a user doesn't properly set a harvester.
'''
def __init__(self, message="[captchatools] No captcha harvester selected"):
- super(NoHarvesterException, self).__init__(message)
\ No newline at end of file
+ super(NoHarvesterException, self).__init__(message)
+
+class CaptchaIMGTooBig(Exception):
+ '''
+ This exception gets thrown when the filesize of the captcha image is too big for the solving site.
+ '''
+ def __init__(self, message="[captchatools] Size of the captcha image is too big."):
+ super(CaptchaIMGTooBig, self).__init__(message)
+
+class FailedToGetCapIMG(Exception):
+ '''
+ This exception gets thrown when the program fails to get the captcha image after 3 tries
+ '''
+ def __init__(self, message="[captchatools] Failed to fetch captcha image."):
+ super(FailedToGetCapIMG, self).__init__(message)
\ No newline at end of file
diff --git a/captchatools/harvesters.py b/captchatools/harvesters.py
index 4ff7655..c1af7a7 100644
--- a/captchatools/harvesters.py
+++ b/captchatools/harvesters.py
@@ -1,8 +1,9 @@
from .twocap import Twocap
from .anticaptcha import Anticap
from .capmonster import Capmonster
-from .exceptions import NoHarvesterException
-
+from .exceptions import NoHarvesterException, FailedToGetCapIMG
+import requests
+import base64
class captcha_harvesters:
def __init__( self, solving_site=1,
api_key="Key the site gave you to solve captchas",
@@ -40,6 +41,37 @@ def __init__( self, solving_site=1,
def get_token(self):
'''
- Returns a captcha token for the provided details
+ Returns a recaptcha token for the provided details
'''
return self.harvester.get_token()
+
+ def get_normal(self, path_to_image):
+ '''
+ This method will handle returning text from 'Normal Captchas.'
+
+ As per 2captcha,
+ "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."
+
+
+ Parameters:
+ - path_to_image
+ - The path where the captcha is located (you must download the image yourself and then pass it in)
+ '''
+ return self.harvester.get_normal(path_to_image)
+
+ @staticmethod
+ def get_cap_img(img_url:str) -> str:
+ '''
+ This function tries 3 times to get the captcha image.
+
+ If successful, it returns the base64 encoded image.
+ If not successful, raises a FailedToGetCapIMG exception
+ '''
+ for _ in range(3):
+ try:
+ response = requests.get(img_url)
+ b64response = base64.b64encode(response.content).decode("utf-8")
+ return b64response
+ except:
+ pass
+ raise FailedToGetCapIMG()
\ No newline at end of file
diff --git a/captchatools/twocap.py b/captchatools/twocap.py
index a82881a..e0fbc41 100644
--- a/captchatools/twocap.py
+++ b/captchatools/twocap.py
@@ -16,7 +16,10 @@ def __init__(self, parent:object):
def get_token(self) -> str:
return self.get_answer( self.get_id() )
- def get_id(self) -> int:
+ def get_normal(self, cap_pic_url) -> str:
+ return self.get_answer( self.get_id(cap_pic_url) )
+
+ def get_id(self, cap_pic_url=None) -> int:
payload = {
"key": self.user_data.api_key,
"method": "userrecaptcha", # Because V2 recaptcha is defaulted on init, I'll leave this
@@ -42,9 +45,12 @@ def get_id(self) -> int:
payload.pop("googlekey")
payload["sitekey"] = self.user_data.sitekey
+ elif self.user_data.captcha_type == "normal":
+ payload["method"] = "base64"
+ payload["body"] = self.user_data.get_cap_img(cap_pic_url)
while True:
try:
- resp = requests.post(BASEURL, json=payload).json()
+ resp = requests.post(BASEURL, data=payload).json()
if resp["status"] == 1:
return resp["request"] # Return the queue ID
@@ -59,16 +65,12 @@ def get_id(self) -> int:
elif resp["request"] == "ERROR_WRONG_USER_KEY" or resp["request"] == "ERROR_KEY_DOES_NOT_EXIST":
# Throw Exception
raise captchaExceptions.WrongAPIKeyException()
+
+ elif resp["request"] == "ERROR_TOO_BIG_CAPTCHA_FILESIZE":
+ raise captchaExceptions.CaptchaIMGTooBig()
break
- except captchaExceptions.NoBalanceException:
- raise captchaExceptions.NoBalanceException()
- except captchaExceptions.WrongSitekeyException:
- raise captchaExceptions.WrongSitekeyException()
- except captchaExceptions.WrongAPIKeyException:
- raise captchaExceptions.WrongAPIKeyException()
-
- except Exception:
+ except requests.RequestException:
pass
def get_answer(self, queue_id) -> str:
@@ -88,4 +90,4 @@ def get_answer(self, queue_id) -> str:
except KeyError:
self.get_token()
except Exception:
- pass
+ pass
\ No newline at end of file