Class: Retailer::Extractors::HomeDepot
- Inherits:
-
Base
- Object
- Base
- Retailer::Extractors::HomeDepot
- Defined in:
- app/services/retailer/extractors/home_depot.rb
Overview
Home Depot data extractor (USA and Canada).
Uses JSON-LD and data-automation selectors.
Constant Summary collapse
- RENDER_REQUIRED =
SPA-heavy site; price markup is rendered client-side. Keep on.
true- WEB_UNBLOCKER_FALLBACK =
Retry an empty Scraper API response through the Web Unblocker.
Home Depot intermittently serves nothing at all — on 2026-08-08 it returned
0 bytes for newly-covered AND long-working items alike, repeatedly, then
recovered — and Oxylabs publishes no dedicated home_depot source, so
universalplus this fallback is the whole toolkit. true
Class Method Summary collapse
-
.build_payload(url:, geo_location: nil) ⇒ Hash
Build Oxylabs payload for Home Depot product scraping Uses 'universal' source with JS rendering for reliable results.
-
.search_payload(query:, geo_location: nil) ⇒ Hash
Build payload for Home Depot search.
-
.storefront_geo(catalog) ⇒ String
Storefront country for the unblocker fallback.
Instance Method Summary collapse
Class Method Details
.build_payload(url:, geo_location: nil) ⇒ Hash
Build Oxylabs payload for Home Depot product scraping
Uses 'universal' source with JS rendering for reliable results.
Enables redirect following to capture final canonical URL.
47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'app/services/retailer/extractors/home_depot.rb', line 47 def self.build_payload(url:, geo_location: nil) payload = { source: 'universal', url: url, render: render_value, context: [ { key: 'follow_redirects', value: true } ] }.compact payload[:geo_location] = geo_location if geo_location.present? payload end |
.search_payload(query:, geo_location: nil) ⇒ Hash
Build payload for Home Depot search
64 65 66 67 |
# File 'app/services/retailer/extractors/home_depot.rb', line 64 def self.search_payload(query:, geo_location: nil) url = "https://www.homedepot.com/s/#{CGI.escape(query)}" build_payload(url: url, geo_location: geo_location) end |
.storefront_geo(catalog) ⇒ String
Storefront country for the unblocker fallback.
Deliberately COUNTRY-level, not the ZIP the Scraper API probe pins. Web
Unblocker only honours a ZIP for Amazon targets; for a generic retail site
it documents country granularity alone, and silently ignores anything
finer. Passing "60047" through it therefore does not select an Illinois
store — it selects nothing, and we egress from wherever the pool lands
(an actual run exited via Toronto against the US catalog, which would have
read a Canadian storefront).
Home Depot does price per store, so country-level would be a real risk if
our SKUs varied by store. Measured 2026-08-08 across five products —
SS-01, TWS2-TAH07KH, TW-E4PCP, TCT120-KIT-OT-040, TW-SR08KS-HP — the
country-level price matched the ZIP-60047 price to the cent every time, so
Home Depot prices this catalogue nationally and the fallback is
comparable to the primary path. Re-check that if the assortment changes.
36 37 38 |
# File 'app/services/retailer/extractors/home_depot.rb', line 36 def self.storefront_geo(catalog) catalog.country_iso3 == 'CAN' ? 'Canada' : 'United States' end |
Instance Method Details
#extract(check, content) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'app/services/retailer/extractors/home_depot.rb', line 69 def extract(check, content) return unless valid_html?(content) check.scraper_source = source_name check.currency = catalog.id == HOME_DEPOT_CANADA ? 'CAD' : 'USD' doc = parse_html(content) # Check availability check.product_available = doc.at_css('[data-automation="add-to-cart"]').present? || content.include?('Add to Cart') || content.exclude?('Out of Stock') # JSON-LD structured data (most reliable) extract_json_ld_price(check, doc) # Fallback: Home Depot price selectors extract_from_selectors(check, doc) if check.price.blank? # Extract title check.raw_title = extract_title(doc) end |