scrape_creators 0.7.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 385c61c807a5dd2f2f1d7106b9430991d97ba68d5e894b6675d58d324243e1c3
4
- data.tar.gz: 6293f02f4f4724cc2e6b1a11447e66c38ac2440db19f2b31b362a1a260757d81
3
+ metadata.gz: 81c09defede693eaa2d2a5096d7d9be96179e236e48ff2f49c4bce865be49773
4
+ data.tar.gz: d1978cf6dc4d1d3feaf1fbdb128be6aca6ed45d7269aa1b6991615b25207d509
5
5
  SHA512:
6
- metadata.gz: 16846f8a031d0629aece90c2b59ae7f59026a4de1507f0e17a35d036b7c18efb185cdc619babf04bbbe1b81dc4b792ce186d576e58dc7cbd8bea8e33098e6d59
7
- data.tar.gz: e7d80c9c3d21e7b1482776421c9f70ab6a33759ff3e8ec20d674e2b638dd146084917cb4966158b9b2451a8077ea72981f0500b767a9c8a333b407a58ea9f5c7
6
+ metadata.gz: 2db5b1d62794c71c70292bb4225e651ae84cd7558adcb8bb7db4be79b66324096defc3274f9d69c9db4fc86d6299a8b74d16c139bc125c47bca7c78a75f8dca4
7
+ data.tar.gz: ece660c23bb218af965016f85ca918b08c964939ecb3012ac8fb0a7b23bccf7383631975812d35230bef3170139442fd2f25be05b7a4f020c044f5a4cfb1cb97
data/README.md CHANGED
@@ -7,7 +7,7 @@ A zero-dependency Ruby client for the [Scrape Creators API](https://docs.scrapec
7
7
  Add this line to your application's Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'scrape_creators', '0.6.0'
10
+ gem 'scrape_creators', '0.8.0'
11
11
  ```
12
12
 
13
13
  And then execute:
@@ -85,6 +85,36 @@ info = scraper.post("https://www.instagram.com/p/DKSMEpKRd6h/", download_media:
85
85
  comments = scraper.comments("https://www.instagram.com/p/DKSMEpKRd6h/")
86
86
  ```
87
87
 
88
+ ### Comment pagination
89
+
90
+ `comments` returns the first page by default. Pass `pages:` to collect several pages:
91
+
92
+ ```ruby
93
+ comments = scraper.comments(video_url, source: 'instagram', pages: 5)
94
+ ```
95
+
96
+ Use `comments_page` for an initial batch followed by a Load more button. It returns
97
+ `{ comments:, cursor:, has_more: }` for Instagram, TikTok, and YouTube:
98
+
99
+ ```ruby
100
+ page = scraper.comments_page(video_url, source: 'instagram')
101
+
102
+ # When the user asks for more:
103
+ if page[:has_more]
104
+ page = scraper.comments_page(video_url, source: 'instagram', cursor: page[:cursor])
105
+ end
106
+ ```
107
+
108
+ Pass the returned cursor unchanged. The client translates it to YouTube's
109
+ `continuationToken` parameter and uses `cursor` for Instagram and TikTok. TikTok's
110
+ `has_more` flag is respected; missing or unchanged cursors stop pagination.
111
+ Multi-page collection also stops if a cursor repeats. Failed API responses raise
112
+ `ScrapeCreators::APIError` so callers can retry without losing their place.
113
+
114
+ API documentation: [Instagram](https://docs.scrapecreators.com/v2/instagram/post/comments/),
115
+ [TikTok](https://docs.scrapecreators.com/v1/tiktok/video/comments/),
116
+ [YouTube](https://docs.scrapecreators.com/v1/youtube/video/comments/).
117
+
88
118
  ## License
89
119
 
90
120
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -137,12 +137,33 @@ module ScrapeCreators
137
137
  end
138
138
 
139
139
  def comments(url_or_code, options = {})
140
- url = normalize_url(url_or_code)
141
- params = { url: url }.merge(options)
142
- source = options.dig(:source) || 'instagram'
143
- comments_url = comments_url_for(source:)
144
- res = get(comments_url, params)
145
- res.is_a?(Hash) ? (res["comments"] || []) : []
140
+ pages = options[:pages] || options[:max_pages] || 1
141
+ cursor = options[:cursor]
142
+ seen_cursors = {}
143
+ all_comments = []
144
+
145
+ pages.to_i.times do
146
+ break if seen_cursors[cursor.to_s]
147
+
148
+ seen_cursors[cursor.to_s] = true
149
+ page = comments_page(url_or_code, options.merge(cursor: cursor))
150
+ all_comments.concat(page[:comments])
151
+ break unless page[:has_more]
152
+
153
+ cursor = page[:cursor]
154
+ end
155
+
156
+ all_comments
157
+ end
158
+
159
+ def comments_page(url_or_code, options = {})
160
+ source = (options[:source] || INSTAGRAM).to_s
161
+ raise ArgumentError, "Unsupported comments source: #{source}" unless [INSTAGRAM, TIKTOK, YOUTUBE].include?(source)
162
+
163
+ cursor = options[:cursor] || options['cursor']
164
+ params = comments_params(url_or_code, source, cursor, options)
165
+ response = get(comments_url_for(source: source), params)
166
+ comments_result(response, source, cursor)
146
167
  end
147
168
 
148
169
  def get(endpoint, params = {}, options = {})
@@ -185,6 +206,29 @@ module ScrapeCreators
185
206
 
186
207
  private
187
208
 
209
+ def comments_cursor_key(source)
210
+ source == YOUTUBE ? 'continuationToken' : 'cursor'
211
+ end
212
+
213
+ def comments_params(url_or_code, source, cursor, options)
214
+ params = options.reject { |key, _| %w[source cursor pages max_pages].include?(key.to_s) }
215
+ params[:url] = normalize_url(url_or_code)
216
+ params[comments_cursor_key(source)] = cursor unless cursor.nil? || cursor.to_s.empty?
217
+ params
218
+ end
219
+
220
+ def comments_result(response, source, cursor)
221
+ unless response.is_a?(Hash) && response['success'] != false && response['comments'].is_a?(Array)
222
+ raise APIError, 'Unable to fetch comments'
223
+ end
224
+
225
+ next_cursor = response[comments_cursor_key(source)]&.to_s
226
+ next_cursor = nil if next_cursor.to_s.empty? || next_cursor == '0'
227
+ has_more = !next_cursor.nil? && next_cursor != cursor.to_s
228
+ has_more &&= [true, 1, '1'].include?(response['has_more']) if source == TIKTOK
229
+ { comments: response['comments'], cursor: next_cursor, has_more: has_more }
230
+ end
231
+
188
232
  def search_results(response)
189
233
  unless response.is_a?(Hash) && response['success'] != false
190
234
  raise APIError, 'Account search failed'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ScrapeCreators
4
- VERSION = "0.7.0"
4
+ VERSION = "0.8.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scrape_creators
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - swlkr