scrapeunblocker 0.2.1 → 0.4.0
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/CHANGELOG.md +10 -0
- data/README.md +34 -2
- data/lib/scrapeunblocker/client.rb +52 -0
- data/lib/scrapeunblocker/southwest.rb +27 -0
- data/lib/scrapeunblocker/version.rb +1 -1
- data/lib/scrapeunblocker.rb +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fbe2fc1ce79fbf6b9293fe17403a6293599bf6cb04fe775d3596537a40fd5acb
|
|
4
|
+
data.tar.gz: 4b9dce4731d710996fe0796766bc67829d1cdd5753e6a812f3fc74796cdf7c48
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bca9218a5cee0b1bff9b9160860cc2d1cdd69e0b115abf3db35d449d005828e1f52099395f9d9ff0072ee4b509155cdc9088690d947a964179a3cb57823fffe2
|
|
7
|
+
data.tar.gz: 14a9b61b2f89d2bd23d2356a7fdc35fe16c075862251173aa29cb2463633705132f19f4f87a8e76e7dd637d7f955f23078151389007c0a6860f8b21bddc6a3a0
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 (2026-09-16)
|
|
4
|
+
|
|
5
|
+
- Added `southwest.flights(origin:, dest:, depart_date:, ...)` for the new Southwest Airlines plugin (`POST /flights/southwest-quotes`), reached through the new `su.southwest` namespace and mirroring `su.skyscanner`. `origin` and `dest` are IATA airport codes; `depart_date` and the optional `return_date` are `YYYY-MM-DD` (omit `return_date` for a one-way search). Optional `adults` (1-8, default 1), `fare_type` (`"dollars"` default or `"points"`), `proxy_country` (default `"US"`) and `max_attempts` (1-5, default 3). Returns the raw booking / shopping JSON as a Hash.
|
|
6
|
+
|
|
7
|
+
No breaking changes.
|
|
8
|
+
|
|
9
|
+
## 0.3.0 (2026-09-08)
|
|
10
|
+
|
|
11
|
+
- Added `tiktok_profile`, `tiktok_video`, `tiktok_hashtag`, `tiktok_search` and `tiktok_comments` for the new TikTok plugin: a creator's exact follower / like / video counts with their newest videos (up to 200), any video or photo post with exact plays, likes, comments, shares, saves and reposts, hashtags, music, play / download URLs, subtitle tracks and an optional transcript, a hashtag's total views and videos with its videos, keyword search in TikTok's own ranking, and the comments of any post. No login.
|
|
12
|
+
|
|
3
13
|
## 0.2.1 (2026-09-02)
|
|
4
14
|
|
|
5
15
|
- Added `meta_ad_library(advertiser, ...)` for the new Meta Ad Library plugin (`POST /ads/meta-ad-library`) - returns an advertiser's Meta (Facebook) Ad Library ads as a Hash. `advertiser` is required; optional filters `country`, `active_status`, `media_type` and `max_ads` are dropped when unset so the API applies its own defaults.
|
data/README.md
CHANGED
|
@@ -178,6 +178,19 @@ end
|
|
|
178
178
|
|
|
179
179
|
`marketplace` is any of the 19 regional eBay hosts (`ebay.com` default). `condition` is one of `"new"`, `"open_box"`, `"refurbished"`, `"used"` or `"for_parts"`; `sort` is one of `"best_match"` (default), `"newly_listed"`, `"ending_soon"`, `"price_asc"` or `"price_desc"`; `page_size` is 60, 120 or 240. `exactMatches` is `false` when eBay found nothing for the keyword and answered with its own loosely-related suggestions instead, so check it before using the listings.
|
|
180
180
|
|
|
181
|
+
### TikTok
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
profile = su.tiktok_profile("nasa", max_videos: 5) # exact stats + newest videos
|
|
185
|
+
video = su.tiktok_video("https://www.tiktok.com/@nasa/video/7665075736742530317", include_transcript: true)
|
|
186
|
+
tag = su.tiktok_hashtag("nasa", max_videos: 10)
|
|
187
|
+
results = su.tiktok_search("space telescope", max_results: 25) # TikTok's own ranking
|
|
188
|
+
comments = su.tiktok_comments("https://www.tiktok.com/@nasa/video/7665075736742530317", max_comments: 40)
|
|
189
|
+
puts profile["stats"]["followers"], video["stats"]["plays"], tag["stats"]["views"], comments["totalComments"]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Profiles and hashtags list up to 10 videos in a couple of seconds from TikTok's server-rendered widget; ask for more (up to 200) and the real grid is scrolled in a browser session.
|
|
193
|
+
|
|
181
194
|
## Cookies and the serving proxy
|
|
182
195
|
|
|
183
196
|
```ruby
|
|
@@ -210,6 +223,25 @@ hotels = su.skyscanner.hotels(destination: "Madrid", checkin: "2026-09-01", chec
|
|
|
210
223
|
cars = su.skyscanner.carhire(pickup: "Madrid", pickup_datetime: "2026-09-01T10:00", dropoff_datetime: "2026-09-03T10:00")
|
|
211
224
|
```
|
|
212
225
|
|
|
226
|
+
## Southwest plugin
|
|
227
|
+
|
|
228
|
+
Southwest Airlines flight quotes as JSON. `origin` and `dest` are IATA airport codes; omit `return_date` for a one-way search.
|
|
229
|
+
|
|
230
|
+
```ruby
|
|
231
|
+
flights = su.southwest.flights(
|
|
232
|
+
origin: "DAL", dest: "HOU",
|
|
233
|
+
depart_date: "2026-10-20", return_date: "2026-10-27"
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# One-way, priced in Rapid Rewards points
|
|
237
|
+
oneway = su.southwest.flights(
|
|
238
|
+
origin: "DAL", dest: "HOU",
|
|
239
|
+
depart_date: "2026-10-20", adults: 2, fare_type: "points"
|
|
240
|
+
)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
`adults` is 1-8 (default 1), `fare_type` is `"dollars"` (default) or `"points"`, `proxy_country` defaults to `"US"` and `max_attempts` is 1-5 (default 3). The call returns the raw booking / shopping JSON.
|
|
244
|
+
|
|
213
245
|
## Error handling
|
|
214
246
|
|
|
215
247
|
Non-2xx responses raise typed errors, all subclasses of `ScrapeUnblocker::Error`.
|
|
@@ -268,7 +300,7 @@ end
|
|
|
268
300
|
|
|
269
301
|
When more than one applies, the most serious wins: failed payment outranks credit limit, which outranks quota. All three lift by themselves once the billing state changes - access returns within about a minute, and the API key stays the same. One catch worth knowing: subscribing to a new plan does **not** clear `PaymentFailedError`, because the old unpaid invoice stays open until it is paid.
|
|
270
302
|
|
|
271
|
-
Full details for every status code: [
|
|
303
|
+
Full details for every status code: [docs.scrapeunblocker.com/errors](https://docs.scrapeunblocker.com/errors).
|
|
272
304
|
|
|
273
305
|
## Configuration
|
|
274
306
|
|
|
@@ -283,7 +315,7 @@ ScrapeUnblocker::Client.new(
|
|
|
283
315
|
|
|
284
316
|
## Links
|
|
285
317
|
|
|
286
|
-
- Documentation: [
|
|
318
|
+
- Documentation: [docs.scrapeunblocker.com](https://docs.scrapeunblocker.com?utm_source=rubygems&utm_medium=integration&utm_campaign=ruby-sdk)
|
|
287
319
|
- Website: [scrapeunblocker.com](https://scrapeunblocker.com?utm_source=rubygems&utm_medium=integration&utm_campaign=ruby-sdk)
|
|
288
320
|
- Dashboard: [app.scrapeunblocker.com](https://app.scrapeunblocker.com?utm_source=rubygems&utm_medium=integration&utm_campaign=ruby-sdk)
|
|
289
321
|
|
|
@@ -7,6 +7,7 @@ require "json"
|
|
|
7
7
|
require_relative "errors"
|
|
8
8
|
require_relative "parsed_page"
|
|
9
9
|
require_relative "skyscanner"
|
|
10
|
+
require_relative "southwest"
|
|
10
11
|
require_relative "version"
|
|
11
12
|
|
|
12
13
|
module ScrapeUnblocker
|
|
@@ -22,6 +23,9 @@ module ScrapeUnblocker
|
|
|
22
23
|
# @return [Skyscanner] the Skyscanner plugin endpoints
|
|
23
24
|
attr_reader :skyscanner
|
|
24
25
|
|
|
26
|
+
# @return [Southwest] the Southwest Airlines plugin endpoints
|
|
27
|
+
attr_reader :southwest
|
|
28
|
+
|
|
25
29
|
def initialize(api_key: nil, base_url: DEFAULT_BASE_URL, timeout: 180, max_retries: 2, transport: nil)
|
|
26
30
|
@api_key = api_key || ENV["SCRAPEUNBLOCKER_KEY"]
|
|
27
31
|
if @api_key.nil? || @api_key.empty?
|
|
@@ -34,6 +38,7 @@ module ScrapeUnblocker
|
|
|
34
38
|
@max_retries = max_retries
|
|
35
39
|
@transport = transport || method(:net_http_transport)
|
|
36
40
|
@skyscanner = Skyscanner.new(self)
|
|
41
|
+
@southwest = Southwest.new(self)
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
# Fetch a URL and return the fully rendered HTML.
|
|
@@ -190,6 +195,53 @@ module ScrapeUnblocker
|
|
|
190
195
|
end
|
|
191
196
|
|
|
192
197
|
# @api private
|
|
198
|
+
# Scrape a public TikTok creator profile and its newest videos.
|
|
199
|
+
#
|
|
200
|
+
# Returns the exact follower, following, like and video counts, bio, bio
|
|
201
|
+
# link, verified / private / organization / seller flags, avatar and a
|
|
202
|
+
# +videos+ array of the creator's newest posts (up to 200), each in the
|
|
203
|
+
# full #tiktok_video shape. No login.
|
|
204
|
+
def tiktok_profile(username, max_videos: 10, video_details: true, proxy_country: nil)
|
|
205
|
+
post_json("/social/tiktok-profile",
|
|
206
|
+
username: username, max_videos: max_videos,
|
|
207
|
+
video_details: video_details ? nil : false,
|
|
208
|
+
proxy_country: proxy_country)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Scrape one TikTok video or photo post: exact plays, likes, comments,
|
|
212
|
+
# shares, saves and reposts, hashtags, mentions, author, music, play /
|
|
213
|
+
# download URLs, subtitle tracks and, with +include_transcript+, the
|
|
214
|
+
# transcript as text.
|
|
215
|
+
def tiktok_video(url, include_transcript: false, transcript_language: nil, proxy_country: nil)
|
|
216
|
+
post_json("/social/tiktok-video",
|
|
217
|
+
url: url, include_transcript: include_transcript ? true : nil,
|
|
218
|
+
transcript_language: transcript_language, proxy_country: proxy_country)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Scrape a TikTok hashtag: total views and videos plus its videos (up to 200).
|
|
222
|
+
def tiktok_hashtag(hashtag, max_videos: 10, video_details: true, proxy_country: nil)
|
|
223
|
+
post_json("/social/tiktok-hashtag",
|
|
224
|
+
hashtag: hashtag, max_videos: max_videos,
|
|
225
|
+
video_details: video_details ? nil : false,
|
|
226
|
+
proxy_country: proxy_country)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Search TikTok videos by keyword. Runs in a browser session that clears
|
|
230
|
+
# TikTok's captcha, so +results+ carry TikTok's own ranking (region via
|
|
231
|
+
# +proxy_country+), each in the full #tiktok_video shape. 20-45 s.
|
|
232
|
+
def tiktok_search(query, max_results: 20, proxy_country: nil)
|
|
233
|
+
post_json("/social/tiktok-search",
|
|
234
|
+
query: query, max_results: max_results, proxy_country: proxy_country)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Scrape the comments of a TikTok post (text, date, likes, reply count,
|
|
238
|
+
# author, creator flags, preloaded replies) plus +totalComments+ and
|
|
239
|
+
# +hasMore+. Runs in a browser session that clears TikTok's captcha. 20-45 s.
|
|
240
|
+
def tiktok_comments(url, max_comments: 50, proxy_country: nil)
|
|
241
|
+
post_json("/social/tiktok-comments",
|
|
242
|
+
url: url, max_comments: max_comments, proxy_country: proxy_country)
|
|
243
|
+
end
|
|
244
|
+
|
|
193
245
|
def post_json(path, params)
|
|
194
246
|
JSON.parse(request(path, params)[:body])
|
|
195
247
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ScrapeUnblocker
|
|
4
|
+
# Southwest Airlines plugin endpoints (flights).
|
|
5
|
+
class Southwest
|
|
6
|
+
# @api private
|
|
7
|
+
def initialize(client)
|
|
8
|
+
@client = client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Fetch Southwest Airlines flight quotes and return the raw booking JSON.
|
|
12
|
+
#
|
|
13
|
+
# +origin+ and +dest+ are IATA airport codes (e.g. "DAL", "HOU").
|
|
14
|
+
# +depart_date+ (and the optional +return_date+) are "YYYY-MM-DD"; omit
|
|
15
|
+
# +return_date+ for a one-way search. +adults+ is 1-8. +fare_type+ is
|
|
16
|
+
# "dollars" (default) or "points". +proxy_country+ pins the exit (default
|
|
17
|
+
# "US"). +max_attempts+ is 1-5.
|
|
18
|
+
def flights(origin:, dest:, depart_date:, return_date: nil, adults: 1,
|
|
19
|
+
fare_type: "dollars", proxy_country: "US", max_attempts: 3)
|
|
20
|
+
@client.post_json("/flights/southwest-quotes",
|
|
21
|
+
origin: origin, dest: dest, depart_date: depart_date,
|
|
22
|
+
return_date: return_date, adults: adults,
|
|
23
|
+
fare_type: fare_type, proxy_country: proxy_country,
|
|
24
|
+
max_attempts: max_attempts)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/scrapeunblocker.rb
CHANGED
|
@@ -4,6 +4,7 @@ require_relative "scrapeunblocker/version"
|
|
|
4
4
|
require_relative "scrapeunblocker/errors"
|
|
5
5
|
require_relative "scrapeunblocker/parsed_page"
|
|
6
6
|
require_relative "scrapeunblocker/skyscanner"
|
|
7
|
+
require_relative "scrapeunblocker/southwest"
|
|
7
8
|
require_relative "scrapeunblocker/client"
|
|
8
9
|
|
|
9
10
|
# Official Ruby client for the ScrapeUnblocker web scraping API.
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: scrapeunblocker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ScrapeUnblocker
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: JS-rendered pages that bypass Cloudflare, DataDome, PerimeterX and Akamai,
|
|
14
14
|
plus Google SERP and Skyscanner flights/hotels/car-hire scraping as JSON.
|
|
@@ -26,6 +26,7 @@ files:
|
|
|
26
26
|
- lib/scrapeunblocker/errors.rb
|
|
27
27
|
- lib/scrapeunblocker/parsed_page.rb
|
|
28
28
|
- lib/scrapeunblocker/skyscanner.rb
|
|
29
|
+
- lib/scrapeunblocker/southwest.rb
|
|
29
30
|
- lib/scrapeunblocker/version.rb
|
|
30
31
|
homepage: https://scrapeunblocker.com?utm_source=rubygems&utm_medium=integration&utm_campaign=ruby-sdk
|
|
31
32
|
licenses:
|
|
@@ -33,7 +34,7 @@ licenses:
|
|
|
33
34
|
metadata:
|
|
34
35
|
homepage_uri: https://scrapeunblocker.com?utm_source=rubygems&utm_medium=integration&utm_campaign=ruby-sdk
|
|
35
36
|
source_code_uri: https://github.com/ScrapeUnblocker/scrapeunblocker-ruby
|
|
36
|
-
documentation_uri: https://
|
|
37
|
+
documentation_uri: https://docs.scrapeunblocker.com?utm_source=rubygems&utm_medium=integration&utm_campaign=ruby-sdk
|
|
37
38
|
changelog_uri: https://github.com/ScrapeUnblocker/scrapeunblocker-ruby/blob/main/CHANGELOG.md
|
|
38
39
|
bug_tracker_uri: https://github.com/ScrapeUnblocker/scrapeunblocker-ruby/issues
|
|
39
40
|
rubygems_mfa_required: 'true'
|