adspower-client 1.0.12 → 1.0.15
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 +4 -4
- data/adspower-client.gemspec +2 -2
- data/lib/adspower-client.rb +142 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78c1201b2d2e5a524b67b7cac64506ba9afc2538e9890a387a02252387dd1259
|
4
|
+
data.tar.gz: c82ad9106e87929604fc7242e13680cdeddef6e0ede4e1bfe8181eb7e5c042d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a9ef2494df3d2c2adbd7d9d16286ff2b5e5b05f0f1872c32cb3d0439db1d915df5c4de9b2ff1a2321e09f96dccd4122da266f749c4c7f9fd89d45490144e2f4
|
7
|
+
data.tar.gz: a1d62383908125640ea807fcd96e38577c821ee7f4785b37936666aa892fa2462d6897c06861f084f265a431391dcf523424cff2a4799244e0b5fdd24cb59266
|
data/adspower-client.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'adspower-client'
|
3
|
-
s.version = '1.0.
|
4
|
-
s.date = '
|
3
|
+
s.version = '1.0.15'
|
4
|
+
s.date = '2025-07-17'
|
5
5
|
s.summary = "Ruby library for operating AdsPower API."
|
6
6
|
s.description = "Ruby library for operating AdsPower API."
|
7
7
|
s.authors = ["Leandro Daniel Sardi"]
|
data/lib/adspower-client.rb
CHANGED
@@ -6,10 +6,12 @@ require 'selenium-webdriver'
|
|
6
6
|
require 'watir'
|
7
7
|
require 'fileutils'
|
8
8
|
|
9
|
-
class AdsPowerClient
|
9
|
+
class AdsPowerClient
|
10
|
+
CLOUD_API_BASE = 'https://api.adspower.com/v1'
|
11
|
+
|
10
12
|
# reference: https://localapi-doc-en.adspower.com/
|
11
13
|
# reference: https://localapi-doc-en.adspower.com/docs/Rdw7Iu
|
12
|
-
attr_accessor :key, :port, :server_log, :adspower_listener, :adspower_default_browser_version
|
14
|
+
attr_accessor :key, :port, :server_log, :adspower_listener, :adspower_default_browser_version, :cloud_token
|
13
15
|
|
14
16
|
# control over the drivers created, in order to not create the same driver twice and not generate memory leaks.
|
15
17
|
# reference: https://github.com/leandrosardi/adspower-client/issues/4
|
@@ -22,7 +24,12 @@ class AdsPowerClient
|
|
22
24
|
self.port = h[:port] || '50325'
|
23
25
|
self.server_log = h[:server_log] || '~/adspower-client.log'
|
24
26
|
self.adspower_listener = h[:adspower_listener] || 'http://127.0.0.1'
|
27
|
+
|
28
|
+
# DEPRECATED
|
25
29
|
self.adspower_default_browser_version = h[:adspower_default_browser_version] || '116'
|
30
|
+
|
31
|
+
# PENDING
|
32
|
+
self.cloud_token = h[:cloud_token]
|
26
33
|
end
|
27
34
|
|
28
35
|
# Acquire the lock
|
@@ -89,6 +96,54 @@ class AdsPowerClient
|
|
89
96
|
end
|
90
97
|
end
|
91
98
|
|
99
|
+
# Count current profiles (optionally filtered by group)
|
100
|
+
def profile_count(group_id: nil)
|
101
|
+
count = 0
|
102
|
+
page = 1
|
103
|
+
|
104
|
+
loop do
|
105
|
+
params = { page: page, limit: 100 }
|
106
|
+
params[:group_id] = group_id if group_id
|
107
|
+
url = "#{adspower_listener}:#{port}/api/v2/browser-profile/list"
|
108
|
+
res = BlackStack::Netting.call_post(url, params)
|
109
|
+
data = JSON.parse(res.body)
|
110
|
+
raise "Error listing profiles: #{data['msg']}" unless data['code'] == 0
|
111
|
+
|
112
|
+
list = data['data']['list']
|
113
|
+
count += list.size
|
114
|
+
break if list.size < 100
|
115
|
+
|
116
|
+
page += 1
|
117
|
+
end
|
118
|
+
|
119
|
+
count
|
120
|
+
end
|
121
|
+
|
122
|
+
# Return a hash with:
|
123
|
+
# • :limit ⇒ total profile slots allowed (-1 = unlimited)
|
124
|
+
# • :used ⇒ number of profiles currently created
|
125
|
+
# • :remaining ⇒ slots left (nil if unlimited)
|
126
|
+
# Fetch your real profile quota from the Cloud API
|
127
|
+
def cloud_profile_quota
|
128
|
+
uri = URI("#{CLOUD_API_BASE}/account/get_info")
|
129
|
+
req = Net::HTTP::Get.new(uri)
|
130
|
+
req['Authorization'] = "Bearer #{self.cloud_token}"
|
131
|
+
|
132
|
+
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
133
|
+
http.request(req)
|
134
|
+
end
|
135
|
+
data = JSON.parse(res.body)
|
136
|
+
raise "Cloud API error: #{data['msg']}" unless data['code'] == 0
|
137
|
+
|
138
|
+
allowed = data['data']['total_profiles_allowed'].to_i
|
139
|
+
used = data['data']['profiles_used'].to_i
|
140
|
+
remaining = allowed < 0 ? nil : (allowed - used)
|
141
|
+
|
142
|
+
{ limit: allowed,
|
143
|
+
used: used,
|
144
|
+
remaining: remaining }
|
145
|
+
end # cloud_profile_quota
|
146
|
+
|
92
147
|
# Create a new user profile via API call and return the ID of the created user.
|
93
148
|
def create
|
94
149
|
with_lock do
|
@@ -106,8 +161,62 @@ class AdsPowerClient
|
|
106
161
|
raise "Error: #{ret.to_s}" if ret['msg'].to_s.downcase != 'success'
|
107
162
|
ret['data']['id']
|
108
163
|
end
|
109
|
-
end
|
164
|
+
end # def create
|
165
|
+
|
166
|
+
# Create a new desktop profile with custom name, proxy, and fingerprint settings
|
167
|
+
#
|
168
|
+
# @param name [String] the profile’s display name
|
169
|
+
# @param proxy_config [Hash] keys: :ip, :port, :user, :password, :proxy_soft (default 'other'), :proxy_type (default 'http')
|
170
|
+
# @param group_id [String] which AdsPower group to assign (default '0')
|
171
|
+
# @param browser_version [String] Chrome version to use (must match Chromedriver), defaults to adspower_default_browser_version
|
172
|
+
# @return String the new profile’s ID
|
173
|
+
def create2(name:, proxy_config:, group_id: '0', browser_version: nil)
|
174
|
+
browser_version ||= adspower_default_browser_version
|
175
|
+
|
176
|
+
with_lock do
|
177
|
+
url = "#{adspower_listener}:#{port}/api/v2/browser-profile/create"
|
178
|
+
body = {
|
179
|
+
'name' => name,
|
180
|
+
'group_id' => group_id,
|
181
|
+
'user_proxy_config' => {
|
182
|
+
'proxy_soft' => proxy_config[:proxy_soft] || 'other',
|
183
|
+
'proxy_type' => proxy_config[:proxy_type] || 'http',
|
184
|
+
'proxy_host' => proxy_config[:ip],
|
185
|
+
'proxy_port' => proxy_config[:port].to_s,
|
186
|
+
'proxy_user' => proxy_config[:user],
|
187
|
+
'proxy_password' => proxy_config[:password]
|
188
|
+
},
|
189
|
+
'fingerprint_config' => {
|
190
|
+
# 1) Chrome kernel version → must match your Chromedriver
|
191
|
+
'browser_kernel_config' => {
|
192
|
+
'version' => browser_version,
|
193
|
+
'type' => 'chrome'
|
194
|
+
},
|
195
|
+
# 2) Auto‐detect timezone (and locale) from proxy IP
|
196
|
+
'automatic_timezone' => '1',
|
197
|
+
'timezone' => '',
|
198
|
+
'language' => [],
|
199
|
+
# 3) Force desktop UA (no mobile): empty random_ua & default UA settings
|
200
|
+
'ua' => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "\
|
201
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/#{browser_version}.0.0.0 Safari/537.36",
|
202
|
+
'ua_category' => 'desktop',
|
203
|
+
#'screen_resolution' => '1920*1080',
|
204
|
+
'is_mobile' => false,
|
205
|
+
# standard desktop fingerprints
|
206
|
+
'webrtc' => 'disabled', # hide real IP via WebRTC
|
207
|
+
'flash' => 'allow',
|
208
|
+
'fonts' => [], # default fonts
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
res = BlackStack::Netting.call_post(url, body)
|
213
|
+
ret = JSON.parse(res.body)
|
214
|
+
raise "Error creating profile: #{ret['msg']}" unless ret['code'] == 0
|
110
215
|
|
216
|
+
ret['data']['profile_id']
|
217
|
+
end
|
218
|
+
end # def create2
|
219
|
+
|
111
220
|
# Delete a user profile via API call.
|
112
221
|
def delete(id)
|
113
222
|
with_lock do
|
@@ -186,6 +295,36 @@ class AdsPowerClient
|
|
186
295
|
driver
|
187
296
|
end
|
188
297
|
|
298
|
+
# Attach to the existing browser session with Selenium WebDriver.
|
299
|
+
def driver2(id, headless: false, read_timeout: 180)
|
300
|
+
# Return the existing driver if it's still active.
|
301
|
+
old = @@drivers[id]
|
302
|
+
return old if old
|
303
|
+
|
304
|
+
# Otherwise, start the driver
|
305
|
+
ret = self.start(id, headless)
|
306
|
+
|
307
|
+
# Attach test execution to the existing browser
|
308
|
+
url = ret['data']['ws']['selenium']
|
309
|
+
opts = Selenium::WebDriver::Chrome::Options.new
|
310
|
+
opts.add_option("debuggerAddress", url)
|
311
|
+
|
312
|
+
# Set up the custom HTTP client with a longer timeout
|
313
|
+
client = Selenium::WebDriver::Remote::Http::Default.new
|
314
|
+
client.read_timeout = read_timeout # Set this to the desired timeout in seconds
|
315
|
+
|
316
|
+
# Connect to the existing browser
|
317
|
+
driver = Selenium::WebDriver.for(:chrome, options: opts, http_client: client)
|
318
|
+
|
319
|
+
# Save the driver
|
320
|
+
@@drivers[id] = driver
|
321
|
+
|
322
|
+
# Return the driver
|
323
|
+
driver
|
324
|
+
end
|
325
|
+
|
326
|
+
# DEPRECATED - Use Zyte instead of this method.
|
327
|
+
#
|
189
328
|
# Create a new profile, start the browser, visit a page, grab the HTML, and clean up.
|
190
329
|
def html(url)
|
191
330
|
ret = {
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adspower-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leandro Daniel Sardi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-07-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: uri
|