python3-capsolver 0.9.2__py3-none-any.whl → 1.0.0a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. python3_capsolver/__init__.py +1 -0
  2. python3_capsolver/__version__.py +1 -1
  3. python3_capsolver/aws_waf.py +122 -95
  4. python3_capsolver/cloudflare.py +77 -96
  5. python3_capsolver/control.py +31 -29
  6. python3_capsolver/core/aio_captcha_instrument.py +109 -0
  7. python3_capsolver/core/base.py +52 -198
  8. python3_capsolver/core/captcha_instrument.py +145 -0
  9. python3_capsolver/core/const.py +27 -0
  10. python3_capsolver/core/context_instr.py +25 -0
  11. python3_capsolver/core/enum.py +21 -76
  12. python3_capsolver/core/serializer.py +35 -129
  13. python3_capsolver/core/sio_captcha_instrument.py +116 -0
  14. python3_capsolver/core/{config.py → utils.py} +1 -10
  15. python3_capsolver/datadome_slider.py +34 -84
  16. python3_capsolver/friendly_captcha.py +69 -0
  17. python3_capsolver/gee_test.py +58 -90
  18. python3_capsolver/image_to_text.py +86 -116
  19. python3_capsolver/mt_captcha.py +32 -108
  20. python3_capsolver/recaptcha.py +65 -129
  21. python3_capsolver/vision_engine.py +102 -0
  22. python3_capsolver/yandex.py +53 -0
  23. python3_capsolver-1.0.0a0.dist-info/LICENSE +21 -0
  24. {python3_capsolver-0.9.2.dist-info → python3_capsolver-1.0.0a0.dist-info}/METADATA +25 -55
  25. python3_capsolver-1.0.0a0.dist-info/RECORD +28 -0
  26. {python3_capsolver-0.9.2.dist-info → python3_capsolver-1.0.0a0.dist-info}/WHEEL +1 -1
  27. python3_capsolver/akamai.py +0 -192
  28. python3_capsolver/binance.py +0 -112
  29. python3_capsolver/cyber_si_ara.py +0 -128
  30. python3_capsolver/fun_captcha.py +0 -251
  31. python3_capsolver/hcaptcha.py +0 -197
  32. python3_capsolver/imperva.py +0 -120
  33. python3_capsolver-0.9.2.dist-info/RECORD +0 -25
  34. {python3_capsolver-0.9.2.dist-info → python3_capsolver-1.0.0a0.dist-info}/top_level.txt +0 -0
@@ -1,30 +1,47 @@
1
- from typing import Any, Dict, List, Literal, Optional
1
+ from enum import Enum
2
+ from typing import Any, Dict, Literal, Optional
2
3
 
3
- from pydantic import Field, BaseModel, conint
4
+ from msgspec import Struct
5
+
6
+ from .enum import ResponseStatusEnm
7
+ from .const import APP_ID
8
+
9
+ __all__ = ("PostRequestSer", "TaskSer", "RequestCreateTaskSer", "CaptchaResponseSer", "RequestGetTaskResultSer")
10
+
11
+
12
+ class MyBaseModel(Struct):
13
+ def to_dict(self) -> Dict[str, str]:
14
+ result = {}
15
+ for f in self.__struct_fields__:
16
+ if isinstance(getattr(self, f), Enum):
17
+ result.update({f: getattr(self, f).value})
18
+ else:
19
+ result.update({f: getattr(self, f)})
20
+ return result
4
21
 
5
- from python3_capsolver.core.enum import ResponseStatusEnm
6
- from python3_capsolver.core.config import APP_ID
7
22
 
8
23
  """
9
24
  HTTP API Request ser
10
25
  """
11
26
 
12
27
 
13
- class PostRequestSer(BaseModel):
14
- clientKey: str = Field(..., description="Client account key, can be found in user account")
15
- task: dict = Field(None, description="Task object")
28
+ class PostRequestSer(MyBaseModel):
29
+ clientKey: str
30
+ task: Dict = {}
31
+ callbackUrl: Optional[str] = None
16
32
 
17
33
 
18
- class TaskSer(BaseModel):
19
- type: str = Field(..., description="Task type name", alias="captcha_type")
34
+ class TaskSer(MyBaseModel):
35
+ type: str
20
36
 
21
37
 
22
38
  class RequestCreateTaskSer(PostRequestSer):
23
39
  appId: Literal[APP_ID] = APP_ID
24
40
 
25
41
 
26
- class RequestGetTaskResultSer(PostRequestSer):
27
- taskId: Optional[str] = Field(None, description="ID created by the createTask method")
42
+ class RequestGetTaskResultSer(MyBaseModel):
43
+ clientKey: str
44
+ taskId: Optional[str] = None
28
45
 
29
46
 
30
47
  """
@@ -32,125 +49,14 @@ HTTP API Response ser
32
49
  """
33
50
 
34
51
 
35
- class ResponseSer(BaseModel):
36
- errorId: int = Field(..., description="Error message: `False` - no error, `True` - with error")
52
+ class ResponseSer(MyBaseModel):
53
+ errorId: int = 0
37
54
  # error info
38
- errorCode: Optional[str] = Field(None, description="Error code")
39
- errorDescription: Optional[str] = Field(None, description="Error description")
55
+ errorCode: Optional[str] = None
56
+ errorDescription: Optional[str] = None
40
57
 
41
58
 
42
59
  class CaptchaResponseSer(ResponseSer):
43
- taskId: Optional[str] = Field(None, description="Task ID for future use in getTaskResult method.")
44
- status: ResponseStatusEnm = Field(ResponseStatusEnm.Processing, description="Task current status")
45
- solution: Dict[str, Any] = Field(None, description="Task result data. Different for each type of task.")
46
-
47
- class Config:
48
- allow_population_by_field_name = True
49
-
50
-
51
- class ControlResponseSer(ResponseSer):
52
- balance: Optional[float] = Field(0, description="Account balance value in USD")
53
-
54
-
55
- """
56
- Other ser
57
- """
58
-
59
-
60
- class CaptchaOptionsSer(BaseModel):
61
- api_key: str
62
- sleep_time: conint(ge=5) = 5
63
-
64
-
65
- """
66
- Captcha tasks ser
67
- """
68
-
69
-
70
- class WebsiteDataOptionsSer(TaskSer):
71
- websiteURL: str = Field(..., description="Address of a webpage with Captcha")
72
- websiteKey: Optional[str] = Field(None, description="Website key")
73
-
74
-
75
- class ReCaptchaV3Ser(WebsiteDataOptionsSer):
76
- pageAction: str = Field(
77
- "verify",
78
- description="Widget action value."
79
- "Website owner defines what user is doing on the page through this parameter",
80
- )
81
-
82
-
83
- class HCaptchaClassificationOptionsSer(TaskSer):
84
- queries: List[str] = Field(..., description="Base64-encoded images, do not include 'data:image/***;base64,'")
85
- question: str = Field(
86
- ..., description="Question ID. Support English and Chinese, other languages please convert yourself"
87
- )
88
-
89
-
90
- class FunCaptchaClassificationOptionsSer(TaskSer):
91
- images: List[str] = Field(..., description="Base64-encoded images, do not include 'data:image/***;base64,'")
92
- question: str = Field(
93
- ...,
94
- description="Question name. this param value from API response game_variant field. Exmaple: maze,maze2,flockCompass,3d_rollball_animals",
95
- )
96
-
97
-
98
- class GeeTestSer(TaskSer):
99
- websiteURL: str = Field(..., description="Address of a webpage with Geetest")
100
- gt: str = Field(..., description="The domain public key, rarely updated")
101
- challenge: Optional[str] = Field(
102
- "",
103
- description="If you need to solve Geetest V3 you must use this parameter, don't need if you need to solve GeetestV4",
104
- )
105
-
106
-
107
- class FunCaptchaSer(TaskSer):
108
- websiteURL: str = Field(..., description="Address of a webpage with Funcaptcha")
109
- websitePublicKey: str = Field(..., description="Funcaptcha website key.")
110
- funcaptchaApiJSSubdomain: Optional[str] = Field(
111
- None,
112
- description="A special subdomain of funcaptcha.com, from which the JS captcha widget should be loaded."
113
- "Most FunCaptcha installations work from shared domains.",
114
- )
115
-
116
-
117
- class DatadomeSliderSer(TaskSer):
118
- websiteURL: str = Field(..., description="Address of a webpage with DatadomeSlider")
119
- captchaUrl: str = Field(..., description="Captcha Url where is the captcha")
120
- userAgent: str = Field(..., description="Browser's User-Agent which is used in emulation")
121
-
122
-
123
- class CloudflareTurnstileSer(WebsiteDataOptionsSer):
124
- ...
125
-
126
-
127
- class CyberSiAraSer(WebsiteDataOptionsSer):
128
- SlideMasterUrlId: str = Field(
129
- ..., description="You can get MasterUrlId param form `api/CyberSiara/GetCyberSiara` endpoint request"
130
- )
131
- UserAgent: str = Field(..., description="Browser userAgent, you need submit your userAgent")
132
-
133
-
134
- class AntiAkamaiBMPTaskSer(TaskSer):
135
- packageName: str = Field("de.zalando.iphone", description="Package name of AkamaiBMP mobile APP")
136
- version: str = Field("3.2.6", description="AKAMAI BMP Version number")
137
- country: str = Field("US", description="AKAMAI BMP country")
138
-
139
-
140
- class AntiAkamaiWebTaskSer(TaskSer):
141
- url: str = Field(..., description="Browser url address")
142
-
143
-
144
- class AntiImpervaTaskSer(TaskSer):
145
- websiteUrl: str = Field(..., description="The website url")
146
- userAgent: str = Field(..., description="Browser userAgent")
147
- utmvc: bool = Field(
148
- True, description="If cookie contains `incap_see_xxx`, `nlbi_xxx`, `visid_inap_xxx`, mean is true"
149
- )
150
- reese84: bool = Field(True, description="if cookie conains `reese84`, set it true")
151
-
152
-
153
- class BinanceCaptchaTaskSer(TaskSer):
154
- websiteURL: str = Field(..., description="Address of a webpage with Binance captcha")
155
- websiteKey: str = Field("login", description="`bizId` always be `login`")
156
- validateId: str = Field(..., description="`validateId` bncaptcha validateId field")
60
+ taskId: Optional[str] = None
61
+ status: ResponseStatusEnm = ResponseStatusEnm.Processing
62
+ solution: Optional[Dict[str, Any]] = None
@@ -0,0 +1,116 @@
1
+ import time
2
+ import logging
3
+ from typing import Optional
4
+ from urllib import parse
5
+
6
+ import requests
7
+ from requests.adapters import HTTPAdapter
8
+
9
+ from .enum import ResponseStatusEnm, EndpointPostfixEnm
10
+ from .const import RETRIES, REQUEST_URL, VALID_STATUS_CODES, GET_BALANCE_POSTFIX
11
+ from .utils import attempts_generator
12
+ from .serializer import CaptchaResponseSer
13
+ from .captcha_instrument import CaptchaInstrument
14
+
15
+ __all__ = ("SIOCaptchaInstrument",)
16
+
17
+
18
+ class SIOCaptchaInstrument(CaptchaInstrument):
19
+ """
20
+ Instrument for working with sync captcha
21
+ """
22
+
23
+ def __init__(self, captcha_params: "CaptchaParams"):
24
+ super().__init__()
25
+ self.captcha_params = captcha_params
26
+ self.created_task_data = CaptchaResponseSer
27
+ # prepare session
28
+ self.session = requests.Session()
29
+ self.session.mount("http://", HTTPAdapter(max_retries=RETRIES))
30
+ self.session.mount("https://", HTTPAdapter(max_retries=RETRIES))
31
+ self.session.verify = False
32
+
33
+ def processing_captcha(self) -> dict:
34
+ self.captcha_params.create_task_payload.task = self.captcha_params.task_params
35
+
36
+ self.created_task_data = CaptchaResponseSer(**self.__create_task())
37
+
38
+ # if task created and ready - return result
39
+ if self.created_task_data.errorId == 0 and self.created_task_data.status == ResponseStatusEnm.Processing:
40
+ return self.__get_result().to_dict()
41
+ elif self.created_task_data.errorId != 0:
42
+ self.created_task_data.status = ResponseStatusEnm.Failed
43
+
44
+ return self.created_task_data.to_dict()
45
+
46
+ def __create_task(self, url_postfix: str = EndpointPostfixEnm.CREATE_TASK.value) -> dict:
47
+ """
48
+ Function send SYNC request to service and wait for result
49
+ """
50
+ try:
51
+ resp = self.session.post(
52
+ parse.urljoin(self.captcha_params.request_url, url_postfix),
53
+ json=self.captcha_params.create_task_payload.to_dict(),
54
+ )
55
+ if resp.status_code in VALID_STATUS_CODES:
56
+ return resp.json()
57
+ else:
58
+ raise ValueError(resp.raise_for_status())
59
+ except Exception as error:
60
+ logging.exception(error)
61
+ raise
62
+
63
+ def __get_result(self, url_postfix: str = EndpointPostfixEnm.GET_TASK_RESULT.value) -> CaptchaResponseSer:
64
+ """
65
+ Method send SYNC request to service and wait for result
66
+ """
67
+ # initial waiting
68
+ time.sleep(self.captcha_params.sleep_time)
69
+
70
+ self.captcha_params.get_result_params.taskId = self.created_task_data.taskId
71
+
72
+ attempts = attempts_generator()
73
+ for _ in attempts:
74
+ try:
75
+ resp = self.session.post(
76
+ parse.urljoin(self.captcha_params.request_url, url_postfix),
77
+ json=self.captcha_params.get_result_params.to_dict(),
78
+ )
79
+ if resp.status_code in VALID_STATUS_CODES:
80
+ result_data = CaptchaResponseSer(**resp.json())
81
+ if result_data.status in (ResponseStatusEnm.Ready, ResponseStatusEnm.Failed):
82
+ # if captcha ready\failed or have unknown status - return exist data
83
+ return result_data
84
+ else:
85
+ raise ValueError(resp.raise_for_status())
86
+ except Exception as error:
87
+ logging.exception(error)
88
+ raise
89
+
90
+ # if captcha just created or in processing now - wait
91
+ time.sleep(self.captcha_params.sleep_time)
92
+ # default response if server is silent
93
+ self.result.errorId = 1
94
+ self.result.errorCode = self.CAPTCHA_UNSOLVABLE
95
+ self.result.errorDescription = "Captcha not recognized"
96
+ self.result.taskId = self.created_task_data.taskId
97
+ self.result.status = ResponseStatusEnm.Failed
98
+
99
+ @staticmethod
100
+ def send_post_request(
101
+ payload: Optional[dict] = None,
102
+ session: requests.Session = requests.Session(),
103
+ url_postfix: str = GET_BALANCE_POSTFIX,
104
+ ) -> dict:
105
+ """
106
+ Function send SYNC request to service and wait for result
107
+ """
108
+ try:
109
+ resp = session.post(parse.urljoin(REQUEST_URL, url_postfix), json=payload)
110
+ if resp.status_code == 200:
111
+ return resp.json()
112
+ else:
113
+ raise ValueError(resp.status_code)
114
+ except Exception as error:
115
+ logging.exception(error)
116
+ raise
@@ -1,15 +1,6 @@
1
1
  from typing import Generator
2
2
 
3
- from tenacity import AsyncRetrying, wait_fixed, stop_after_attempt
4
- from requests.adapters import Retry
5
-
6
- RETRIES = Retry(total=5, backoff_factor=0.9, status_forcelist=[500, 502, 503, 504])
7
- ASYNC_RETRIES = AsyncRetrying(wait=wait_fixed(5), stop=stop_after_attempt(5), reraise=True)
8
-
9
- REQUEST_URL = "https://api.capsolver.com"
10
- VALID_STATUS_CODES = (200, 202, 400, 401, 405)
11
-
12
- APP_ID = "3E36E3CD-7EB5-4CAF-AA15-91011E652321"
3
+ __all__ = ("attempts_generator",)
13
4
 
14
5
 
15
6
  # Connection retry generator
@@ -1,103 +1,53 @@
1
1
  from typing import Union
2
2
 
3
- from python3_capsolver.core.base import BaseCaptcha
4
- from python3_capsolver.core.enum import DatadomeSliderTypeEnm
5
- from python3_capsolver.core.serializer import DatadomeSliderSer, CaptchaResponseSer
3
+ from .core.base import CaptchaParams
4
+ from .core.enum import CaptchaTypeEnm
6
5
 
7
6
 
8
- class DatadomeSlider(BaseCaptcha):
7
+ class DatadomeSlider(CaptchaParams):
9
8
  """
10
- The class is used to work with Capsolver DatadomeSlider method.
9
+ The class is used to work with Capsolver DatadomeSliderTask method.
11
10
 
12
11
  Args:
13
12
  api_key: Capsolver API key
14
- websiteURL: Address of the webpage
15
- captchaUrl: Captcha Url where is the captcha
16
- proxy: Proxy data
17
- userAgent: Browser's User-Agent which is used in emulation
13
+ captcha_type: Captcha type name, like ``DatadomeSliderTask`` and etc.
14
+ kwargs: additional params for client, like captcha waiting time
15
+ available keys:
16
+ - sleep_time: int - captcha solution waintig time in sec
17
+ - request_url: str - API address for sending requests,
18
+ else official will be used
18
19
 
19
20
  Examples:
20
- >>> DatadomeSlider(api_key="CAI-1324...",
21
- ... captcha_type=DatadomeSliderTypeEnm.DatadomeSliderTask,
22
- ... websiteURL="https://www.some-url.com/",
23
- ... captchaUrl="https://www.some-url.com/to-page-with-captcha",
24
- ... proxy="socks5:158.120.100.23:334:user:pass",
25
- ... userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
26
- ... ).captcha_handler()
27
- CaptchaResponseSer(errorId=0,
28
- errorCode=None,
29
- errorDescription=None,
30
- taskId='73bdcd28-6c77-4414-8....',
31
- status=<ResponseStatusEnm.Ready: 'ready'>,
32
- solution={'gRecaptchaResponse': '44795sds...'}
33
- )
34
-
35
- >>> await DatadomeSlider(api_key="CAI-1324...",
36
- ... captcha_type="DatadomeSliderTask",
37
- ... websiteURL="https://www.some-url.com/",
38
- ... captchaUrl="https://www.some-url.com/to-page-with-captcha",
39
- ... proxy="socks5:158.120.100.23:334:user:pass",
40
- ... userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
41
- ... ).aio_captcha_handler()
42
- CaptchaResponseSer(errorId=0,
43
- errorCode=None,
44
- errorDescription=None,
45
- taskId='73bdcd28-6c77-4414-8....',
46
- status=<ResponseStatusEnm.Ready: 'ready'>,
47
- solution={'gRecaptchaResponse': '44795sds...'}
48
- )
49
-
50
- Returns:
51
- CaptchaResponseSer model with full server response
21
+ >>> from python3_capsolver.datadome_slider import DatadomeSlider
22
+ >>> from python3_capsolver.core.enum import CaptchaTypeEnm
23
+ >>> DatadomeSlider(api_key="CAI-12345....",
24
+ ... captcha_type=CaptchaTypeEnm.DatadomeSliderTask)
25
+ ... .captcha_handler(task_payload={
26
+ ... "captchaUrl": "https://geo.captchaxxxxxx",
27
+ ... "userAgent": "Mozilla/5.0 xxxx",
28
+ ... "proxy": "0.0.0.0:334:user:pass"
29
+ ... })
30
+ {
31
+ "errorId":0,
32
+ "errorCode":"None",
33
+ "errorDescription":"None",
34
+ "taskId":"db0a3153-621d-4f5e-8554-a1c032597ee7",
35
+ "status":"ready",
36
+ "solution":{
37
+ "userAgent": "Mozilla/5.0 xxxx",
38
+ "cookie": "datadome=yzj_BK..xxxx"
39
+ }
40
+ }
52
41
 
53
42
  Notes:
54
- https://docs.capsolver.com/guide/antibots/datadome.html
43
+ https://docs.capsolver.com/en/guide/captcha/datadome/
55
44
  """
56
45
 
57
46
  def __init__(
58
47
  self,
59
- websiteURL: str,
60
- captchaUrl: str,
61
- userAgent: str,
62
- captcha_type: Union[DatadomeSliderTypeEnm, str] = DatadomeSliderTypeEnm.DatadomeSliderTask,
63
- *args,
48
+ api_key: str,
49
+ captcha_type: Union[CaptchaTypeEnm, str] = CaptchaTypeEnm.DatadomeSliderTask,
64
50
  **kwargs,
65
51
  ):
66
- super().__init__(*args, **kwargs)
67
-
68
- if captcha_type in DatadomeSliderTypeEnm.list():
69
- self.task_params = DatadomeSliderSer(**locals()).dict()
70
- else:
71
- raise ValueError(
72
- f"""Invalid `captcha_type` parameter set for `{self.__class__.__name__}`,
73
- available - {DatadomeSliderTypeEnm.list()}"""
74
- )
75
- for key in kwargs:
76
- self.task_params.update({key: kwargs[key]})
77
-
78
- def captcha_handler(self) -> CaptchaResponseSer:
79
- """
80
- Sync method for captcha solving
81
-
82
- Returns:
83
- CaptchaResponseSer model with full service response
84
-
85
- Notes:
86
- Check class docstring for more info
87
- """
88
- return self._processing_captcha(create_params=self.task_params)
89
-
90
- async def aio_captcha_handler(
91
- self,
92
- **additional_params,
93
- ) -> CaptchaResponseSer:
94
- """
95
- Async method for captcha solving
96
-
97
- Returns:
98
- CaptchaResponseSer model with full service response
99
52
 
100
- Notes:
101
- Check class docstring for more info
102
- """
103
- return await self._aio_processing_captcha(create_params=self.task_params)
53
+ super().__init__(api_key=api_key, captcha_type=captcha_type, **kwargs)
@@ -0,0 +1,69 @@
1
+ from typing import Union
2
+
3
+ from .core.base import CaptchaParams
4
+ from .core.enum import CaptchaTypeEnm
5
+
6
+ __all__ = ("FriendlyCaptcha",)
7
+
8
+
9
+ class FriendlyCaptcha(CaptchaParams):
10
+ """
11
+ The class is used to work with Capsolver FriendlyCaptchaTaskProxyless methods.
12
+
13
+ Args:
14
+ api_key: Capsolver API key
15
+ captcha_type: Captcha type name, like ``FriendlyCaptchaTaskProxyless`` and etc.
16
+ kwargs: additional params for client, like captcha waiting time
17
+ available keys:
18
+ - sleep_time: int - captcha solution waintig time in sec
19
+ - request_url: str - API address for sending requests,
20
+ else official will be used
21
+
22
+ Examples:
23
+ >>> from python3_capsolver.core.enum import CaptchaTypeEnm
24
+ >>> from python3_capsolver.friendly_captcha import FriendlyCaptcha
25
+ >>> FriendlyCaptcha(api_key="CAP-XXXXX",
26
+ ... captcha_type=CaptchaTypeEnm.FriendlyCaptchaTaskProxyless,
27
+ ... ).captcha_handler(task_payload={
28
+ ... "websiteURL": "https://www.yourwebsite.com",
29
+ ... "proxy": "ip:port:user:pass"
30
+ ... })
31
+ {
32
+ "errorId":0,
33
+ "errorCode":"None",
34
+ "errorDescription":"None",
35
+ "taskId":"db0a3153-621d-4f5e-8554-a1c032597ee7",
36
+ "status":"ready",
37
+ "solution":{
38
+ "cookies": "cf_clearance=_VPxxxx",
39
+ "headers": {
40
+ "sec-ch-ua": "\"Chromium\";v=\"130\", \"Google Chrome\";v=\"130\", \"Not?A_Brand\";v=\"99\"",
41
+ "sec-ch-ua-platform": "\"Windows\"",
42
+ "accept": "text/html,axxxx",
43
+ "User-Agent": "Mozilla/5.0xxxx",
44
+ "sec-ch-ua-mobile": "?0",
45
+ "sec-fetch-user": "?1",
46
+ "referer": "https://www.yourwebsite.com",
47
+ "Sec-Fetch-Dest": "document",
48
+ "Sec-Fetch-Mode": "navigate",
49
+ "Sec-Fetch-Site": "same-origin",
50
+ "accept-language": "en",
51
+ },
52
+ "page_url": "https://www.yourwebsite.com",
53
+ "proxy": "your proxyxxxx",
54
+ "token": "_VPCTZXP5bhinxxxx"
55
+ }
56
+ }
57
+
58
+ Notes:
59
+ https://docs.capsolver.com/en/guide/captcha/FriendlyCaptcha/
60
+ """
61
+
62
+ def __init__(
63
+ self,
64
+ api_key: str,
65
+ captcha_type: Union[CaptchaTypeEnm, str] = CaptchaTypeEnm.FriendlyCaptchaTaskProxyless,
66
+ **kwargs,
67
+ ):
68
+
69
+ super().__init__(api_key=api_key, captcha_type=captcha_type, **kwargs)