Skip to content

Commit

Permalink
Merge pull request #24 from Matthew17-21/hcap-rqdata
Browse files Browse the repository at this point in the history
* Added hcaptcha rqdata support for Python and Go
* Added Capsolver's `HCaptchaTurboTask`
* Added build scripts for PyPi
  • Loading branch information
Matthew17-21 committed Nov 28, 2023
2 parents 5be7772 + f4fd1fb commit c7b4abd
Show file tree
Hide file tree
Showing 19 changed files with 188 additions and 43 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ captcha_answer = solver.get_token()
| solving_site| true| String (name of site) or int (site ID) | "capmonster"| The captcha solving site that will be used. Refer to [the site IDs](https://github.com/Matthew17-21/Captcha-Tools/tree/main/captchatools-go#site-specific-support)|
| sitekey| true | String | - | Sitekey from the site where captcha is loaded|
| captcha_url | true| String | - | URL where the captcha is located|
| captcha_type| false| String | "v2" | Type of captcha you are solving. Either captcha `image`, `v2`, `v3` or `hcaptcha` (`hcap` works aswell)|
| captcha_type| false| String | "v2" | Type of captcha you are solving. Either captcha `image`, `v2`, `v3`,`hcaptcha` (`hcap` works aswell) or `hcaptchaturbo`|
| invisible_captcha| false | bool | false | If the captcha is invisible or not.<br />__This param is only required when solving invisible captchas__|
| min_score | false | double |0.7 | Minimum score for v3 captchas.<br />__This param is only required when solving V3 and it needs a higher / lower score__|
| action | false | String | "verify" | Action that is associated with the V3 captcha.<br />__This param is only required when solving V3 captchas__|
Expand All @@ -44,6 +44,7 @@ captcha_answer = solver.get_token()
| proxy| false | string | Proxy to be used to solve captchas.<br />This will make the captcha be solved from the proxy ip<br /><br />Format: `ip:port:user:pass` |
| proxy_type | false | string | Type of the proxy being used. Options are:<br /> `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`|
| user_agent | false | string | UserAgent that will be passed to the service and used to solve the captcha |
| rq_data | false | string | Custom data that is used in some implementations of hCaptcha. Most of the times, you want to set the `invisible_captcha` param to `true`.|
### Examples
##### Example - V2 Captcha / Basic usage
```python
Expand Down Expand Up @@ -122,7 +123,7 @@ def main():
| Capmonster | captchatools.CapmonsterSite| Image captchas,<br/> Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | ImageToTextTask,<br/>NoCaptchaTask,<br/> NoCaptchaTaskProxyless,<br/> RecaptchaV3TaskProxyless,<br />HCaptchaTaskProxyless |
| Anticaptcha | captchatools.AnticaptchaSite| Image captchas,<br/> Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | ImageToTextTask,<br/> RecaptchaV2Task<br/> RecaptchaV2TaskProxyless,<br />RecaptchaV3TaskProxyless,<br />HCaptchaTaskProxyless |
| 2Captcha | captchatools.TwoCaptchaSite| Image captchas,<br/> Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | - |
| Capsolver | captchatools.CapsolverSite| Image captchas,<br/> Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | - |
| Capsolver | captchatools.CapsolverSite| Image captchas,<br/> Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha<br />HcaptchaTurbo | - |
| CaptchaAI | captchatools.CaptchaAISite| Image captchas,<br/> Recaptcha V2,<br />Recaptcha V3,<br />HCaptcha | - |


Expand Down
2 changes: 2 additions & 0 deletions captchatools-go/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func main() {
| Proxy| false | *Proxy | Proxy to be used to solve captchas.<br />This will make the captcha be solved from the proxy ip|
| ProxyType | false | string | Type of the proxy being used. Options are:<br /> `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`|
| UserAgent | false | string | UserAgent that will be passed to the service and used to solve the captcha |
| RQData | false | string | Custom data that is used in some implementations of hCaptcha. Most of the times, you want to set the `IsInvisibleCaptcha` param to `true`.|
### Examples
##### Example - V2 Captcha / Basic usage
```go
Expand Down Expand Up @@ -269,6 +270,7 @@ func addtional_data() {
| Recaptcha V2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Recaptcha V3 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Hcaptcha | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| HcaptchaTurbo |:x: | :x: | :x: | :white_check_mark: | :x: |
| Image Captcha | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Cloudflare Turnstile | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: |
| Funcaptcha |:x: | :x: | :x: | :x: | :x: |
Expand Down
72 changes: 54 additions & 18 deletions captchatools-go/anticaptcha.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,27 +179,43 @@ Possible errors that can be returned:
1) ErrIncorrectCapType
*/
func (a Anticaptcha) createPayload(data *AdditionalData) (string, error) {
type EnterprisePayload struct {
Rqdata string `json:"rqdata,omitempty"`
Sentry bool `json:"sentry,omitempty"`
ApiEndpoint string `json:"apiEndpoint,omitempty"`
Endpoint string `json:"endpoint,omitempty"`
ReportAPI string `json:"reportapi,omitempty"`
AssetHost string `json:"assethost,omitempty"`
ImgHost string `json:"imghost,omitempty"`
}
type Task struct {
Type captchaType `json:"type"`
WebsiteURL string `json:"websiteURL"`
WebsiteKey string `json:"websiteKey"`
IsInvisible bool `json:"isInvisible,omitempty"`
MinScore float32 `json:"minScore,omitempty"`
PageAction string `json:"pageAction,omitempty"`
Body string `json:"body,omitempty"`
ProxyType string `json:"proxyType,omitempty"`
ProxyAddress string `json:"proxyAddress,omitempty"`
ProxyPort int `json:"proxyPort,omitempty"`
ProxyLogin string `json:"proxyLogin,omitempty"`
ProxyPassword string `json:"proxyPassword,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
HcapEnterpriseData *EnterprisePayload `json:"enterprisePayload,omitempty"`
}
type Payload struct {
ClientKey string `json:"clientKey"`
Task Task `json:"task"`
SoftID int `json:"softId,omitempty"`
}
// Define the payload we are going to send to the API
payload := capmonsterIDPayload{
payload := Payload{
ClientKey: a.config.Api_key,
Task: struct {
WebsiteURL string "json:\"websiteURL\""
WebsiteKey string "json:\"websiteKey\""
Type captchaType "json:\"type\""
IsInvisible bool "json:\"isInvisible,omitempty\""
MinScore float32 "json:\"minScore,omitempty\""
PageAction string "json:\"pageAction,omitempty\""
Body string "json:\"body,omitempty\""
ProxyType string "json:\"proxyType,omitempty\""
ProxyAddress string "json:\"proxyAddress,omitempty\""
ProxyPort int "json:\"proxyPort,omitempty\""
ProxyLogin string "json:\"proxyLogin,omitempty\""
ProxyPassword string "json:\"proxyPassword,omitempty\""
UserAgent string "json:\"userAgent,omitempty\""
}{
WebsiteURL: a.config.CaptchaURL,
WebsiteKey: a.config.Sitekey,
Task: Task{
Type: a.config.CaptchaType,
WebsiteKey: a.config.Sitekey,
WebsiteURL: a.config.CaptchaURL,
},
}

Expand Down Expand Up @@ -255,6 +271,26 @@ func (a Anticaptcha) createPayload(data *AdditionalData) (string, error) {
default:
return "", ErrIncorrectCapType
}

// Check for any additional data about the task
if data != nil && a.config.CaptchaType != ImageCaptcha {
if data.UserAgent != "" {
payload.Task.UserAgent = data.UserAgent
}
if data.Proxy != nil {
if port, err := strconv.Atoi(data.Proxy.Port); err == nil {
payload.Task.ProxyAddress = data.Proxy.Ip
payload.Task.ProxyPort = port
payload.Task.ProxyLogin = data.Proxy.User
payload.Task.ProxyPassword = data.Proxy.Password
}
}
if data.RQData != "" {
payload.Task.HcapEnterpriseData = &EnterprisePayload{
Rqdata: data.RQData,
}
}
}
encoded, _ := json.Marshal(payload)
return string(encoded), nil
}
Expand Down
19 changes: 17 additions & 2 deletions captchatools-go/capmonster.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type capmonsterIDPayload struct {
ProxyLogin string `json:"proxyLogin,omitempty"`
ProxyPassword string `json:"proxyPassword,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
RqData string `json:"data,omitempty"` // Custom data that is used in some implementations of hCaptcha, mostly with isInvisible=true. In most cases you see it as rqdata inside network requests.
} `json:"task"`
}
type capmonsterCapAnswerPayload struct {
Expand Down Expand Up @@ -228,6 +229,7 @@ func (c Capmonster) createPayload(data *AdditionalData) (string, error) {
ProxyLogin string "json:\"proxyLogin,omitempty\""
ProxyPassword string "json:\"proxyPassword,omitempty\""
UserAgent string "json:\"userAgent,omitempty\""
RqData string "json:\"data,omitempty\""
}{
WebsiteURL: c.config.CaptchaURL,
WebsiteKey: c.config.Sitekey,
Expand Down Expand Up @@ -281,8 +283,21 @@ func (c Capmonster) createPayload(data *AdditionalData) (string, error) {
}

// Check for addtional data
if data != nil && data.UserAgent != "" {
payload.Task.UserAgent = data.UserAgent
if data != nil && c.config.CaptchaType != ImageCaptcha {
if data.UserAgent != "" {
payload.Task.UserAgent = data.UserAgent
}
if data.Proxy != nil {
if port, err := strconv.Atoi(data.Proxy.Port); err == nil {
payload.Task.ProxyAddress = data.Proxy.Ip
payload.Task.ProxyPort = port
payload.Task.ProxyLogin = data.Proxy.User
payload.Task.ProxyPassword = data.Proxy.Password
}
}
if data.RQData != "" {
payload.Task.RqData = data.RQData
}
}

encoded, _ := json.Marshal(payload)
Expand Down
16 changes: 14 additions & 2 deletions captchatools-go/capsolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,17 @@ func (c Capsolver) getCaptchaAnswer(ctx context.Context, additional ...*Addition
solution,
c.Api_key,
c.CaptchaType,
AnticaptchaSite, // TODO change this
CapsolverSite,
ua,
), nil
}
return nil, ErrMaxAttempts
}

func (c Capsolver) createPayload(data *AdditionalData) (string, error) {
type EnterprisePayload struct {
Rqdata string `json:"rqdata"`
}
type Task struct {
Type captchaType `json:"type"`
WebsiteURL string `json:"websiteURL"`
Expand All @@ -183,6 +186,9 @@ func (c Capsolver) createPayload(data *AdditionalData) (string, error) {

// Image Captcha data
B64Image string `json:"body,omitempty"`

// Custom data that is used in some implementations of hCaptcha Enterprise.
HcapEnterpriseData *EnterprisePayload `json:"enterprisePayload,omitempty"`
}
type Payload struct {
ClientKey string `json:"clientKey"`
Expand Down Expand Up @@ -222,7 +228,8 @@ func (c Capsolver) createPayload(data *AdditionalData) (string, error) {
if data != nil && data.Proxy != nil {
p.Task.Type = "HCaptchaTurboTask"
}

case HcaptchaTurbo:
p.Task.Type = "HCaptchaTurboTask"
}

// Check for any additional data about the task
Expand All @@ -233,6 +240,11 @@ func (c Capsolver) createPayload(data *AdditionalData) (string, error) {
if data.Proxy != nil {
p.Task.Proxy = data.Proxy.StringFormatted()
}
if data.RQData != "" {
p.Task.HcapEnterpriseData = &EnterprisePayload{
Rqdata: data.RQData,
}
}
}

// TODO add softkey id
Expand Down
3 changes: 3 additions & 0 deletions captchatools-go/captchaai.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ func (t CaptchaAi) createUrl(data *AdditionalData) (string, error) {
if data.ProxyType != "" {
query.Add("proxytype", data.ProxyType)
}
if data.RQData != "" {
query.Add("data", data.RQData)
}
}

u.RawQuery = query.Encode()
Expand Down
11 changes: 6 additions & 5 deletions captchatools-go/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ const (
)

const (
V2Captcha captchaType = "v2"
V3Captcha captchaType = "v3"
HCaptcha captchaType = "hcaptcha"
ImageCaptcha captchaType = "image"
CFTurnstile captchaType = "cfturnstile"
V2Captcha captchaType = "v2"
V3Captcha captchaType = "v3"
HCaptcha captchaType = "hcaptcha"
HcaptchaTurbo captchaType = "hcaptchaturbo"
ImageCaptcha captchaType = "image"
CFTurnstile captchaType = "cfturnstile"
)

type (
Expand Down
1 change: 1 addition & 0 deletions captchatools-go/harvester.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type AdditionalData struct {
Proxy *Proxy // A proxy in correct formatting - such as user:pass@ip:port
ProxyType string // Type of your proxy: HTTP, HTTPS, SOCKS4, SOCKS5
UserAgent string // UserAgent that will be passed to the service and used to solve the captcha
RQData string // Custom rqdata for hcaptcha
}

// Configurations for the captchas you are solving.
Expand Down
4 changes: 4 additions & 0 deletions captchatools-go/twocaptcha.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type twoCapIDPayload struct {
UserAgent string `json:"userAgent,omitempty"` // userAgent that will be used to solve the captcha
Proxy string `json:"proxy,omitempty"` // Proxy to use to solve captchas from
ProxyType string `json:"proxytype,omitempty"` // Type of the proxy
RQData string `json:"data,omitempty"` // Custom rqdata. mostly with invisible=1
}

// Type that will be used when getting a response from 2captcha
Expand Down Expand Up @@ -232,6 +233,9 @@ func (t Twocaptcha) createPayload(data *AdditionalData) (string, error) {
if data.ProxyType != "" {
payload.ProxyType = data.ProxyType
}
if data.RQData != "" {
payload.RQData = data.RQData
}
}

encoded, _ := json.Marshal(payload)
Expand Down
5 changes: 3 additions & 2 deletions captchatools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(self, **kwargs) -> None:
raise captchaExceptions.WrongAPIKeyException()
if self.solving_site is None:
raise captchaExceptions.NoHarvesterException("No solving site selected")
if self.captcha_type not in ["v2", "v3", "hcaptcha", "hcap", "image", "normal"]:
if self.captcha_type not in ["v2", "v3", "hcaptcha", "hcap", "image", "normal", "hcaptchaturbo"]:
raise captchaExceptions.NoCaptchaType("Invalid captcha type")
if self.soft_id is None:
if self.solving_site == 3 or self.solving_site == "2captcha":
Expand All @@ -63,7 +63,8 @@ def get_token(
self, b64_img: Optional[str]=None,
user_agent: Optional[str]=None,
proxy: Optional[str]=None,
proxy_type: Optional[str]=None
proxy_type: Optional[str]=None,
rq_data: Optional[str] = None
):
'''
Returns a captcha token
Expand Down
3 changes: 2 additions & 1 deletion captchatools/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class Harvester(ABC):
self, b64_img: Optional[str]=None,
user_agent: Optional[str]=None,
proxy: Optional[str]=None,
proxy_type: Optional[str]=None
proxy_type: Optional[str]=None,
rq_data: Optional[str]=None
): ...

def new_harvester(
Expand Down
14 changes: 12 additions & 2 deletions captchatools/anticaptcha.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,21 @@ def get_balance(self) -> float:
except requests.RequestException:
pass

def get_token(self, b64_img: Optional[str] = None, user_agent: Optional[str] = None, proxy: Optional[str] = None, proxy_type: Optional[str] = "HTTP"):
def get_token(
self,
b64_img: Optional[str] = None,
user_agent: Optional[str] = None,
proxy: Optional[str] = None,
proxy_type: Optional[str] = "HTTP",
rq_data: Optional[str] = None
):
# Get ID
task_id = self.__get_id(
b64_img=b64_img,
user_agent=user_agent,
proxy=proxy,
proxy_type=proxy_type
proxy_type=proxy_type,
rq_data=rq_data
)

# Get Answer
Expand Down Expand Up @@ -75,6 +83,8 @@ def __create_payload(self, **kwargs):
payload["task"]["proxyPassword"] = splitted[3]
if kwargs.get("user_agent", None) is not None:
payload["task"]["userAgent"] = kwargs.get("user_agent")
if kwargs.get("rq_data", None) is not None:
payload["task"]["enterprisePayload"] ={"rqdata" :kwargs.get("rq_data")}
return payload

def __get_id(self,**kwargs):
Expand Down
14 changes: 12 additions & 2 deletions captchatools/capmonster.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,21 @@ def get_balance(self) -> float:
except requests.RequestException:
pass

def get_token(self, b64_img: Optional[str] = None, user_agent: Optional[str] = None, proxy: Optional[str] = None, proxy_type: Optional[str] = "HTTP"):
def get_token(
self,
b64_img: Optional[str] = None,
user_agent: Optional[str] = None,
proxy: Optional[str] = None,
proxy_type: Optional[str] = "HTTP",
rq_data: Optional[str] = None
):
# Get ID
task_id = self.__get_id(
b64_img=b64_img,
user_agent=user_agent,
proxy=proxy,
proxy_type=proxy_type
proxy_type=proxy_type,
rq_data=rq_data
)

# Get Answer
Expand Down Expand Up @@ -80,6 +88,8 @@ def __create_payload(self, **kwargs):
payload["task"]["proxyType"] = kwargs.get("proxy_type", "http")
if kwargs.get("user_agent", None) is not None:
payload["task"]["userAgent"] = kwargs.get("user_agent")
if kwargs.get("rq_data", None) is not None:
payload["task"]["data"] = kwargs.get("rq_data")
return payload

def __get_id(self,**kwargs):
Expand Down
Loading

0 comments on commit c7b4abd

Please sign in to comment.