scrapeunblocker 0.10.1 → 0.11.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 +4 -4
- data/CHANGELOG.md +10 -1
- data/README.md +5 -3
- data/lib/scrapeunblocker/client.rb +5 -1
- data/lib/scrapeunblocker/errors.rb +8 -7
- data/lib/scrapeunblocker/plugins.rb +0 -164
- data/lib/scrapeunblocker/version.rb +1 -1
- 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: 9bd6d663c941e4d49cc8c8b7446f15c2c4cff0ac7025e85144dd72706ac24220
|
|
4
|
+
data.tar.gz: 68949c187f57eb403d1f890a236fd9caa671beeaf395225c8100d4da22ce8fac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b6c58655e6ea4657b358e0edf1c147226d2fdbb5b55b64a18b88f3f5b5d821b58b78ef29ccb2f505554998c6ef9e8183afa45f5dcf01fcf9f9eb3fb5dea28d75
|
|
7
|
+
data.tar.gz: 8ab2b5635e0b7edc16bfd1202e92ed24e0a189a115d2f37ea26e2c21c9b7780e5f9f942a50edda29cdb6645e2b7a61228bcea014abe08c44f20f5565f31f1057
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.1 (2026-10-15)
|
|
4
|
+
|
|
5
|
+
- `get_image` docs: the API now returns the image's original bytes and format (JPEG, PNG, WebP, AVIF, GIF, SVG, ...) instead of a PNG re-encode. The method still returns a binary `String`.
|
|
6
|
+
- A missing image (the host's own 404/410) raises `TargetNotFoundError`; a URL that is not an image raises `UnsupportedContentError`. The 415 message no longer says "does not serve HTML", which was wrong for `get_image`.
|
|
7
|
+
|
|
8
|
+
## 0.11.0 (2026-10-13)
|
|
9
|
+
|
|
10
|
+
- Removed four plugin methods added in 0.10.0: `youtube_comments`, `telegram_channel`, `quora_question` and `quora_profile`. Those plugins are no longer offered through the SDKs; `plugin(path, params)` still reaches any endpoint your account can use.
|
|
11
|
+
|
|
3
12
|
## 0.10.1 (2026-10-13)
|
|
4
13
|
|
|
5
14
|
- `tiktok_shop_search` takes its keyword as optional, so a category-only search works (`category` option).
|
|
@@ -9,7 +18,7 @@
|
|
|
9
18
|
|
|
10
19
|
## 0.10.0 (2026-10-13)
|
|
11
20
|
|
|
12
|
-
- 104 new plugin methods on `ScrapeUnblocker::Client`, one for every public plugin endpoint: e-commerce (Walmart, Target, Best Buy, Home Depot, Etsy, Temu, SHEIN, Zalando, AliExpress, Alibaba, 1688, TikTok Shop, Amazon Best Sellers and reviews), groceries (Woolworths, Coles, ALDI Australia), travel (Booking.com reviews, Airbnb listings and reviews, Tripadvisor), Google (Trends, Shopping, Jobs, Maps place details), Bing / DuckDuckGo / Yahoo / Brave search and images, real estate (Zillow, Redfin, Rightmove, Idealista, ImmobilienScout24), vehicles (mobile.de, AutoScout24), jobs (Indeed, Glassdoor, Naukri, Wellfound, company career sites), reviews and companies (Trustpilot, G2, Capterra, Product Hunt, Crunchbase), Yelp, Naver Place, Google Play, the App Store, YouTube, Spotify,
|
|
21
|
+
- 104 new plugin methods on `ScrapeUnblocker::Client`, one for every public plugin endpoint: e-commerce (Walmart, Target, Best Buy, Home Depot, Etsy, Temu, SHEIN, Zalando, AliExpress, Alibaba, 1688, TikTok Shop, Amazon Best Sellers and reviews), groceries (Woolworths, Coles, ALDI Australia), travel (Booking.com reviews, Airbnb listings and reviews, Tripadvisor), Google (Trends, Shopping, Jobs, Maps place details), Bing / DuckDuckGo / Yahoo / Brave search and images, real estate (Zillow, Redfin, Rightmove, Idealista, ImmobilienScout24), vehicles (mobile.de, AutoScout24), jobs (Indeed, Glassdoor, Naukri, Wellfound, company career sites), reviews and companies (Trustpilot, G2, Capterra, Product Hunt, Crunchbase), Yelp, Naver Place, Google Play, the App Store, YouTube, Spotify, Similarweb, Ahrefs and Semrush. The README lists them by category; every parameter is on the docs plugin pages.
|
|
13
22
|
- Each method takes the plugin's main input positionally and the rest as keyword options; options left `nil` are not sent, so the API's defaults apply. Methods for one mode of a multi-mode endpoint set the mode themselves (`woolworths_product("888137")`, `spotify_artist(...)`).
|
|
14
23
|
- New `plugin(path, **params)` calls any plugin endpoint by path. Array values are sent as a repeated query parameter.
|
|
15
24
|
|
data/README.md
CHANGED
|
@@ -145,7 +145,7 @@ jobs = su.career_site_jobs("https://jobs.ashbyhq.com/ramp", keyword: "engineer")
|
|
|
145
145
|
| Reviews & Companies | `trustpilot_reviews`, `g2_reviews`, `g2_search`, `capterra_reviews`, `capterra_search`, `product_hunt`, `crunchbase_company`, `crunchbase_search` |
|
|
146
146
|
| Local & Maps | `yelp_search`, `yelp_business`, `yelp_reviews`, `naver_place_search`, `naver_place_details` |
|
|
147
147
|
| Apps | `google_play_app`, `google_play_search`, `app_store_app`, `app_store_search`, `app_store_reviews` |
|
|
148
|
-
| Video
|
|
148
|
+
| Video & Music | `youtube_channel`, `youtube_search`, `youtube_transcript`, `spotify_search`, `spotify_artist`, `spotify_album`, `spotify_track`, `spotify_playlist` |
|
|
149
149
|
| SEO & Ads | `similarweb_overview`, `ahrefs`, `semrush_overview`, `meta_ad_library` |
|
|
150
150
|
<!-- plugin-methods:end -->
|
|
151
151
|
|
|
@@ -242,6 +242,8 @@ bytes = su.get_image("https://example.com/photo.jpg")
|
|
|
242
242
|
File.binwrite("photo.jpg", bytes)
|
|
243
243
|
```
|
|
244
244
|
|
|
245
|
+
The bytes come back exactly as the image host serves them, in the original format (JPEG, PNG, WebP, AVIF, GIF, SVG, ...); nothing is re-encoded. Pass the image URL itself, not the page it sits on.
|
|
246
|
+
|
|
245
247
|
## Skyscanner plugins
|
|
246
248
|
|
|
247
249
|
Flights, hotels and car hire as JSON:
|
|
@@ -287,10 +289,10 @@ end
|
|
|
287
289
|
| `BudgetExceededError` | 402 | This billing period's spend reached the monthly budget limit you set |
|
|
288
290
|
| `PaymentFailedError` | 402 | A card payment was declined three times |
|
|
289
291
|
| `BlockedError` | 403 | Blocked by bot protection on every path |
|
|
290
|
-
| `NotFoundError` | 404 | What you asked for does not exist -
|
|
292
|
+
| `NotFoundError` | 404 | What you asked for does not exist - a plugin lookup found nothing |
|
|
291
293
|
| `TargetNotFoundError` | 404 / 410 | The target page itself does not exist; carries `origin_status`, `html`, `destination_url` (subclass of `NotFoundError`, billed) |
|
|
292
294
|
| `BrowserTimeoutError` | 408 | Our browser run timed out before the page was ready |
|
|
293
|
-
| `UnsupportedContentError` | 415 | The URL serves something other than HTML |
|
|
295
|
+
| `UnsupportedContentError` | 415 | The URL serves something other than HTML (`get_page_source`) or other than an image (`get_image`) |
|
|
294
296
|
| `ValidationError` | 422 | Missing or wrong-typed parameter; `body` holds the `detail` array |
|
|
295
297
|
| `RateLimitError` | 429 | Too many requests |
|
|
296
298
|
| `UpstreamOutageError` | 503 | The target origin is down |
|
|
@@ -215,7 +215,11 @@ module ScrapeUnblocker
|
|
|
215
215
|
proxy_country: proxy_country)
|
|
216
216
|
end
|
|
217
217
|
|
|
218
|
-
# Fetch an image
|
|
218
|
+
# Fetch an image and return its bytes exactly as the image host serves them -
|
|
219
|
+
# the original format (JPEG, PNG, WebP, AVIF, GIF, SVG, ...), nothing
|
|
220
|
+
# re-encoded. +url+ must point at the image itself: a page URL raises
|
|
221
|
+
# UnsupportedContentError, and an image the host answers 404 or 410 for
|
|
222
|
+
# raises TargetNotFoundError.
|
|
219
223
|
def get_image(url, proxy_country: nil)
|
|
220
224
|
request("/getImage", url: url, proxy_country: proxy_country)[:body]
|
|
221
225
|
end
|
|
@@ -94,16 +94,15 @@ module ScrapeUnblocker
|
|
|
94
94
|
|
|
95
95
|
# Something the call asked for does not exist (HTTP 404).
|
|
96
96
|
#
|
|
97
|
-
#
|
|
98
|
-
# plugin methods raise it when the item they look up does not exist. When the
|
|
97
|
+
# Plugin methods raise it when the item they look up does not exist. When the
|
|
99
98
|
# target page itself answered 404 or 410, the more specific
|
|
100
99
|
# TargetNotFoundError subclass is raised instead.
|
|
101
100
|
class NotFoundError < APIError; end
|
|
102
101
|
|
|
103
102
|
# The target page itself does not exist (HTTP 404 or 410).
|
|
104
103
|
#
|
|
105
|
-
# Raised by #get_page_source, #get_parsed
|
|
106
|
-
# site you asked for answered 404 or 410 on its own. The API passes that
|
|
104
|
+
# Raised by #get_page_source, #get_parsed, #get_page_with_cookies and
|
|
105
|
+
# #get_image when the site you asked for answered 404 or 410 on its own. The API passes that
|
|
107
106
|
# status through and marks it with the X-Origin-Status header, which is how
|
|
108
107
|
# this is told apart from an API-side 404. It is the target's final answer,
|
|
109
108
|
# not a block, so it is never retried - and the call is billed, because the
|
|
@@ -130,8 +129,10 @@ module ScrapeUnblocker
|
|
|
130
129
|
# the API answered - it just could not render the page in time.
|
|
131
130
|
class BrowserTimeoutError < APIError; end
|
|
132
131
|
|
|
133
|
-
# The URL serves
|
|
134
|
-
#
|
|
132
|
+
# The URL serves a content type the call cannot return (HTTP 415): something
|
|
133
|
+
# other than HTML for #get_page_source (for images, use #get_image), or
|
|
134
|
+
# something other than an image for #get_image. The message names the content
|
|
135
|
+
# type found.
|
|
135
136
|
class UnsupportedContentError < APIError; end
|
|
136
137
|
|
|
137
138
|
# A request parameter is missing or has the wrong type (HTTP 422).
|
|
@@ -183,7 +184,7 @@ module ScrapeUnblocker
|
|
|
183
184
|
403 => "Target blocked by bot protection on every bypass path",
|
|
184
185
|
404 => "Requested element not found on the page",
|
|
185
186
|
408 => "Browser run timed out before the page was ready",
|
|
186
|
-
415 => "URL
|
|
187
|
+
415 => "URL serves a content type this call cannot return",
|
|
187
188
|
422 => "Validation error - see the detail array in the response body",
|
|
188
189
|
429 => "Rate limited - too many requests",
|
|
189
190
|
503 => "Upstream origin returned a server-side outage page",
|
|
@@ -3302,30 +3302,6 @@ module ScrapeUnblocker
|
|
|
3302
3302
|
})
|
|
3303
3303
|
end
|
|
3304
3304
|
|
|
3305
|
-
# Scrape a YouTube video's comments.
|
|
3306
|
-
#
|
|
3307
|
-
# Returns a YouTube video's comments as JSON. For each comment: `commentId`, `author`,
|
|
3308
|
-
# `authorChannelId`, `authorThumbnail`, `text`, `likeCount`, `publishedTimeText`,
|
|
3309
|
-
# `replyCount`, and the `isPinned`, `isHearted`, `isAuthorVerified` and `isUploader` flags,
|
|
3310
|
-
# plus the video `title` and total `commentCount`. Sort by `top` or `newest` and collect up
|
|
3311
|
-
# to `max_results` across pages.
|
|
3312
|
-
#
|
|
3313
|
-
# @param video [String] Video id (dQw4w9WgXcQ) or any YouTube video URL.
|
|
3314
|
-
# @param sort [String] Comment order: top, newest. API default: top.
|
|
3315
|
-
# @param max_results [Integer] How many comments to collect across pages (~20 per page). API
|
|
3316
|
-
# default: 20.
|
|
3317
|
-
# @param proxy_country [String] Proxy country the request is sent from (ISO-2, e.g. 'US',
|
|
3318
|
-
# 'DE') for the watch page. Defaults to US.
|
|
3319
|
-
# Calls POST /content/youtube-comments.
|
|
3320
|
-
def youtube_comments(video, sort: nil, max_results: nil, proxy_country: nil)
|
|
3321
|
-
post_json("/content/youtube-comments", {
|
|
3322
|
-
video: video,
|
|
3323
|
-
sort: sort,
|
|
3324
|
-
max_results: max_results,
|
|
3325
|
-
proxy_country: proxy_country,
|
|
3326
|
-
})
|
|
3327
|
-
end
|
|
3328
|
-
|
|
3329
3305
|
# Get a YouTube video transcript.
|
|
3330
3306
|
#
|
|
3331
3307
|
# Returns a YouTube video's captions as JSON: timestamped `segments` (`start`, `dur`,
|
|
@@ -3566,146 +3542,6 @@ module ScrapeUnblocker
|
|
|
3566
3542
|
})
|
|
3567
3543
|
end
|
|
3568
3544
|
|
|
3569
|
-
# Scrape a public Telegram channel: info and posts.
|
|
3570
|
-
#
|
|
3571
|
-
# Reads a public Telegram channel's web preview. Returns `channel` (`username`, `title`,
|
|
3572
|
-
# `description`, `avatar`, `verified`, `subscribers` and the other `counters`) and `posts`,
|
|
3573
|
-
# newest first: `id`, `url`, `date` (ISO-8601 UTC), `text` (plain), `textHtml`, `views`,
|
|
3574
|
-
# `author` (signature), `edited`, `forwardedFrom`, `replyTo`, `media` (photo / video /
|
|
3575
|
-
# animation / round_video / voice / audio / document / sticker, with CDN `url`, `thumbnail`,
|
|
3576
|
-
# `duration`), `poll`, `linkPreview`, `reactions` (a custom-emoji reaction has its
|
|
3577
|
-
# `customEmojiId`, plus the standard `emoji` and `image` Telegram falls back to when the
|
|
3578
|
-
# page shows that emoji anywhere), `buttons`, `links`, `hashtags` (the tags Telegram links;
|
|
3579
|
-
# a bare '#7' is text) and `mentions`. One page (about 20 posts) by default; `max_posts` (up
|
|
3580
|
-
# to 500) pages back through history; `before`, `after` and `since` bound the range, `q`
|
|
3581
|
-
# searches inside the channel and `post_id` returns one post. `nextBefore` continues a
|
|
3582
|
-
# capped answer. Only channels have a public preview: users, bots, groups and private
|
|
3583
|
-
# channels answer 404. Billed one request per page fetched (`pagesFetched`).
|
|
3584
|
-
#
|
|
3585
|
-
# @param channel [String] Public channel: username ('durov'), '@durov', or a t.me link
|
|
3586
|
-
# ('https://t.me/durov', 'https://t.me/s/durov'). A post link ('https://t.me/durov/400')
|
|
3587
|
-
# returns that one post.
|
|
3588
|
-
# @param max_posts [Integer] Posts to collect, newest first (1-500), paging back through the
|
|
3589
|
-
# channel's history; each page fetched is billed as one request. Omit it for one page,
|
|
3590
|
-
# billed once: the newest posts (a page has 20 message slots and an album fills one per
|
|
3591
|
-
# photo, so it can hold fewer posts).
|
|
3592
|
-
# @param before [Integer] Only posts with an id below this one. Pass `nextBefore` of a
|
|
3593
|
-
# previous response to continue where it stopped.
|
|
3594
|
-
# @param after [Integer] Stop at this post id: only posts with a higher id are returned.
|
|
3595
|
-
# @param since [String] Stop at this date: only posts published on or after it (YYYY-MM-DD
|
|
3596
|
-
# or an ISO-8601 datetime, UTC when no offset is given).
|
|
3597
|
-
# @param q [String] Search inside the channel: only posts matching this text.
|
|
3598
|
-
# @param post_id [Integer] Return only this post (a post id of the channel).
|
|
3599
|
-
# @param proxy_country [String] Proxy country the request is sent from (ISO-2, e.g. 'US',
|
|
3600
|
-
# 'DE'). Leave blank to let the API pick.
|
|
3601
|
-
# Calls POST /social/telegram-channel.
|
|
3602
|
-
def telegram_channel(channel, max_posts: nil, before: nil, after: nil, since: nil, q: nil, post_id: nil, proxy_country: nil)
|
|
3603
|
-
post_json("/social/telegram-channel", {
|
|
3604
|
-
channel: channel,
|
|
3605
|
-
max_posts: max_posts,
|
|
3606
|
-
before: before,
|
|
3607
|
-
after: after,
|
|
3608
|
-
since: since,
|
|
3609
|
-
q: q,
|
|
3610
|
-
post_id: post_id,
|
|
3611
|
-
proxy_country: proxy_country,
|
|
3612
|
-
})
|
|
3613
|
-
end
|
|
3614
|
-
|
|
3615
|
-
# Scrape Quora questions, answers and profiles.
|
|
3616
|
-
#
|
|
3617
|
-
# Given a Quora `question` (URL or slug), returns the `question` (`qid`, `title`, `url`,
|
|
3618
|
-
# `answerCount`, `allRelatedCount`, `followerCount`, `commentCount`, `topics`) and its
|
|
3619
|
-
# `answers`: `id`, `url`, `relation` (`answer`, `merged` for an answer to a question Quora
|
|
3620
|
-
# merged into this one, `related` with `include_related=true`), the answered `question`,
|
|
3621
|
-
# `author` (`name`, `uid`, `profileUrl`, `imageUrl`, `credential`, `isVerified`,
|
|
3622
|
-
# `isAnonymous`), the full `text` with `images` and `links`, `upvotes`, `views`, `shares`,
|
|
3623
|
-
# `comments`, `createdAt`, `updatedAt` and `isAiGenerated`; plus `relatedQuestions`. Answers
|
|
3624
|
-
# are in Quora's own order, up to `max_answers` (10 per page after the first few), unique
|
|
3625
|
-
# within a call. `nextCursor` as `cursor` continues, best-effort: Quora re-ranks the list on
|
|
3626
|
-
# every visit, so a continuation can repeat or skip answers of earlier calls (dedupe by
|
|
3627
|
-
# `id`); for a complete list ask for a larger `max_answers` in one call (up to 300).
|
|
3628
|
-
# `mode=profile&profile=` returns a public `profile` (`name`, `headline`, `description`,
|
|
3629
|
-
# follower / following / answer / question / post counts, `contentViews`, `credentials`,
|
|
3630
|
-
# `knowsAbout`, `spaces`, `topWriterYears`, `joinedAt`) with its newest `answers`. No login:
|
|
3631
|
-
# only what Quora shows an anonymous visitor - Quora's search is not available that way, and
|
|
3632
|
-
# Quora lists only a profile's newest few dozen answers to logged-out visitors
|
|
3633
|
-
# (`pagingStopped`: `quora_logged_out_limit`). `pagingStopped` otherwise names why paging
|
|
3634
|
-
# ended early (`blocked`, `time`, `unavailable`). Billed one unit per page fetched
|
|
3635
|
-
# (`pagesFetched`); a `cursor` continuation bills only its GraphQL pages.
|
|
3636
|
-
#
|
|
3637
|
-
# @param question [String] Quora question URL (https://www.quora.com/What-is-the-best-way-
|
|
3638
|
-
# to-learn-programming), an answer URL on it, or the question slug (What-is-the-best-way-to-
|
|
3639
|
-
# learn-programming). Language editions such as es.quora.com are accepted as URLs. Required
|
|
3640
|
-
# with mode=question.
|
|
3641
|
-
# @param max_answers [Integer] Answers to return: 1-300 with mode=question (default 20),
|
|
3642
|
-
# 0-200 with mode=profile (default 10; 0 = profile only). Answers come 10 per page after the
|
|
3643
|
-
# first few; each page is one billed unit.
|
|
3644
|
-
# @param include_related [Boolean] mode=question: also return the answers Quora shows from
|
|
3645
|
-
# related questions (its 'All related' view, `relation`='related'). By default only answers
|
|
3646
|
-
# to this question and to questions merged into it. API default: false.
|
|
3647
|
-
# @param cursor [String] Continue after a previous call: pass its `nextCursor`. Best-effort:
|
|
3648
|
-
# each call is a new Quora visit and Quora re-ranks the list per visit, so a continuation
|
|
3649
|
-
# can repeat or skip answers of earlier calls - dedupe by answer `id`. For a complete list
|
|
3650
|
-
# ask for a larger `max_answers` in one call (up to 300).
|
|
3651
|
-
# @param proxy_country [String] Proxy country the request is sent from (ISO-2, e.g. 'US',
|
|
3652
|
-
# 'DE'). Leave blank for the countries chosen for the site.
|
|
3653
|
-
# Calls POST /social/quora.
|
|
3654
|
-
def quora_question(question, max_answers: nil, include_related: nil, cursor: nil, proxy_country: nil)
|
|
3655
|
-
post_json("/social/quora", {
|
|
3656
|
-
mode: "question",
|
|
3657
|
-
question: question,
|
|
3658
|
-
max_answers: max_answers,
|
|
3659
|
-
include_related: include_related,
|
|
3660
|
-
cursor: cursor,
|
|
3661
|
-
proxy_country: proxy_country,
|
|
3662
|
-
})
|
|
3663
|
-
end
|
|
3664
|
-
|
|
3665
|
-
# Scrape Quora questions, answers and profiles.
|
|
3666
|
-
#
|
|
3667
|
-
# Given a Quora `question` (URL or slug), returns the `question` (`qid`, `title`, `url`,
|
|
3668
|
-
# `answerCount`, `allRelatedCount`, `followerCount`, `commentCount`, `topics`) and its
|
|
3669
|
-
# `answers`: `id`, `url`, `relation` (`answer`, `merged` for an answer to a question Quora
|
|
3670
|
-
# merged into this one, `related` with `include_related=true`), the answered `question`,
|
|
3671
|
-
# `author` (`name`, `uid`, `profileUrl`, `imageUrl`, `credential`, `isVerified`,
|
|
3672
|
-
# `isAnonymous`), the full `text` with `images` and `links`, `upvotes`, `views`, `shares`,
|
|
3673
|
-
# `comments`, `createdAt`, `updatedAt` and `isAiGenerated`; plus `relatedQuestions`. Answers
|
|
3674
|
-
# are in Quora's own order, up to `max_answers` (10 per page after the first few), unique
|
|
3675
|
-
# within a call. `nextCursor` as `cursor` continues, best-effort: Quora re-ranks the list on
|
|
3676
|
-
# every visit, so a continuation can repeat or skip answers of earlier calls (dedupe by
|
|
3677
|
-
# `id`); for a complete list ask for a larger `max_answers` in one call (up to 300).
|
|
3678
|
-
# `mode=profile&profile=` returns a public `profile` (`name`, `headline`, `description`,
|
|
3679
|
-
# follower / following / answer / question / post counts, `contentViews`, `credentials`,
|
|
3680
|
-
# `knowsAbout`, `spaces`, `topWriterYears`, `joinedAt`) with its newest `answers`. No login:
|
|
3681
|
-
# only what Quora shows an anonymous visitor - Quora's search is not available that way, and
|
|
3682
|
-
# Quora lists only a profile's newest few dozen answers to logged-out visitors
|
|
3683
|
-
# (`pagingStopped`: `quora_logged_out_limit`). `pagingStopped` otherwise names why paging
|
|
3684
|
-
# ended early (`blocked`, `time`, `unavailable`). Billed one unit per page fetched
|
|
3685
|
-
# (`pagesFetched`); a `cursor` continuation bills only its GraphQL pages.
|
|
3686
|
-
#
|
|
3687
|
-
# @param profile [String] Quora profile URL (https://www.quora.com/profile/Adam-DAngelo) or
|
|
3688
|
-
# profile slug (Adam-DAngelo). Required with mode=profile.
|
|
3689
|
-
# @param max_answers [Integer] Answers to return: 1-300 with mode=question (default 20),
|
|
3690
|
-
# 0-200 with mode=profile (default 10; 0 = profile only). Answers come 10 per page after the
|
|
3691
|
-
# first few; each page is one billed unit.
|
|
3692
|
-
# @param cursor [String] Continue after a previous call: pass its `nextCursor`. Best-effort:
|
|
3693
|
-
# each call is a new Quora visit and Quora re-ranks the list per visit, so a continuation
|
|
3694
|
-
# can repeat or skip answers of earlier calls - dedupe by answer `id`. For a complete list
|
|
3695
|
-
# ask for a larger `max_answers` in one call (up to 300).
|
|
3696
|
-
# @param proxy_country [String] Proxy country the request is sent from (ISO-2, e.g. 'US',
|
|
3697
|
-
# 'DE'). Leave blank for the countries chosen for the site.
|
|
3698
|
-
# Calls POST /social/quora.
|
|
3699
|
-
def quora_profile(profile, max_answers: nil, cursor: nil, proxy_country: nil)
|
|
3700
|
-
post_json("/social/quora", {
|
|
3701
|
-
mode: "profile",
|
|
3702
|
-
profile: profile,
|
|
3703
|
-
max_answers: max_answers,
|
|
3704
|
-
cursor: cursor,
|
|
3705
|
-
proxy_country: proxy_country,
|
|
3706
|
-
})
|
|
3707
|
-
end
|
|
3708
|
-
|
|
3709
3545
|
# Get a website's Similarweb traffic overview.
|
|
3710
3546
|
#
|
|
3711
3547
|
# Returns Similarweb's public traffic overview for `domain` as JSON: `globalRank`,
|
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.11.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-10-
|
|
11
|
+
date: 2026-10-15 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 100+ ready-made site plugins (Amazon, Walmart, Zillow, Google
|