anticaptchaofficial 1.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +442 -0
- data/lib/anticaptcha/client.rb +352 -0
- data/lib/anticaptcha/errors.rb +52 -0
- data/lib/anticaptcha/solution.rb +162 -0
- data/lib/anticaptcha/tasks.rb +318 -0
- data/lib/anticaptcha/version.rb +5 -0
- data/lib/anticaptcha.rb +33 -0
- metadata +57 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Anticaptcha
|
|
4
|
+
# Builds the "task" objects sent to the createTask API method.
|
|
5
|
+
#
|
|
6
|
+
# Every method validates what it can before anything leaves the process and
|
|
7
|
+
# raises {InvalidTaskError} on bad input. You normally do not call these
|
|
8
|
+
# directly, {Client} does it for you.
|
|
9
|
+
module Tasks
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
PROXY_TYPES = %w[http socks4 socks5].freeze
|
|
13
|
+
|
|
14
|
+
# Validates your proxy and turns it into the API's proxy* fields.
|
|
15
|
+
#
|
|
16
|
+
# @param proxy [Hash] :type, :address, :port, :login, :password
|
|
17
|
+
# @param with_type [Boolean] AntiBotCookieTask takes no proxyType
|
|
18
|
+
def proxy_fields(proxy, with_type: true)
|
|
19
|
+
raise InvalidTaskError, "proxy is required for a proxy-on task" if proxy.nil?
|
|
20
|
+
|
|
21
|
+
proxy = normalize(proxy)
|
|
22
|
+
address = proxy[:address].to_s
|
|
23
|
+
port = proxy[:port].to_i
|
|
24
|
+
type = (proxy[:type] || "http").to_s
|
|
25
|
+
|
|
26
|
+
raise InvalidTaskError, "proxy address is empty" if address.empty?
|
|
27
|
+
unless (1..65_535).cover?(port)
|
|
28
|
+
raise InvalidTaskError,
|
|
29
|
+
"proxy port #{proxy[:port].inspect} is out of range"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
unless PROXY_TYPES.include?(type)
|
|
33
|
+
raise InvalidTaskError, "proxy type must be one of #{PROXY_TYPES.join(", ")}, got #{type.inspect}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
fields = { "proxyAddress" => address, "proxyPort" => port }
|
|
37
|
+
fields["proxyType"] = type if with_type
|
|
38
|
+
|
|
39
|
+
login = proxy[:login].to_s
|
|
40
|
+
|
|
41
|
+
unless login.empty?
|
|
42
|
+
fields["proxyLogin"] = login
|
|
43
|
+
fields["proxyPassword"] = proxy[:password].to_s
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
fields
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# https://anti-captcha.com/apidoc/task-types/ImageToTextTask
|
|
50
|
+
def image(body:, phrase: false, case_sensitive: false, numeric: 0, math_operation: false,
|
|
51
|
+
min_length: 0, max_length: 0, language_pool: "en", comment: nil, website_url: nil)
|
|
52
|
+
raise InvalidTaskError, "captcha image is empty" if body.to_s.empty?
|
|
53
|
+
|
|
54
|
+
task = {
|
|
55
|
+
"type" => "ImageToTextTask",
|
|
56
|
+
"body" => body,
|
|
57
|
+
"phrase" => phrase,
|
|
58
|
+
"case" => case_sensitive,
|
|
59
|
+
"numeric" => numeric,
|
|
60
|
+
"math" => math_operation,
|
|
61
|
+
"minLength" => min_length,
|
|
62
|
+
"maxLength" => max_length,
|
|
63
|
+
"languagePool" => language_pool
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
put(task, "comment", comment)
|
|
67
|
+
put(task, "websiteURL", website_url)
|
|
68
|
+
|
|
69
|
+
task
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# https://anti-captcha.com/apidoc/task-types/ImageToCoordinatesTask
|
|
73
|
+
def image_to_coordinates(body:, mode: "points", comment: nil, website_url: nil)
|
|
74
|
+
raise InvalidTaskError, "captcha image is empty" if body.to_s.empty?
|
|
75
|
+
|
|
76
|
+
task = { "type" => "ImageToCoordinatesTask", "body" => body, "mode" => mode }
|
|
77
|
+
|
|
78
|
+
put(task, "comment", comment)
|
|
79
|
+
put(task, "websiteURL", website_url)
|
|
80
|
+
|
|
81
|
+
task
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# https://anti-captcha.com/apidoc/task-types/RecaptchaV2TaskProxyless
|
|
85
|
+
#
|
|
86
|
+
# Setting is_enterprise switches the task to RecaptchaV2EnterpriseTask.
|
|
87
|
+
# Enterprise tasks get isInvisible only when it is true.
|
|
88
|
+
def recaptcha_v2(website_url:, website_key:, website_s_token: nil, is_invisible: false,
|
|
89
|
+
data_s_value: nil, is_enterprise: false, enterprise_payload: nil,
|
|
90
|
+
api_domain: nil, user_agent: nil, proxy: nil)
|
|
91
|
+
type =
|
|
92
|
+
if is_enterprise
|
|
93
|
+
proxy ? "RecaptchaV2EnterpriseTask" : "RecaptchaV2EnterpriseTaskProxyless"
|
|
94
|
+
else
|
|
95
|
+
proxy ? "RecaptchaV2Task" : "RecaptchaV2TaskProxyless"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
task = {
|
|
99
|
+
"type" => type,
|
|
100
|
+
"websiteURL" => website_url,
|
|
101
|
+
"websiteKey" => website_key
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
task["isInvisible"] = is_invisible if !is_enterprise || is_invisible
|
|
105
|
+
put(task, "websiteSToken", website_s_token)
|
|
106
|
+
put(task, "recaptchaDataSValue", data_s_value)
|
|
107
|
+
put(task, "apiDomain", api_domain)
|
|
108
|
+
put(task, "enterprisePayload", enterprise_payload)
|
|
109
|
+
|
|
110
|
+
with_proxy(task, proxy, user_agent)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# https://anti-captcha.com/apidoc/task-types/RecaptchaV3TaskProxyless
|
|
114
|
+
# This captcha has no proxy-on version.
|
|
115
|
+
def recaptcha_v3(website_url:, website_key:, min_score: 0.3, page_action: nil,
|
|
116
|
+
is_enterprise: false, api_domain: nil)
|
|
117
|
+
unless [0.3, 0.7, 0.9].include?(min_score)
|
|
118
|
+
raise InvalidTaskError, "min_score must be one of 0.3, 0.7, 0.9; got #{min_score.inspect}"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
task = {
|
|
122
|
+
"type" => "RecaptchaV3TaskProxyless",
|
|
123
|
+
"websiteURL" => website_url,
|
|
124
|
+
"websiteKey" => website_key,
|
|
125
|
+
"minScore" => min_score,
|
|
126
|
+
"isEnterprise" => is_enterprise
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
put(task, "pageAction", page_action)
|
|
130
|
+
put(task, "apiDomain", api_domain)
|
|
131
|
+
|
|
132
|
+
task
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# https://anti-captcha.com/apidoc/task-types/HCaptchaTaskProxyless
|
|
136
|
+
def hcaptcha(website_url:, website_key:, is_invisible: false, is_enterprise: false,
|
|
137
|
+
enterprise_payload: nil, user_agent: nil, cookies: nil, proxy: nil)
|
|
138
|
+
task = {
|
|
139
|
+
"type" => proxy ? "HCaptchaTask" : "HCaptchaTaskProxyless",
|
|
140
|
+
"websiteURL" => website_url,
|
|
141
|
+
"websiteKey" => website_key,
|
|
142
|
+
"isInvisible" => is_invisible,
|
|
143
|
+
"isEnterprise" => is_enterprise
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
put(task, "enterprisePayload", enterprise_payload)
|
|
147
|
+
task = with_proxy(task, proxy, user_agent)
|
|
148
|
+
put(task, "cookies", cookies) if proxy
|
|
149
|
+
|
|
150
|
+
task
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# https://anti-captcha.com/apidoc/task-types/FunCaptchaTaskProxyless
|
|
154
|
+
def funcaptcha(website_url:, website_public_key:, api_subdomain: nil, data_blob: nil,
|
|
155
|
+
user_agent: nil, proxy: nil)
|
|
156
|
+
task = {
|
|
157
|
+
"type" => proxy ? "FunCaptchaTask" : "FunCaptchaTaskProxyless",
|
|
158
|
+
"websiteURL" => website_url,
|
|
159
|
+
"websitePublicKey" => website_public_key
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
put(task, "funcaptchaApiJSSubdomain", api_subdomain)
|
|
163
|
+
put(task, "data", data_blob)
|
|
164
|
+
|
|
165
|
+
with_proxy(task, proxy, user_agent)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# https://anti-captcha.com/apidoc/task-types/GeeTestTaskProxyless
|
|
169
|
+
def geetest(website_url:, gt:, version: 3, challenge: nil, api_subdomain: nil,
|
|
170
|
+
init_parameters: nil, user_agent: nil, proxy: nil)
|
|
171
|
+
unless [3, 4].include?(version)
|
|
172
|
+
raise InvalidTaskError, "GeeTest version must be 3 or 4, got #{version.inspect}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
raise InvalidTaskError, "GeeTest v3 requires a challenge value" if version == 3 && challenge.to_s.empty?
|
|
176
|
+
|
|
177
|
+
task = {
|
|
178
|
+
"type" => proxy ? "GeeTestTask" : "GeeTestTaskProxyless",
|
|
179
|
+
"websiteURL" => website_url,
|
|
180
|
+
"gt" => gt,
|
|
181
|
+
"version" => version
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
put(task, "challenge", challenge)
|
|
185
|
+
put(task, "geetestApiServerSubdomain", api_subdomain)
|
|
186
|
+
put(task, "initParameters", init_parameters)
|
|
187
|
+
|
|
188
|
+
with_proxy(task, proxy, user_agent)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# https://anti-captcha.com/apidoc/task-types/TurnstileTaskProxyless
|
|
192
|
+
def turnstile(website_url:, website_key:, action: nil, c_data: nil, chl_page_data: nil,
|
|
193
|
+
user_agent: nil, proxy: nil)
|
|
194
|
+
task = {
|
|
195
|
+
"type" => proxy ? "TurnstileTask" : "TurnstileTaskProxyless",
|
|
196
|
+
"websiteURL" => website_url,
|
|
197
|
+
"websiteKey" => website_key
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
put(task, "action", action)
|
|
201
|
+
put(task, "cData", c_data)
|
|
202
|
+
put(task, "chlPageData", chl_page_data)
|
|
203
|
+
|
|
204
|
+
with_proxy(task, proxy, user_agent)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# https://anti-captcha.com/apidoc/task-types/ProsopoTaskProxyless
|
|
208
|
+
def prosopo(website_url:, website_key:, user_agent: nil, proxy: nil)
|
|
209
|
+
sitekey_task(proxy ? "ProsopoTask" : "ProsopoTaskProxyless",
|
|
210
|
+
website_url, website_key, user_agent, proxy)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# https://anti-captcha.com/apidoc/task-types/FriendlyCaptchaTaskProxyless
|
|
214
|
+
def friendly_captcha(website_url:, website_key:, user_agent: nil, proxy: nil)
|
|
215
|
+
sitekey_task(proxy ? "FriendlyCaptchaTask" : "FriendlyCaptchaTaskProxyless",
|
|
216
|
+
website_url, website_key, user_agent, proxy)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# https://anti-captcha.com/apidoc/task-types/AltchaTaskProxyless
|
|
220
|
+
def altcha(website_url:, challenge_url: nil, challenge_json: nil, user_agent: nil, proxy: nil)
|
|
221
|
+
if challenge_url.to_s.empty? && challenge_json.to_s.empty?
|
|
222
|
+
raise InvalidTaskError, "set either challenge_url or challenge_json"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
task = {
|
|
226
|
+
"type" => proxy ? "AltchaTask" : "AltchaTaskProxyless",
|
|
227
|
+
"websiteURL" => website_url
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
put(task, "challengeURL", challenge_url)
|
|
231
|
+
put(task, "challengeJSON", challenge_json)
|
|
232
|
+
|
|
233
|
+
with_proxy(task, proxy, user_agent)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# https://anti-captcha.com/apidoc/task-types/AmazonTaskProxyless
|
|
237
|
+
def amazon(website_url:, website_key:, iv: nil, context: nil, captcha_script: nil,
|
|
238
|
+
challenge_script: nil, jsapi_script: nil, waf_type: nil, user_agent: nil,
|
|
239
|
+
proxy: nil)
|
|
240
|
+
task = {
|
|
241
|
+
"type" => proxy ? "AmazonTask" : "AmazonTaskProxyless",
|
|
242
|
+
"websiteURL" => website_url,
|
|
243
|
+
"websiteKey" => website_key
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
put(task, "wafType", waf_type)
|
|
247
|
+
put(task, "iv", iv)
|
|
248
|
+
put(task, "context", context)
|
|
249
|
+
put(task, "captchaScript", captcha_script)
|
|
250
|
+
put(task, "challengeScript", challenge_script)
|
|
251
|
+
put(task, "jsapiScript", jsapi_script)
|
|
252
|
+
|
|
253
|
+
with_proxy(task, proxy, user_agent)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# https://anti-captcha.com/apidoc/task-types/AntiGateTask
|
|
257
|
+
#
|
|
258
|
+
# The proxy is optional for this task type.
|
|
259
|
+
def antigate(website_url:, template_name:, variables: nil, domains_of_interest: nil,
|
|
260
|
+
proxy: nil)
|
|
261
|
+
task = {
|
|
262
|
+
"type" => "AntiGateTask",
|
|
263
|
+
"websiteURL" => website_url,
|
|
264
|
+
"templateName" => template_name
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
put(task, "variables", variables)
|
|
268
|
+
put(task, "domainsOfInterest", domains_of_interest)
|
|
269
|
+
|
|
270
|
+
task.merge!(proxy_fields(proxy)) if proxy
|
|
271
|
+
|
|
272
|
+
task
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# https://anti-captcha.com/apidoc/task-types/AntiBotCookieTask
|
|
276
|
+
#
|
|
277
|
+
# The proxy is required: the cookies are only valid for the IP address they
|
|
278
|
+
# were issued to. This task type takes no proxyType, only http proxies work.
|
|
279
|
+
def antibot_cookie(website_url:, proxy:)
|
|
280
|
+
{
|
|
281
|
+
"type" => "AntiBotCookieTask",
|
|
282
|
+
"websiteURL" => website_url
|
|
283
|
+
}.merge(proxy_fields(proxy, with_type: false))
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Prosopo and Friendly Captcha take exactly the same parameters.
|
|
287
|
+
def sitekey_task(type, website_url, website_key, user_agent, proxy)
|
|
288
|
+
task = { "type" => type, "websiteURL" => website_url, "websiteKey" => website_key }
|
|
289
|
+
|
|
290
|
+
with_proxy(task, proxy, user_agent)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Adds a parameter, skipping it when the caller left it unset.
|
|
294
|
+
def put(task, name, value)
|
|
295
|
+
return task if value.nil?
|
|
296
|
+
return task if value.respond_to?(:empty?) && value.empty?
|
|
297
|
+
|
|
298
|
+
task[name] = value
|
|
299
|
+
task
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def with_proxy(task, proxy, user_agent)
|
|
303
|
+
return task if proxy.nil?
|
|
304
|
+
|
|
305
|
+
task.merge!(proxy_fields(proxy))
|
|
306
|
+
put(task, "userAgent", user_agent)
|
|
307
|
+
|
|
308
|
+
task
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# Accepts both symbol and string keys.
|
|
312
|
+
def normalize(proxy)
|
|
313
|
+
return proxy if proxy.is_a?(Hash) && proxy.keys.all?(Symbol)
|
|
314
|
+
|
|
315
|
+
proxy.to_h { |key, value| [key.to_sym, value] }
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|
data/lib/anticaptcha.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "anticaptcha/version"
|
|
4
|
+
require_relative "anticaptcha/errors"
|
|
5
|
+
require_relative "anticaptcha/solution"
|
|
6
|
+
require_relative "anticaptcha/tasks"
|
|
7
|
+
require_relative "anticaptcha/client"
|
|
8
|
+
|
|
9
|
+
# Official Anti-Captcha.com API client.
|
|
10
|
+
#
|
|
11
|
+
# Solves image captchas, Recaptcha v2/v3 (Enterprise and non-Enterprise),
|
|
12
|
+
# hCaptcha, FunCaptcha (Arkose Labs), GeeTest v3/v4, Cloudflare Turnstile,
|
|
13
|
+
# Amazon WAF, Prosopo, Friendly Captcha, Altcha, and runs AntiGate custom
|
|
14
|
+
# scenarios.
|
|
15
|
+
#
|
|
16
|
+
# require "anticaptcha"
|
|
17
|
+
#
|
|
18
|
+
# client = Anticaptcha.new("API_KEY_HERE")
|
|
19
|
+
# puts client.balance
|
|
20
|
+
#
|
|
21
|
+
# solution = client.solve_recaptcha_v2(
|
|
22
|
+
# website_url: "https://www.website.com/",
|
|
23
|
+
# website_key: "6Lcyu8UZAAAAACwSh6Xf58WrNXTu0LLu4F85xf20"
|
|
24
|
+
# )
|
|
25
|
+
# puts solution.g_recaptcha_response
|
|
26
|
+
#
|
|
27
|
+
# See https://anti-captcha.com/apidoc for the API details.
|
|
28
|
+
module Anticaptcha
|
|
29
|
+
# Shorthand for Anticaptcha::Client.new.
|
|
30
|
+
def self.new(api_key = nil, **options)
|
|
31
|
+
Client.new(api_key, **options)
|
|
32
|
+
end
|
|
33
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: anticaptchaofficial
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Anti-Captcha.com
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: |-
|
|
13
|
+
Official Anti-Captcha.com client for solving image captchas, Recaptcha V2/V3
|
|
14
|
+
(Enterprise and non-Enterprise), hCaptcha, FunCaptcha (Arkose Labs), GeeTest
|
|
15
|
+
v3/v4, Cloudflare Turnstile, Amazon WAF, Prosopo, Friendly Captcha, Altcha
|
|
16
|
+
and AntiGate custom tasks. No runtime dependencies.
|
|
17
|
+
email:
|
|
18
|
+
- support@anti-captcha.com
|
|
19
|
+
executables: []
|
|
20
|
+
extensions: []
|
|
21
|
+
extra_rdoc_files: []
|
|
22
|
+
files:
|
|
23
|
+
- LICENSE
|
|
24
|
+
- README.md
|
|
25
|
+
- lib/anticaptcha.rb
|
|
26
|
+
- lib/anticaptcha/client.rb
|
|
27
|
+
- lib/anticaptcha/errors.rb
|
|
28
|
+
- lib/anticaptcha/solution.rb
|
|
29
|
+
- lib/anticaptcha/tasks.rb
|
|
30
|
+
- lib/anticaptcha/version.rb
|
|
31
|
+
homepage: https://anti-captcha.com
|
|
32
|
+
licenses:
|
|
33
|
+
- MIT
|
|
34
|
+
metadata:
|
|
35
|
+
homepage_uri: https://anti-captcha.com
|
|
36
|
+
source_code_uri: https://github.com/anti-captcha/anticaptcha-ruby
|
|
37
|
+
documentation_uri: https://anti-captcha.com/apidoc
|
|
38
|
+
bug_tracker_uri: https://github.com/anti-captcha/anticaptcha-ruby/issues
|
|
39
|
+
rubygems_mfa_required: 'true'
|
|
40
|
+
rdoc_options: []
|
|
41
|
+
require_paths:
|
|
42
|
+
- lib
|
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 3.0.0
|
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0'
|
|
53
|
+
requirements: []
|
|
54
|
+
rubygems_version: 4.0.16
|
|
55
|
+
specification_version: 4
|
|
56
|
+
summary: Official Anti-Captcha.com API client
|
|
57
|
+
test_files: []
|