scrapeunblocker 0.1.9 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28108195aac1cc524421665dfd8eafcf8c41e0419f0e692172b72f55ab3912c8
4
- data.tar.gz: 9f80e41ef6047c3b12e32338739c9edd3a0d796211933a09f47b5dd3b70708e8
3
+ metadata.gz: 52fcc1782b1ae470a517b26515674f570071abefa9183613f772f54c002cd050
4
+ data.tar.gz: 688d1524ef190967afcd2272e7ca6cc17fc0a36417fec75a839f0cc2b607fde7
5
5
  SHA512:
6
- metadata.gz: 04040b3a41778d5a98307082d147ca90be55992453dd64409e09b94a7cbee9b5c767585fccb3150d426505ba3f6f533215dafdf63a2e675ce024f6909fe2d925
7
- data.tar.gz: 65a01b202aea9d3e94126692df4de80d35312821ee6a14425c6cca8f63e2cf59a0d8f51c38cd1e54e972cbe844e80e0b1a461b38948ce8855682d5ad6a7d67c3
6
+ metadata.gz: f60f1a37fcf62e63fe8195904a50464d7a06f6a1fcc4aac3cffe435fe5a9af0c7fa6de4a89ea0dc0658ed7e7c527f7b731bcb14389e5581913d1173f893f505d
7
+ data.tar.gz: c044299c381b979ad904cf1e0ecb67687e5e93ed91b44f4bc06af06bcf11cd11bda3e7bbabe08c3a0e63cac3474b24b5384141fe2999c9e5f06b548905f84e77
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.1 (2026-09-02)
4
+
5
+ - 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.
6
+
7
+ No breaking changes.
8
+
9
+ ## 0.2.0 (2026-08-29)
10
+
11
+ - `get_page_source` now accepts `steps:` - an ordered Array of browser-action Hashes the API runs in the real browser after the page loads (`wait_for`, `wait_for_text`, `wait`, `click`, `type`, `select`, `press_key`, `scroll`). The array is JSON-encoded into the `steps` query parameter. Steps run once and are not idempotent; a failed step returns HTTP 422 and raises `ScrapeUnblocker::ValidationError`, whose `body` names the failed step (`step_index`, `action`, `reason`, `selector`, `html`).
12
+ - `get_page_source` now accepts `list_elements:` - pass `true` to get a JSON summary of the matched elements (`{"url", "count", "elements"}`) instead of HTML. When set, the method returns the parsed Hash rather than an HTML String, mirroring `get_parsed`.
13
+
14
+ No breaking changes.
15
+
3
16
  ## 0.1.9 (2026-08-28)
4
17
 
5
18
  - Added `amazon_product` and `amazon_search` for the new Amazon plugin. `amazon_product(asin:/url:)` returns one product - title, brand, numeric price and currency, list price and savings, availability, rating, review count, seller, feature bullets, categories and images. `amazon_search(keyword, ...)` returns a keyword search's cards - asin, title, price, list price, rating, review count, a clean product URL, image and the sponsored/prime flags - on any of 20 regional marketplaces.
data/README.md CHANGED
@@ -62,6 +62,47 @@ html = su.get_page_source(
62
62
  )
63
63
  ```
64
64
 
65
+ ## Browser steps
66
+
67
+ Drive the page after it loads with an ordered list of browser actions - fill a form, click through, wait for content, then capture the rendered result. Steps run once in the real browser, in order.
68
+
69
+ ```ruby
70
+ html = su.get_page_source(
71
+ "https://example.com/search",
72
+ steps: [
73
+ { action: "type", selector: "input#q", value: "web scraping", clear: true },
74
+ { action: "press_key", value: "Enter" },
75
+ { action: "wait_for", selector: "#results" },
76
+ { action: "scroll", value: "bottom" }
77
+ ]
78
+ )
79
+ ```
80
+
81
+ Supported actions and their fields:
82
+
83
+ | Action | Fields |
84
+ |---|---|
85
+ | `wait_for` | `selector`, `selector_type` (`css` default, `xPath`, `className`, `tagName`), `timeout_ms` |
86
+ | `wait_for_text` | `value` (text to await), `timeout_ms` |
87
+ | `wait` | `value` (milliseconds) |
88
+ | `click` | `selector`, `selector_type`, `timeout_ms` |
89
+ | `type` | `selector`, `selector_type`, `value`, `clear` (bool), `timeout_ms` - types like a human |
90
+ | `select` | `selector`, `selector_type`, `value`, `timeout_ms` |
91
+ | `press_key` | `value` - one of `Enter`, `Tab`, `Escape`, `Backspace`, `Delete`, `Space`, `ArrowUp`, `ArrowDown`, `ArrowLeft`, `ArrowRight`, `Home`, `End`, `PageUp`, `PageDown` |
92
+ | `scroll` | `value` - `"bottom"` or a pixel count |
93
+
94
+ Steps are not idempotent (they submit forms, click buttons), so a call is not safe to blindly retry. If a step fails, the API answers HTTP 422 and the client raises `ScrapeUnblocker::ValidationError`; its `body` is the JSON describing which step failed (`error: "step_failed"`, `step_index`, `action`, `reason`, `selector`, `html`).
95
+
96
+ ## List elements
97
+
98
+ Pass `list_elements: true` to get a JSON summary of the matched elements instead of the full HTML. The method then returns a parsed Hash (`{"url", "count", "elements"}`) rather than an HTML String.
99
+
100
+ ```ruby
101
+ result = su.get_page_source("https://example.com", list_elements: true)
102
+ puts result["count"]
103
+ result["elements"].each { |el| p el }
104
+ ```
105
+
65
106
  ## Get parsed JSON
66
107
 
67
108
  ```ruby
@@ -87,6 +128,15 @@ local = su.google_local("coffee shops in chicago", proxy_country: "US", gl: "us"
87
128
  local["results"].each { |biz| puts "#{biz['name']} #{biz['rating']} #{biz['address']}" }
88
129
  ```
89
130
 
131
+ ## Meta Ad Library
132
+
133
+ ```ruby
134
+ ads = su.meta_ad_library("Nike", country: "US")
135
+ ads["results"].each { |ad| puts "#{ad['id']} #{ad['media_type']}" }
136
+ ```
137
+
138
+ `advertiser` is required. Optional filters: `country`, `active_status`, `media_type` and `max_ads`. Unset filters are dropped and the API applies its own defaults.
139
+
90
140
  ## Oopbuy goods search
91
141
 
92
142
  ```ruby
@@ -37,10 +37,31 @@ module ScrapeUnblocker
37
37
  end
38
38
 
39
39
  # Fetch a URL and return the fully rendered HTML.
40
- def get_page_source(url, proxy_country: nil, time_sleep: nil, method: nil, value: nil, method_timeout: nil)
41
- request("/getPageSource",
42
- url: url, proxy_country: proxy_country, time_sleep: time_sleep,
43
- method: method, value: value, method_timeout: method_timeout)[:body]
40
+ #
41
+ # +steps+ is an ordered Array of browser-action Hashes the API runs in the
42
+ # real browser after the page loads (each Hash carries an +action+ and its
43
+ # fields): +wait_for+ {selector, selector_type?, timeout_ms?}, +wait_for_text+
44
+ # {value, timeout_ms?}, +wait+ {value}, +click+ {selector, selector_type?,
45
+ # timeout_ms?}, +type+ {selector, selector_type?, value, clear?, timeout_ms?},
46
+ # +select+ {selector, selector_type?, value, timeout_ms?}, +press_key+ {value},
47
+ # +scroll+ {value}. +selector_type+ is one of "css" (default), "xPath",
48
+ # "className" or "tagName". The steps run once and are not idempotent; if a
49
+ # step fails the API answers HTTP 422 with a JSON body naming the failed step,
50
+ # which surfaces here as a ScrapeUnblocker::ValidationError.
51
+ #
52
+ # +list_elements+, when true, makes the API return a JSON summary of the
53
+ # matched elements ({"url", "count", "elements"}) instead of HTML. This method
54
+ # then returns that parsed Hash rather than an HTML String.
55
+ def get_page_source(url, proxy_country: nil, time_sleep: nil, method: nil, value: nil, method_timeout: nil,
56
+ steps: nil, list_elements: nil)
57
+ body = request("/getPageSource",
58
+ url: url, proxy_country: proxy_country, time_sleep: time_sleep,
59
+ method: method, value: value, method_timeout: method_timeout,
60
+ steps: (steps ? JSON.generate(steps) : nil),
61
+ list_elements: (list_elements ? true : nil))[:body]
62
+ return JSON.parse(body) if list_elements
63
+
64
+ body
44
65
  end
45
66
 
46
67
  # Fetch a URL and return structured JSON instead of HTML.
@@ -80,6 +101,19 @@ module ScrapeUnblocker
80
101
  keyword: keyword, proxy_country: proxy_country, hl: hl, gl: gl)
81
102
  end
82
103
 
104
+ # Fetch an advertiser's Meta (Facebook) Ad Library ads and return them as a Hash.
105
+ #
106
+ # +advertiser+ is the advertiser name or page to look up. Optional filters:
107
+ # +country+ (the Ad Library region), +active_status+ (active or inactive
108
+ # ads), +media_type+ (image, video, etc.) and +max_ads+ (a cap on how many
109
+ # ads to return). Unset filters are dropped from the request and the API
110
+ # applies its own defaults.
111
+ def meta_ad_library(advertiser, country: nil, active_status: nil, media_type: nil, max_ads: nil)
112
+ post_json("/ads/meta-ad-library",
113
+ advertiser: advertiser, country: country, active_status: active_status,
114
+ media_type: media_type, max_ads: max_ads)
115
+ end
116
+
83
117
  # Search Oopbuy (1688, Taobao or official channel) and return the goods as a Hash.
84
118
  #
85
119
  # Returns matched products, each with spu, channel, title, titleCn, price,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ScrapeUnblocker
4
- VERSION = "0.1.9"
4
+ VERSION = "0.2.1"
5
5
  end
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.1.9
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ScrapeUnblocker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-28 00:00:00.000000000 Z
11
+ date: 2026-09-02 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.