captcha-solver-api 1.0.0__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.
- captcha_solver_api/__init__.py +38 -0
- captcha_solver_api/_version.py +1 -0
- captcha_solver_api/async_client.py +248 -0
- captcha_solver_api/client.py +230 -0
- captcha_solver_api/exceptions.py +41 -0
- captcha_solver_api/py.typed +0 -0
- captcha_solver_api/tasks.py +705 -0
- captcha_solver_api-1.0.0.dist-info/METADATA +730 -0
- captcha_solver_api-1.0.0.dist-info/RECORD +12 -0
- captcha_solver_api-1.0.0.dist-info/WHEEL +5 -0
- captcha_solver_api-1.0.0.dist-info/licenses/LICENSE.md +21 -0
- captcha_solver_api-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,705 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task definitions for all supported CAPTCHA types.
|
|
3
|
+
|
|
4
|
+
Each class maps 1:1 to a `type` value accepted by the API's `createTask`
|
|
5
|
+
endpoint. Pass an instance to `CaptchaClient.solve()` (or `create_task()`);
|
|
6
|
+
`to_dict()` serializes it into the request body. Optional fields left as
|
|
7
|
+
`None` are omitted from the request rather than sent as `null`.
|
|
8
|
+
|
|
9
|
+
Every class's docstring lists the `solution` fields returned by `solve()`
|
|
10
|
+
once the task is `"ready"`.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any, Dict, List, Optional
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseTask:
|
|
19
|
+
"""Base class for all CAPTCHA tasks."""
|
|
20
|
+
|
|
21
|
+
type: str
|
|
22
|
+
|
|
23
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
24
|
+
"""Serializes the task to the dict shape expected by the `task` field
|
|
25
|
+
of `createTask`, dropping any fields left as `None`."""
|
|
26
|
+
result = {"type": self.type}
|
|
27
|
+
for key, value in self.__dict__.items():
|
|
28
|
+
if value is not None:
|
|
29
|
+
result[key] = value
|
|
30
|
+
return result
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ProxyMixin:
|
|
34
|
+
"""Mixin that adds proxy fields to a task.
|
|
35
|
+
|
|
36
|
+
Args (via `set_proxy`, or pass directly to the task's `__init__`):
|
|
37
|
+
proxy_type: `"http"`, `"socks4"`, or `"socks5"`.
|
|
38
|
+
proxy_address: Proxy IP address or hostname.
|
|
39
|
+
proxy_port: Proxy port.
|
|
40
|
+
proxy_login: Proxy auth username, if required.
|
|
41
|
+
proxy_password: Proxy auth password, if required.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
proxyType: str
|
|
45
|
+
proxyAddress: str
|
|
46
|
+
proxyPort: int
|
|
47
|
+
proxyLogin: Optional[str]
|
|
48
|
+
proxyPassword: Optional[str]
|
|
49
|
+
|
|
50
|
+
def set_proxy(
|
|
51
|
+
self,
|
|
52
|
+
proxy_type: str,
|
|
53
|
+
proxy_address: str,
|
|
54
|
+
proxy_port: int,
|
|
55
|
+
proxy_login: Optional[str] = None,
|
|
56
|
+
proxy_password: Optional[str] = None,
|
|
57
|
+
) -> None:
|
|
58
|
+
self.proxyType = proxy_type
|
|
59
|
+
self.proxyAddress = proxy_address
|
|
60
|
+
self.proxyPort = proxy_port
|
|
61
|
+
self.proxyLogin = proxy_login
|
|
62
|
+
self.proxyPassword = proxy_password
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class RecaptchaV2TaskProxyless(BaseTask):
|
|
66
|
+
"""reCAPTCHA v2 without proxy -- the service solves using its own IPs.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
websiteURL: Full URL of the page where the captcha is located.
|
|
70
|
+
websiteKey: Value of the widget's `data-sitekey` attribute.
|
|
71
|
+
isInvisible: `True` for invisible reCAPTCHA v2.
|
|
72
|
+
recaptchaDataSValue: The `data-s` value, found on Google Search/YouTube pages.
|
|
73
|
+
apiDomain: Non-default domain the widget's script is served from, if any.
|
|
74
|
+
userAgent: User-Agent to solve with. Recommended to match the agent that
|
|
75
|
+
will submit the resulting token.
|
|
76
|
+
cookies: Session cookies to use while solving, if the page requires them.
|
|
77
|
+
|
|
78
|
+
Returns (`solution` from `solve()`):
|
|
79
|
+
`gRecaptchaResponse` -- the token to submit as `g-recaptcha-response`.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
type = "RecaptchaV2TaskProxyless"
|
|
83
|
+
|
|
84
|
+
def __init__(
|
|
85
|
+
self,
|
|
86
|
+
websiteURL: str,
|
|
87
|
+
websiteKey: str,
|
|
88
|
+
isInvisible: Optional[bool] = None,
|
|
89
|
+
recaptchaDataSValue: Optional[str] = None,
|
|
90
|
+
apiDomain: Optional[str] = None,
|
|
91
|
+
userAgent: Optional[str] = None,
|
|
92
|
+
cookies: Optional[str] = None,
|
|
93
|
+
) -> None:
|
|
94
|
+
self.websiteURL = websiteURL
|
|
95
|
+
self.websiteKey = websiteKey
|
|
96
|
+
self.isInvisible = isInvisible
|
|
97
|
+
self.recaptchaDataSValue = recaptchaDataSValue
|
|
98
|
+
self.apiDomain = apiDomain
|
|
99
|
+
self.userAgent = userAgent
|
|
100
|
+
self.cookies = cookies
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class RecaptchaV2Task(BaseTask, ProxyMixin):
|
|
104
|
+
"""reCAPTCHA v2 solved through your own proxy.
|
|
105
|
+
|
|
106
|
+
Use this instead of `RecaptchaV2TaskProxyless` when the target site is
|
|
107
|
+
geo-restricted or you need the solving session to share an IP with the
|
|
108
|
+
browser/bot that will submit the token.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
websiteURL: Full URL of the page where the captcha is located.
|
|
112
|
+
websiteKey: Value of the widget's `data-sitekey` attribute.
|
|
113
|
+
proxyType: `"http"`, `"socks4"`, or `"socks5"`.
|
|
114
|
+
proxyAddress: Proxy IP address or hostname.
|
|
115
|
+
proxyPort: Proxy port.
|
|
116
|
+
proxyLogin: Proxy auth username, if required.
|
|
117
|
+
proxyPassword: Proxy auth password, if required.
|
|
118
|
+
isInvisible: `True` for invisible reCAPTCHA v2.
|
|
119
|
+
recaptchaDataSValue: The `data-s` value, found on Google Search/YouTube pages.
|
|
120
|
+
apiDomain: Non-default domain the widget's script is served from, if any.
|
|
121
|
+
userAgent: User-Agent to solve with.
|
|
122
|
+
cookies: Session cookies to use while solving, if the page requires them.
|
|
123
|
+
|
|
124
|
+
Returns (`solution` from `solve()`):
|
|
125
|
+
`gRecaptchaResponse` -- the token to submit as `g-recaptcha-response`.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
type = "RecaptchaV2Task"
|
|
129
|
+
|
|
130
|
+
def __init__(
|
|
131
|
+
self,
|
|
132
|
+
websiteURL: str,
|
|
133
|
+
websiteKey: str,
|
|
134
|
+
proxyType: str,
|
|
135
|
+
proxyAddress: str,
|
|
136
|
+
proxyPort: int,
|
|
137
|
+
proxyLogin: Optional[str] = None,
|
|
138
|
+
proxyPassword: Optional[str] = None,
|
|
139
|
+
isInvisible: Optional[bool] = None,
|
|
140
|
+
recaptchaDataSValue: Optional[str] = None,
|
|
141
|
+
apiDomain: Optional[str] = None,
|
|
142
|
+
userAgent: Optional[str] = None,
|
|
143
|
+
cookies: Optional[str] = None,
|
|
144
|
+
) -> None:
|
|
145
|
+
self.websiteURL = websiteURL
|
|
146
|
+
self.websiteKey = websiteKey
|
|
147
|
+
self.proxyType = proxyType
|
|
148
|
+
self.proxyAddress = proxyAddress
|
|
149
|
+
self.proxyPort = proxyPort
|
|
150
|
+
self.proxyLogin = proxyLogin
|
|
151
|
+
self.proxyPassword = proxyPassword
|
|
152
|
+
self.isInvisible = isInvisible
|
|
153
|
+
self.recaptchaDataSValue = recaptchaDataSValue
|
|
154
|
+
self.apiDomain = apiDomain
|
|
155
|
+
self.userAgent = userAgent
|
|
156
|
+
self.cookies = cookies
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class RecaptchaV2EnterpriseTaskProxyless(BaseTask):
|
|
160
|
+
"""reCAPTCHA v2 Enterprise without proxy.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
websiteURL: Full URL of the page where the captcha is located.
|
|
164
|
+
websiteKey: Value of the widget's `data-sitekey` attribute.
|
|
165
|
+
enterprisePayload: Extra parameters passed to `grecaptcha.enterprise.render`
|
|
166
|
+
on the page, if any (e.g. `{"s": "..."}`).
|
|
167
|
+
isInvisible: `True` for invisible reCAPTCHA v2 Enterprise.
|
|
168
|
+
apiDomain: Non-default domain, defaults to `google.com`.
|
|
169
|
+
userAgent: User-Agent to solve with.
|
|
170
|
+
cookies: Session cookies to use while solving, if the page requires them.
|
|
171
|
+
|
|
172
|
+
Returns (`solution` from `solve()`):
|
|
173
|
+
`gRecaptchaResponse` -- the token to submit as `g-recaptcha-response`.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
type = "RecaptchaV2EnterpriseTaskProxyless"
|
|
177
|
+
|
|
178
|
+
def __init__(
|
|
179
|
+
self,
|
|
180
|
+
websiteURL: str,
|
|
181
|
+
websiteKey: str,
|
|
182
|
+
enterprisePayload: Optional[Dict[str, Any]] = None,
|
|
183
|
+
isInvisible: Optional[bool] = None,
|
|
184
|
+
apiDomain: Optional[str] = None,
|
|
185
|
+
userAgent: Optional[str] = None,
|
|
186
|
+
cookies: Optional[str] = None,
|
|
187
|
+
) -> None:
|
|
188
|
+
self.websiteURL = websiteURL
|
|
189
|
+
self.websiteKey = websiteKey
|
|
190
|
+
self.enterprisePayload = enterprisePayload
|
|
191
|
+
self.isInvisible = isInvisible
|
|
192
|
+
self.apiDomain = apiDomain
|
|
193
|
+
self.userAgent = userAgent
|
|
194
|
+
self.cookies = cookies
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class RecaptchaV2EnterpriseTask(BaseTask, ProxyMixin):
|
|
198
|
+
"""reCAPTCHA v2 Enterprise solved through your own proxy.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
websiteURL: Full URL of the page where the captcha is located.
|
|
202
|
+
websiteKey: Value of the widget's `data-sitekey` attribute.
|
|
203
|
+
proxyType: `"http"`, `"socks4"`, or `"socks5"`.
|
|
204
|
+
proxyAddress: Proxy IP address or hostname.
|
|
205
|
+
proxyPort: Proxy port.
|
|
206
|
+
proxyLogin: Proxy auth username, if required.
|
|
207
|
+
proxyPassword: Proxy auth password, if required.
|
|
208
|
+
enterprisePayload: Extra parameters passed to `grecaptcha.enterprise.render`
|
|
209
|
+
on the page, if any (e.g. `{"s": "..."}`).
|
|
210
|
+
isInvisible: `True` for invisible reCAPTCHA v2 Enterprise.
|
|
211
|
+
apiDomain: Non-default domain, defaults to `google.com`.
|
|
212
|
+
userAgent: User-Agent to solve with.
|
|
213
|
+
cookies: Session cookies to use while solving, if the page requires them.
|
|
214
|
+
|
|
215
|
+
Returns (`solution` from `solve()`):
|
|
216
|
+
`gRecaptchaResponse` -- the token to submit as `g-recaptcha-response`.
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
type = "RecaptchaV2EnterpriseTask"
|
|
220
|
+
|
|
221
|
+
def __init__(
|
|
222
|
+
self,
|
|
223
|
+
websiteURL: str,
|
|
224
|
+
websiteKey: str,
|
|
225
|
+
proxyType: str,
|
|
226
|
+
proxyAddress: str,
|
|
227
|
+
proxyPort: int,
|
|
228
|
+
proxyLogin: Optional[str] = None,
|
|
229
|
+
proxyPassword: Optional[str] = None,
|
|
230
|
+
enterprisePayload: Optional[Dict[str, Any]] = None,
|
|
231
|
+
isInvisible: Optional[bool] = None,
|
|
232
|
+
apiDomain: Optional[str] = None,
|
|
233
|
+
userAgent: Optional[str] = None,
|
|
234
|
+
cookies: Optional[str] = None,
|
|
235
|
+
) -> None:
|
|
236
|
+
self.websiteURL = websiteURL
|
|
237
|
+
self.websiteKey = websiteKey
|
|
238
|
+
self.proxyType = proxyType
|
|
239
|
+
self.proxyAddress = proxyAddress
|
|
240
|
+
self.proxyPort = proxyPort
|
|
241
|
+
self.proxyLogin = proxyLogin
|
|
242
|
+
self.proxyPassword = proxyPassword
|
|
243
|
+
self.enterprisePayload = enterprisePayload
|
|
244
|
+
self.isInvisible = isInvisible
|
|
245
|
+
self.apiDomain = apiDomain
|
|
246
|
+
self.userAgent = userAgent
|
|
247
|
+
self.cookies = cookies
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class RecaptchaV3TaskProxyless(BaseTask):
|
|
251
|
+
"""reCAPTCHA v3. No proxy variant exists for this type -- v3 is score-based
|
|
252
|
+
and invisible, so there's no widget/session to keep pinned to a proxy IP.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
websiteURL: Full URL of the page where the captcha is located.
|
|
256
|
+
websiteKey: Site key for the v3 widget.
|
|
257
|
+
minScore: Minimum acceptable token score to return, e.g. `0.3`, `0.7`, `0.9`.
|
|
258
|
+
pageAction: The `action` parameter passed to `grecaptcha.execute()` on the page.
|
|
259
|
+
isEnterprise: `True` if this is reCAPTCHA v3 Enterprise.
|
|
260
|
+
apiDomain: Non-standard domain the widget's script is served from, if any.
|
|
261
|
+
|
|
262
|
+
Returns (`solution` from `solve()`):
|
|
263
|
+
`gRecaptchaResponse` -- the token to submit as `g-recaptcha-response`.
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
type = "RecaptchaV3TaskProxyless"
|
|
267
|
+
|
|
268
|
+
def __init__(
|
|
269
|
+
self,
|
|
270
|
+
websiteURL: str,
|
|
271
|
+
websiteKey: str,
|
|
272
|
+
minScore: float,
|
|
273
|
+
pageAction: Optional[str] = None,
|
|
274
|
+
isEnterprise: Optional[bool] = None,
|
|
275
|
+
apiDomain: Optional[str] = None,
|
|
276
|
+
) -> None:
|
|
277
|
+
self.websiteURL = websiteURL
|
|
278
|
+
self.websiteKey = websiteKey
|
|
279
|
+
self.minScore = minScore
|
|
280
|
+
self.pageAction = pageAction
|
|
281
|
+
self.isEnterprise = isEnterprise
|
|
282
|
+
self.apiDomain = apiDomain
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class TurnstileTaskProxyless(BaseTask):
|
|
286
|
+
"""Cloudflare Turnstile without proxy.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
websiteURL: Full URL of the page where the widget is located.
|
|
290
|
+
websiteKey: Value of the widget's `data-sitekey` attribute.
|
|
291
|
+
action: Value of the widget's `data-action` attribute, if set.
|
|
292
|
+
data: Custom payload from the widget's `data-cdata` attribute, if set.
|
|
293
|
+
pagedata: Value of the `chlPageData` parameter, needed for some Cloudflare
|
|
294
|
+
challenge pages beyond the basic widget. Named lowercase (not `pageData`)
|
|
295
|
+
to match the API field name exactly -- Cloudflare-specific fields are
|
|
296
|
+
the one place this API doesn't camelCase.
|
|
297
|
+
userAgent: User-Agent to solve with. The returned token is tied to it --
|
|
298
|
+
submit it with the same User-Agent.
|
|
299
|
+
|
|
300
|
+
Returns (`solution` from `solve()`):
|
|
301
|
+
`token` -- the value to submit as `cf-turnstile-response`.
|
|
302
|
+
"""
|
|
303
|
+
|
|
304
|
+
type = "TurnstileTaskProxyless"
|
|
305
|
+
|
|
306
|
+
def __init__(
|
|
307
|
+
self,
|
|
308
|
+
websiteURL: str,
|
|
309
|
+
websiteKey: str,
|
|
310
|
+
action: Optional[str] = None,
|
|
311
|
+
data: Optional[str] = None,
|
|
312
|
+
pagedata: Optional[str] = None,
|
|
313
|
+
userAgent: Optional[str] = None,
|
|
314
|
+
) -> None:
|
|
315
|
+
self.websiteURL = websiteURL
|
|
316
|
+
self.websiteKey = websiteKey
|
|
317
|
+
self.action = action
|
|
318
|
+
self.data = data
|
|
319
|
+
self.pagedata = pagedata
|
|
320
|
+
self.userAgent = userAgent
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class TurnstileTask(BaseTask, ProxyMixin):
|
|
324
|
+
"""Cloudflare Turnstile solved through your own proxy.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
websiteURL: Full URL of the page where the widget is located.
|
|
328
|
+
websiteKey: Value of the widget's `data-sitekey` attribute.
|
|
329
|
+
proxyType: `"http"`, `"socks4"`, or `"socks5"`.
|
|
330
|
+
proxyAddress: Proxy IP address or hostname.
|
|
331
|
+
proxyPort: Proxy port.
|
|
332
|
+
proxyLogin: Proxy auth username, if required.
|
|
333
|
+
proxyPassword: Proxy auth password, if required.
|
|
334
|
+
action: Value of the widget's `data-action` attribute, if set.
|
|
335
|
+
data: Custom payload from the widget's `data-cdata` attribute, if set.
|
|
336
|
+
pagedata: Value of the `chlPageData` parameter, needed for some Cloudflare
|
|
337
|
+
challenge pages beyond the basic widget. Named lowercase (not `pageData`)
|
|
338
|
+
to match the API field name exactly.
|
|
339
|
+
userAgent: User-Agent to solve with. The returned token is tied to it.
|
|
340
|
+
|
|
341
|
+
Returns (`solution` from `solve()`):
|
|
342
|
+
`token` -- the value to submit as `cf-turnstile-response`.
|
|
343
|
+
"""
|
|
344
|
+
|
|
345
|
+
type = "TurnstileTask"
|
|
346
|
+
|
|
347
|
+
def __init__(
|
|
348
|
+
self,
|
|
349
|
+
websiteURL: str,
|
|
350
|
+
websiteKey: str,
|
|
351
|
+
proxyType: str,
|
|
352
|
+
proxyAddress: str,
|
|
353
|
+
proxyPort: int,
|
|
354
|
+
proxyLogin: Optional[str] = None,
|
|
355
|
+
proxyPassword: Optional[str] = None,
|
|
356
|
+
action: Optional[str] = None,
|
|
357
|
+
data: Optional[str] = None,
|
|
358
|
+
pagedata: Optional[str] = None,
|
|
359
|
+
userAgent: Optional[str] = None,
|
|
360
|
+
) -> None:
|
|
361
|
+
self.websiteURL = websiteURL
|
|
362
|
+
self.websiteKey = websiteKey
|
|
363
|
+
self.proxyType = proxyType
|
|
364
|
+
self.proxyAddress = proxyAddress
|
|
365
|
+
self.proxyPort = proxyPort
|
|
366
|
+
self.proxyLogin = proxyLogin
|
|
367
|
+
self.proxyPassword = proxyPassword
|
|
368
|
+
self.action = action
|
|
369
|
+
self.data = data
|
|
370
|
+
self.pagedata = pagedata
|
|
371
|
+
self.userAgent = userAgent
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
class ImageToTextTask(BaseTask):
|
|
375
|
+
"""Image-to-text recognition for classic distorted-text/number captchas.
|
|
376
|
+
No proxy variant exists -- the image is submitted directly, no browser
|
|
377
|
+
session or target site is involved.
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
body: The captcha image, base64-encoded (no `data:image/...;base64,` prefix).
|
|
381
|
+
phrase: `True` if the answer is multiple words.
|
|
382
|
+
case: `True` if the answer is case-sensitive.
|
|
383
|
+
numeric: Character set hint -- `0` unspecified, `1` digits only, `2` letters
|
|
384
|
+
only, `3` any with digits, `4` any with letters.
|
|
385
|
+
math: `True` if the image contains a math expression to evaluate rather
|
|
386
|
+
than text to transcribe.
|
|
387
|
+
minLength: Minimum expected answer length.
|
|
388
|
+
maxLength: Maximum expected answer length.
|
|
389
|
+
comment: Free-text hint for the worker (e.g. what kind of answer is expected).
|
|
390
|
+
imgInstructions: Optional supplementary instruction image, base64-encoded.
|
|
391
|
+
|
|
392
|
+
Returns (`solution` from `solve()`):
|
|
393
|
+
`text` -- the recognized text/answer.
|
|
394
|
+
"""
|
|
395
|
+
|
|
396
|
+
type = "ImageToTextTask"
|
|
397
|
+
|
|
398
|
+
def __init__(
|
|
399
|
+
self,
|
|
400
|
+
body: str,
|
|
401
|
+
phrase: Optional[bool] = None,
|
|
402
|
+
case: Optional[bool] = None,
|
|
403
|
+
numeric: Optional[int] = None,
|
|
404
|
+
math: Optional[bool] = None,
|
|
405
|
+
minLength: Optional[int] = None,
|
|
406
|
+
maxLength: Optional[int] = None,
|
|
407
|
+
comment: Optional[str] = None,
|
|
408
|
+
imgInstructions: Optional[str] = None,
|
|
409
|
+
) -> None:
|
|
410
|
+
self.body = body
|
|
411
|
+
self.phrase = phrase
|
|
412
|
+
self.case = case
|
|
413
|
+
self.numeric = numeric
|
|
414
|
+
self.math = math
|
|
415
|
+
self.minLength = minLength
|
|
416
|
+
self.maxLength = maxLength
|
|
417
|
+
self.comment = comment
|
|
418
|
+
self.imgInstructions = imgInstructions
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
class GeeTestTaskProxyless(BaseTask):
|
|
422
|
+
"""GeeTest v3 or v4 without proxy. Set `version=4` for v4 (and provide
|
|
423
|
+
`initParameters["captcha_id"]`); v3 is the default and needs `gt`/`challenge`
|
|
424
|
+
instead.
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
websiteURL: Full URL of the page where the widget is located.
|
|
428
|
+
version: `3` (default) or `4`.
|
|
429
|
+
gt: Public key of the GeeTest widget. Required for v3.
|
|
430
|
+
challenge: Session-specific challenge value from the page. Required for
|
|
431
|
+
v3, and must be freshly fetched for every request -- it cannot be reused.
|
|
432
|
+
initParameters: Extra parameters from the page's `initGeetest` call. For
|
|
433
|
+
v4, must contain `captcha_id`.
|
|
434
|
+
geetestApiServerSubdomain: Custom GeeTest API subdomain, if the site uses one.
|
|
435
|
+
userAgent: User-Agent to solve with.
|
|
436
|
+
risk_type: Value of the `risk_type` parameter from the captcha-loading
|
|
437
|
+
request, if present. Dynamic, single-use, and time-limited.
|
|
438
|
+
|
|
439
|
+
Returns (`solution` from `solve()`):
|
|
440
|
+
v3: `challenge`, `validate`, `seccode`.
|
|
441
|
+
v4: `captcha_id`, `lot_number`, `pass_token`, `gen_time`, `captcha_output`.
|
|
442
|
+
"""
|
|
443
|
+
|
|
444
|
+
type = "GeeTestTaskProxyless"
|
|
445
|
+
|
|
446
|
+
def __init__(
|
|
447
|
+
self,
|
|
448
|
+
websiteURL: str,
|
|
449
|
+
version: Optional[int] = None,
|
|
450
|
+
gt: Optional[str] = None,
|
|
451
|
+
challenge: Optional[str] = None,
|
|
452
|
+
initParameters: Optional[Dict[str, Any]] = None,
|
|
453
|
+
geetestApiServerSubdomain: Optional[str] = None,
|
|
454
|
+
userAgent: Optional[str] = None,
|
|
455
|
+
risk_type: Optional[str] = None,
|
|
456
|
+
) -> None:
|
|
457
|
+
self.websiteURL = websiteURL
|
|
458
|
+
self.version = version
|
|
459
|
+
self.gt = gt
|
|
460
|
+
self.challenge = challenge
|
|
461
|
+
self.initParameters = initParameters
|
|
462
|
+
self.geetestApiServerSubdomain = geetestApiServerSubdomain
|
|
463
|
+
self.userAgent = userAgent
|
|
464
|
+
self.risk_type = risk_type
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
class GeeTestTask(BaseTask, ProxyMixin):
|
|
468
|
+
"""GeeTest v3 or v4 solved through your own proxy. See `GeeTestTaskProxyless`
|
|
469
|
+
for the version-specific fields.
|
|
470
|
+
|
|
471
|
+
Args:
|
|
472
|
+
websiteURL: Full URL of the page where the widget is located.
|
|
473
|
+
proxyType: `"http"`, `"socks4"`, or `"socks5"`.
|
|
474
|
+
proxyAddress: Proxy IP address or hostname.
|
|
475
|
+
proxyPort: Proxy port.
|
|
476
|
+
proxyLogin: Proxy auth username, if required.
|
|
477
|
+
proxyPassword: Proxy auth password, if required.
|
|
478
|
+
version: `3` (default) or `4`.
|
|
479
|
+
gt: Public key of the GeeTest widget. Required for v3.
|
|
480
|
+
challenge: Session-specific challenge value from the page, must be fresh.
|
|
481
|
+
Required for v3.
|
|
482
|
+
initParameters: Extra parameters from the page's `initGeetest` call. For
|
|
483
|
+
v4, must contain `captcha_id`.
|
|
484
|
+
geetestApiServerSubdomain: Custom GeeTest API subdomain, if the site uses one.
|
|
485
|
+
userAgent: User-Agent to solve with.
|
|
486
|
+
risk_type: Value of the `risk_type` parameter from the captcha-loading
|
|
487
|
+
request, if present. Dynamic, single-use, and time-limited.
|
|
488
|
+
|
|
489
|
+
Returns (`solution` from `solve()`):
|
|
490
|
+
v3: `challenge`, `validate`, `seccode`.
|
|
491
|
+
v4: `captcha_id`, `lot_number`, `pass_token`, `gen_time`, `captcha_output`.
|
|
492
|
+
"""
|
|
493
|
+
|
|
494
|
+
type = "GeeTestTask"
|
|
495
|
+
|
|
496
|
+
def __init__(
|
|
497
|
+
self,
|
|
498
|
+
websiteURL: str,
|
|
499
|
+
proxyType: str,
|
|
500
|
+
proxyAddress: str,
|
|
501
|
+
proxyPort: int,
|
|
502
|
+
proxyLogin: Optional[str] = None,
|
|
503
|
+
proxyPassword: Optional[str] = None,
|
|
504
|
+
version: Optional[int] = None,
|
|
505
|
+
gt: Optional[str] = None,
|
|
506
|
+
challenge: Optional[str] = None,
|
|
507
|
+
initParameters: Optional[Dict[str, Any]] = None,
|
|
508
|
+
geetestApiServerSubdomain: Optional[str] = None,
|
|
509
|
+
userAgent: Optional[str] = None,
|
|
510
|
+
risk_type: Optional[str] = None,
|
|
511
|
+
) -> None:
|
|
512
|
+
self.websiteURL = websiteURL
|
|
513
|
+
self.proxyType = proxyType
|
|
514
|
+
self.proxyAddress = proxyAddress
|
|
515
|
+
self.proxyPort = proxyPort
|
|
516
|
+
self.proxyLogin = proxyLogin
|
|
517
|
+
self.proxyPassword = proxyPassword
|
|
518
|
+
self.version = version
|
|
519
|
+
self.gt = gt
|
|
520
|
+
self.challenge = challenge
|
|
521
|
+
self.initParameters = initParameters
|
|
522
|
+
self.geetestApiServerSubdomain = geetestApiServerSubdomain
|
|
523
|
+
self.userAgent = userAgent
|
|
524
|
+
self.risk_type = risk_type
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
class YandexSmartCaptchaTaskProxyless(BaseTask):
|
|
528
|
+
"""Yandex SmartCaptcha (token challenge) without proxy. For the image
|
|
529
|
+
challenge instead, use `CoordinatesTask` with `imgType="smart_captcha"`.
|
|
530
|
+
|
|
531
|
+
Args:
|
|
532
|
+
websiteURL: Full URL of the page where the widget is located.
|
|
533
|
+
websiteKey: The `sitekey` value from the page source or captcha iframe.
|
|
534
|
+
userAgent: User-Agent to solve with.
|
|
535
|
+
cookies: Session cookies to use while solving, if the page requires them.
|
|
536
|
+
|
|
537
|
+
Returns (`solution` from `solve()`):
|
|
538
|
+
`token` -- the value to submit as the SmartCaptcha response token.
|
|
539
|
+
"""
|
|
540
|
+
|
|
541
|
+
type = "YandexSmartCaptchaTaskProxyless"
|
|
542
|
+
|
|
543
|
+
def __init__(
|
|
544
|
+
self,
|
|
545
|
+
websiteURL: str,
|
|
546
|
+
websiteKey: str,
|
|
547
|
+
userAgent: Optional[str] = None,
|
|
548
|
+
cookies: Optional[str] = None,
|
|
549
|
+
) -> None:
|
|
550
|
+
self.websiteURL = websiteURL
|
|
551
|
+
self.websiteKey = websiteKey
|
|
552
|
+
self.userAgent = userAgent
|
|
553
|
+
self.cookies = cookies
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
class YandexSmartCaptchaTask(BaseTask, ProxyMixin):
|
|
557
|
+
"""Yandex SmartCaptcha (token challenge) solved through your own proxy.
|
|
558
|
+
|
|
559
|
+
Args:
|
|
560
|
+
websiteURL: Full URL of the page where the widget is located.
|
|
561
|
+
websiteKey: The `sitekey` value from the page source or captcha iframe.
|
|
562
|
+
proxyType: `"http"`, `"socks4"`, or `"socks5"`.
|
|
563
|
+
proxyAddress: Proxy IP address or hostname.
|
|
564
|
+
proxyPort: Proxy port.
|
|
565
|
+
proxyLogin: Proxy auth username, if required.
|
|
566
|
+
proxyPassword: Proxy auth password, if required.
|
|
567
|
+
userAgent: User-Agent to solve with.
|
|
568
|
+
cookies: Session cookies to use while solving, if the page requires them.
|
|
569
|
+
|
|
570
|
+
Returns (`solution` from `solve()`):
|
|
571
|
+
`token` -- the value to submit as the SmartCaptcha response token.
|
|
572
|
+
"""
|
|
573
|
+
|
|
574
|
+
type = "YandexSmartCaptchaTask"
|
|
575
|
+
|
|
576
|
+
def __init__(
|
|
577
|
+
self,
|
|
578
|
+
websiteURL: str,
|
|
579
|
+
websiteKey: str,
|
|
580
|
+
proxyType: str,
|
|
581
|
+
proxyAddress: str,
|
|
582
|
+
proxyPort: int,
|
|
583
|
+
proxyLogin: Optional[str] = None,
|
|
584
|
+
proxyPassword: Optional[str] = None,
|
|
585
|
+
userAgent: Optional[str] = None,
|
|
586
|
+
cookies: Optional[str] = None,
|
|
587
|
+
) -> None:
|
|
588
|
+
self.websiteURL = websiteURL
|
|
589
|
+
self.websiteKey = websiteKey
|
|
590
|
+
self.proxyType = proxyType
|
|
591
|
+
self.proxyAddress = proxyAddress
|
|
592
|
+
self.proxyPort = proxyPort
|
|
593
|
+
self.proxyLogin = proxyLogin
|
|
594
|
+
self.proxyPassword = proxyPassword
|
|
595
|
+
self.userAgent = userAgent
|
|
596
|
+
self.cookies = cookies
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
class CoordinatesTask(BaseTask):
|
|
600
|
+
"""Coordinate-based (click) image captcha. Used both for generic
|
|
601
|
+
"click on X" captchas and for Yandex SmartCaptcha's image challenge (set
|
|
602
|
+
`imgType` accordingly). No proxy variant -- the image is submitted directly.
|
|
603
|
+
|
|
604
|
+
Args:
|
|
605
|
+
body: The captcha image, base64-encoded (no `data:image/...;base64,` prefix).
|
|
606
|
+
comment: Hint for the worker, e.g. `"click on the green apple"`. Recommended
|
|
607
|
+
for generic click captchas.
|
|
608
|
+
imgInstructions: Optional instruction image, base64-encoded, showing what
|
|
609
|
+
to click and in what order. Required when `imgType="smart_captcha"`.
|
|
610
|
+
minClicks: Minimum number of clicks expected (default `1`).
|
|
611
|
+
maxClicks: Maximum number of clicks allowed.
|
|
612
|
+
imgType: Set to `"smart_captcha"` to solve a Yandex SmartCaptcha image
|
|
613
|
+
challenge instead of a generic click captcha.
|
|
614
|
+
|
|
615
|
+
Returns (`solution` from `solve()`):
|
|
616
|
+
`coordinates` -- a list of `{"x": int, "y": int}` pixel positions to click,
|
|
617
|
+
in order.
|
|
618
|
+
"""
|
|
619
|
+
|
|
620
|
+
type = "CoordinatesTask"
|
|
621
|
+
|
|
622
|
+
def __init__(
|
|
623
|
+
self,
|
|
624
|
+
body: str,
|
|
625
|
+
comment: Optional[str] = None,
|
|
626
|
+
imgInstructions: Optional[str] = None,
|
|
627
|
+
minClicks: Optional[int] = None,
|
|
628
|
+
maxClicks: Optional[int] = None,
|
|
629
|
+
imgType: Optional[str] = None,
|
|
630
|
+
) -> None:
|
|
631
|
+
self.body = body
|
|
632
|
+
self.comment = comment
|
|
633
|
+
self.imgInstructions = imgInstructions
|
|
634
|
+
self.minClicks = minClicks
|
|
635
|
+
self.maxClicks = maxClicks
|
|
636
|
+
self.imgType = imgType
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
class TencentTaskProxyless(BaseTask):
|
|
640
|
+
"""Tencent captcha without proxy.
|
|
641
|
+
|
|
642
|
+
Args:
|
|
643
|
+
websiteURL: Full URL of the page where the captcha is located.
|
|
644
|
+
appId: Value of the `appId` parameter found in the page source.
|
|
645
|
+
captchaScript: URL of the Tencent captcha script, if the page uses a
|
|
646
|
+
non-default one.
|
|
647
|
+
|
|
648
|
+
Returns (`solution` from `solve()`):
|
|
649
|
+
`appid`, `ret`, `ticket`, `randstr` -- pass these to the page's Tencent
|
|
650
|
+
captcha callback.
|
|
651
|
+
"""
|
|
652
|
+
|
|
653
|
+
type = "TencentTaskProxyless"
|
|
654
|
+
|
|
655
|
+
def __init__(
|
|
656
|
+
self,
|
|
657
|
+
websiteURL: str,
|
|
658
|
+
appId: str,
|
|
659
|
+
captchaScript: Optional[str] = None,
|
|
660
|
+
) -> None:
|
|
661
|
+
self.websiteURL = websiteURL
|
|
662
|
+
self.appId = appId
|
|
663
|
+
self.captchaScript = captchaScript
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
class TencentTask(BaseTask, ProxyMixin):
|
|
667
|
+
"""Tencent captcha solved through your own proxy.
|
|
668
|
+
|
|
669
|
+
Args:
|
|
670
|
+
websiteURL: Full URL of the page where the captcha is located.
|
|
671
|
+
appId: Value of the `appId` parameter found in the page source.
|
|
672
|
+
proxyType: `"http"`, `"socks4"`, or `"socks5"`.
|
|
673
|
+
proxyAddress: Proxy IP address or hostname.
|
|
674
|
+
proxyPort: Proxy port.
|
|
675
|
+
proxyLogin: Proxy auth username, if required.
|
|
676
|
+
proxyPassword: Proxy auth password, if required.
|
|
677
|
+
captchaScript: URL of the Tencent captcha script, if the page uses a
|
|
678
|
+
non-default one.
|
|
679
|
+
|
|
680
|
+
Returns (`solution` from `solve()`):
|
|
681
|
+
`appid`, `ret`, `ticket`, `randstr` -- pass these to the page's Tencent
|
|
682
|
+
captcha callback.
|
|
683
|
+
"""
|
|
684
|
+
|
|
685
|
+
type = "TencentTask"
|
|
686
|
+
|
|
687
|
+
def __init__(
|
|
688
|
+
self,
|
|
689
|
+
websiteURL: str,
|
|
690
|
+
appId: str,
|
|
691
|
+
proxyType: str,
|
|
692
|
+
proxyAddress: str,
|
|
693
|
+
proxyPort: int,
|
|
694
|
+
proxyLogin: Optional[str] = None,
|
|
695
|
+
proxyPassword: Optional[str] = None,
|
|
696
|
+
captchaScript: Optional[str] = None,
|
|
697
|
+
) -> None:
|
|
698
|
+
self.websiteURL = websiteURL
|
|
699
|
+
self.appId = appId
|
|
700
|
+
self.proxyType = proxyType
|
|
701
|
+
self.proxyAddress = proxyAddress
|
|
702
|
+
self.proxyPort = proxyPort
|
|
703
|
+
self.proxyLogin = proxyLogin
|
|
704
|
+
self.proxyPassword = proxyPassword
|
|
705
|
+
self.captchaScript = captchaScript
|