Class: Heatwave::Crawler::Extract::Seo
- Inherits:
-
Object
- Object
- Heatwave::Crawler::Extract::Seo
- Defined in:
- app/services/heatwave/crawler/extract/seo.rb
Overview
Technical-SEO field extraction from an HTML document. Used by
:inspect mode against the rendered DOM (catches JS-injected schema
and meta that raw-HTML parsing misses) and shared with
Cache::SiteCrawler for JSON-LD extraction.
Class Method Summary collapse
-
.call(html) ⇒ Hash
Title, meta_description, canonical, robots, hreflang, h1s, schemas.
-
.extract_json_ld_schemas(html) ⇒ Array<Hash>
Extract all JSON-LD structured data blocks from HTML.
Class Method Details
.call(html) ⇒ Hash
Returns title, meta_description, canonical, robots,
hreflang, h1s, schemas.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'app/services/heatwave/crawler/extract/seo.rb', line 14 def call(html) doc = Nokogiri::HTML(html) { title: doc.at_css('title')&.text&.strip, meta_description: doc.at_css('meta[name="description"]')&.[]('content')&.strip, canonical: doc.at_css('link[rel="canonical"]')&.[]('href'), robots: doc.at_css('meta[name="robots"]')&.[]('content'), hreflang: doc.css('link[rel="alternate"][hreflang]').map do |link| { lang: link['hreflang'], href: link['href'] } end, h1s: doc.css('h1').map { |h| h.text.strip }.compact_blank, schemas: extract_json_ld_schemas(html) } end |
.extract_json_ld_schemas(html) ⇒ Array<Hash>
Extract all JSON-LD structured data blocks from HTML.
Parses tags and returns an array
of schema objects. Handles @graph containers by flattening nested
schemas.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'app/services/heatwave/crawler/extract/seo.rb', line 36 def extract_json_ld_schemas(html) doc = Nokogiri::HTML(html) schemas = [] doc.css('script[type="application/ld+json"]').each do |script| raw = script.text.strip next if raw.blank? parsed = JSON.parse(raw) # Flatten @graph containers so each schema type is a top-level entry case parsed when Hash if parsed['@graph'] Array(parsed['@graph']).each { |item| schemas << item if item.is_a?(Hash) } else schemas << parsed end when Array parsed.each { |item| schemas << item if item.is_a?(Hash) } end rescue JSON::ParserError => e Rails.logger.warn "[Crawler::Extract::Seo] Invalid JSON-LD on page: #{e.}" end schemas end |