html2rss 0.27.1 → 0.27.2
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '09b4a391aa87101ab6612c07c0c434b9ebc6198fc3bed8c14c2f8b90bd61bc6a'
|
|
4
|
+
data.tar.gz: d7fac305311719a6b131be4e89fe78919aef1b45c763a22c471b24583b41d7fa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d5fb2cdfc2b95e64de5ac42ffbe1479c15fe63b01f4b922d721d3099ffdd418c9293a1672217838612d5cf4f7bbc2e153cf83ffbcc85e8f30bf8a1a17bb20a79
|
|
7
|
+
data.tar.gz: a9f51aa30dfdf8e3e222ed1a49216e857cd056f473408273ad3781e862d743f657a67473fe691423e1fb1252fbe2935ee6eb1cef009d3b2662d03b66f7bdb90c
|
|
@@ -7,7 +7,7 @@ module Html2rss
|
|
|
7
7
|
##
|
|
8
8
|
# Maps html2rss request/response handling to botasaurus-scrape-api OpenAPI 2.0
|
|
9
9
|
# +ScrapeRequest+ / +ScrapeSuccess+ / +ScrapeError+ (sibling +openapi.yaml+).
|
|
10
|
-
class BotasaurusContract
|
|
10
|
+
class BotasaurusContract
|
|
11
11
|
# Closed set from OpenAPI ExecutionMode.
|
|
12
12
|
EXECUTION_MODES = %w[auto request browser].freeze
|
|
13
13
|
# Closed set from OpenAPI NavigationMode.
|
|
@@ -25,12 +25,19 @@ module Html2rss
|
|
|
25
25
|
# OpenAPI WindowSize required keys (positive integers).
|
|
26
26
|
WINDOW_SIZE_PROPERTIES = %i[width height].freeze
|
|
27
27
|
|
|
28
|
-
#
|
|
28
|
+
# Faraday POST /scrape cap mirroring botasaurus-scrape-api total scrape wall (`SCRAPE_TIMEOUT_SECONDS`).
|
|
29
|
+
SCRAPE_TIMEOUT_SECONDS = Integer(ENV.fetch('BOTASAURUS_SCRAPE_TIMEOUT_SECONDS', 45))
|
|
30
|
+
# Post-boot navigate/wait budget mirrored from scrape-api (`SCRAPE_WORK_TIMEOUT_SECONDS`).
|
|
31
|
+
SCRAPE_WORK_TIMEOUT_SECONDS = Integer(ENV.fetch('BOTASAURUS_SCRAPE_WORK_TIMEOUT_SECONDS', 30))
|
|
32
|
+
# Seconds added to the scrape total for client transport overhead.
|
|
33
|
+
TRANSPORT_BUFFER_SECONDS = 2
|
|
34
|
+
|
|
35
|
+
# Published wait clamp floor (`[1, SCRAPE_WORK_TIMEOUT_SECONDS]` in OpenAPI description).
|
|
29
36
|
MIN_WAIT_TIMEOUT_SECONDS = 1
|
|
30
37
|
# Published wait clamp ceiling; YAML values above this are rejected.
|
|
31
|
-
MAX_WAIT_TIMEOUT_SECONDS =
|
|
38
|
+
MAX_WAIT_TIMEOUT_SECONDS = SCRAPE_WORK_TIMEOUT_SECONDS
|
|
32
39
|
# OpenAPI wait_timeout_seconds default (omitted from the client payload).
|
|
33
|
-
DEFAULT_WAIT_TIMEOUT_SECONDS = 15
|
|
40
|
+
DEFAULT_WAIT_TIMEOUT_SECONDS = [15, SCRAPE_WORK_TIMEOUT_SECONDS].min
|
|
34
41
|
|
|
35
42
|
# OpenAPI max_retries maximum (default 2 is applied upstream when omitted).
|
|
36
43
|
MAX_RETRIES = 3
|
|
@@ -40,12 +47,6 @@ module Html2rss
|
|
|
40
47
|
# Allowlisted ChallengeSignal keys nested under diagnostics.challenge.
|
|
41
48
|
CHALLENGE_KEYS = %w[blocked detected marker].freeze
|
|
42
49
|
|
|
43
|
-
# Remaining seconds at or below which Botasaurus retries are disabled.
|
|
44
|
-
TIGHT_BUDGET_SECONDS = 12
|
|
45
|
-
|
|
46
|
-
# Seconds reserved from remaining budget before setting wait_timeout_seconds.
|
|
47
|
-
BUDGET_WAIT_RESERVE_SECONDS = 2
|
|
48
|
-
|
|
49
50
|
##
|
|
50
51
|
# Parsed OpenAPI ScrapeSuccess envelope (HTTP 200).
|
|
51
52
|
class Success
|
|
@@ -246,7 +247,6 @@ module Html2rss
|
|
|
246
247
|
# @param url [Html2rss::Url] canonical URL to scrape
|
|
247
248
|
# @param headers [Hash] request headers from context
|
|
248
249
|
# @param options [Hash] validated request.botasaurus options
|
|
249
|
-
# @param remaining_timeout_seconds [Numeric, nil] shared request budget remainder for clamps
|
|
250
250
|
# @option options [String] :execution_mode
|
|
251
251
|
# @option options [String] :navigation_mode
|
|
252
252
|
# @option options [Integer] :max_retries
|
|
@@ -264,19 +264,19 @@ module Html2rss
|
|
|
264
264
|
# @option options [String] :lang
|
|
265
265
|
# @option options [Hash] :cookies
|
|
266
266
|
# @option options [Hash] :headers
|
|
267
|
-
def initialize(url:, headers: {}, options: {}
|
|
267
|
+
def initialize(url:, headers: {}, options: {})
|
|
268
268
|
@url = url
|
|
269
269
|
@headers = headers
|
|
270
270
|
@options = options
|
|
271
|
-
@remaining_timeout_seconds = remaining_timeout_seconds
|
|
272
271
|
end
|
|
273
272
|
|
|
274
|
-
# @return [Hash] payload for POST /scrape (explicit options plus
|
|
273
|
+
# @return [Hash] payload for POST /scrape (explicit options plus wait cap)
|
|
275
274
|
def request_payload
|
|
276
275
|
payload = { url: url.to_s }.merge(filtered_options)
|
|
277
276
|
forwarded_headers = merged_headers
|
|
278
277
|
payload[:headers] = forwarded_headers if forwarded_headers&.any?
|
|
279
|
-
|
|
278
|
+
cap_wait_timeout!(payload)
|
|
279
|
+
payload
|
|
280
280
|
end
|
|
281
281
|
|
|
282
282
|
# @param transport_response [Faraday::Response] upstream HTTP response
|
|
@@ -291,7 +291,7 @@ module Html2rss
|
|
|
291
291
|
|
|
292
292
|
private
|
|
293
293
|
|
|
294
|
-
attr_reader :url, :headers, :options
|
|
294
|
+
attr_reader :url, :headers, :options
|
|
295
295
|
|
|
296
296
|
def json_object(body)
|
|
297
297
|
payload = JSON.parse(body)
|
|
@@ -315,36 +315,6 @@ module Html2rss
|
|
|
315
315
|
end
|
|
316
316
|
end
|
|
317
317
|
|
|
318
|
-
def clamp_for_budget(payload)
|
|
319
|
-
remaining = remaining_timeout_seconds
|
|
320
|
-
clamped = payload.dup
|
|
321
|
-
unless remaining.nil?
|
|
322
|
-
apply_tight_retries!(clamped, remaining)
|
|
323
|
-
apply_budget_wait!(clamped, remaining)
|
|
324
|
-
end
|
|
325
|
-
cap_wait_timeout!(clamped)
|
|
326
|
-
clamped
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
def apply_tight_retries!(payload, remaining)
|
|
330
|
-
payload[:max_retries] = 0 if remaining <= TIGHT_BUDGET_SECONDS
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
def apply_budget_wait!(payload, remaining)
|
|
334
|
-
budget_wait = budget_wait_seconds(remaining)
|
|
335
|
-
configured = payload[:wait_timeout_seconds]
|
|
336
|
-
if configured
|
|
337
|
-
payload[:wait_timeout_seconds] = [configured, budget_wait].min
|
|
338
|
-
elsif budget_wait < DEFAULT_WAIT_TIMEOUT_SECONDS
|
|
339
|
-
payload[:wait_timeout_seconds] = budget_wait
|
|
340
|
-
end
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
def budget_wait_seconds(remaining)
|
|
344
|
-
reserved = [MIN_WAIT_TIMEOUT_SECONDS, (remaining - BUDGET_WAIT_RESERVE_SECONDS).floor].max
|
|
345
|
-
[reserved, MAX_WAIT_TIMEOUT_SECONDS].min
|
|
346
|
-
end
|
|
347
|
-
|
|
348
318
|
def cap_wait_timeout!(payload)
|
|
349
319
|
wait = payload[:wait_timeout_seconds]
|
|
350
320
|
return unless wait
|
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
require 'faraday'
|
|
4
4
|
require 'json'
|
|
5
|
+
require 'securerandom'
|
|
5
6
|
|
|
6
7
|
module Html2rss
|
|
7
8
|
class RequestService
|
|
8
9
|
##
|
|
9
10
|
# Strategy to delegate fetching to a Botasaurus scrape API.
|
|
10
11
|
class BotasaurusStrategy < Strategy
|
|
12
|
+
# Content-Type negotiation for the scrape API transport hop.
|
|
13
|
+
TRANSPORT_ACCEPT = 'application/json'
|
|
14
|
+
# Disable compressed bodies so Faraday returns raw JSON without implicit decoding surprises.
|
|
15
|
+
TRANSPORT_ENCODING = 'identity'
|
|
16
|
+
# Correlates each POST /scrape with botasaurus-scrape-api request logs.
|
|
17
|
+
REQUEST_ID_HEADER = 'X-Request-Id'
|
|
18
|
+
|
|
11
19
|
private
|
|
12
20
|
|
|
13
21
|
def fetch
|
|
@@ -18,7 +26,9 @@ module Html2rss
|
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
def post_scrape_request
|
|
21
|
-
|
|
29
|
+
request_id = SecureRandom.uuid
|
|
30
|
+
Log.debug("#{self.class}: POST /scrape #{REQUEST_ID_HEADER}=#{request_id}")
|
|
31
|
+
transport_response = client.post('/scrape', JSON.generate(contract.request_payload), post_headers(request_id))
|
|
22
32
|
contract.parse_response(transport_response)
|
|
23
33
|
end
|
|
24
34
|
|
|
@@ -64,13 +74,28 @@ module Html2rss
|
|
|
64
74
|
@contract ||= BotasaurusContract.new(
|
|
65
75
|
url: ctx.url,
|
|
66
76
|
headers: ctx.headers,
|
|
67
|
-
options: ctx.request.fetch(:botasaurus, {})
|
|
68
|
-
remaining_timeout_seconds: attempt_timeout_seconds
|
|
77
|
+
options: ctx.request.fetch(:botasaurus, {})
|
|
69
78
|
)
|
|
70
79
|
end
|
|
71
80
|
|
|
72
81
|
def client
|
|
73
|
-
|
|
82
|
+
# No :gzip middleware on this client — compression is for remote target fetches only.
|
|
83
|
+
@client ||= Faraday.new(url: scraper_base_url.to_s, headers: client_headers, request: request_options)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def client_headers
|
|
87
|
+
{
|
|
88
|
+
'User-Agent' => Config::RequestHeaders::DEFAULT_USER_AGENT,
|
|
89
|
+
'Accept' => TRANSPORT_ACCEPT,
|
|
90
|
+
'Accept-Encoding' => TRANSPORT_ENCODING
|
|
91
|
+
}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def post_headers(request_id)
|
|
95
|
+
{
|
|
96
|
+
'Content-Type' => 'application/json',
|
|
97
|
+
REQUEST_ID_HEADER => request_id
|
|
98
|
+
}
|
|
74
99
|
end
|
|
75
100
|
|
|
76
101
|
def request_options
|
|
@@ -78,13 +103,10 @@ module Html2rss
|
|
|
78
103
|
end
|
|
79
104
|
|
|
80
105
|
def attempt_timeout_seconds
|
|
81
|
-
@attempt_timeout_seconds ||=
|
|
82
|
-
fallback: ctx.policy.total_timeout_seconds
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def content_type_header
|
|
87
|
-
{ 'Content-Type' => 'application/json' }
|
|
106
|
+
@attempt_timeout_seconds ||= begin
|
|
107
|
+
budget = ctx.budget.effective_timeout_seconds(fallback: ctx.policy.total_timeout_seconds)
|
|
108
|
+
[budget, BotasaurusContract::SCRAPE_TIMEOUT_SECONDS + BotasaurusContract::TRANSPORT_BUFFER_SECONDS].min
|
|
109
|
+
end
|
|
88
110
|
end
|
|
89
111
|
|
|
90
112
|
def scraper_base_url
|
data/lib/html2rss/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: html2rss
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.27.
|
|
4
|
+
version: 0.27.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gil Desmarais
|
|
@@ -486,7 +486,7 @@ licenses:
|
|
|
486
486
|
- MIT
|
|
487
487
|
metadata:
|
|
488
488
|
allowed_push_host: https://rubygems.org
|
|
489
|
-
changelog_uri: https://github.com/html2rss/html2rss/releases/tag/v0.27.
|
|
489
|
+
changelog_uri: https://github.com/html2rss/html2rss/releases/tag/v0.27.2
|
|
490
490
|
rubygems_mfa_required: 'true'
|
|
491
491
|
rdoc_options: []
|
|
492
492
|
require_paths:
|