Lexbor

June 20, 2026 · View on GitHub

Build Status

Crystal lang wrapper for the C library lexbor/lexbor — a fast HTML5 parser with CSS selectors.

Add this to your application's shard.yml:

dependencies:
  lexbor:
    github: kostya/lexbor

Usage example

require "lexbor"

html = <<-HTML
  <html>
    <body>
      <div id="t1" class="red">
        <a href="/#">O_o</a>
      </div>
      <div id="t2"></div>
    </body>
  </html>
HTML

lexbor = Lexbor.new(html)

lexbor.nodes(:div) do |node|
  id = node["id"]?

  if first_link = node.nodes(:a).first?
    href = first_link["href"]?
    link_text = first_link.inner_text

    puts "div with id #{id} have link [#{link_text}](#{href})"
  else
    puts "div with id #{id} have no links"
  end
end

# Output:
#   div with id t1 have link [O_o](/#)
#   div with id t2 have no links

Css selectors example

require "lexbor"

html = <<-HTML
  <html>
    <body>
      <table id="t1">
        <tr><td>Hello</td></tr>
      </table>
      <table id="t2">
        <tr><td>123</td><td>other</td></tr>
        <tr><td>foo</td><td>columns</td></tr>
        <tr><td>bar</td><td>are</td></tr>
        <tr><td>xyz</td><td>ignored</td></tr>
      </table>
    </body>
  </html>
HTML

lexbor = Lexbor.new(html)

p lexbor.css("#t2 tr td:first-child").map(&.inner_text).to_a
# => ["123", "foo", "bar", "xyz"]

lexbor.css("#t2 tr td:first-child") do |node|
  puts node.to_html
end
# => <td>123</td>
# => <td>foo</td>
# => <td>bar</td>
# => <td>xyz</td>

lexbor.css("#t2 tr") do |node|
  node.css("td:first-child") do |node2|
    puts node2.to_html
  end
end
# => <td>123</td>
# => <td>foo</td>
# => <td>bar</td>
# => <td>xyz</td>

More Examples

examples

Development Setup:

git clone https://github.com/kostya/lexbor.git
cd lexbor
crystal src/ext/build_ext.cr
crystal spec

Benchmark

Parse google results page(1.5Mb) 1000 times, and 5000 times css select.

lexbor-program myhtml-program crystagiri-program nokogiri-program

Running on Ryzen 3800x.

LangLibParse time, sCss time, sMemory, MiB
Ruby 2.7Nokolexbor(lexbor)4.071.80112.5
Crystallexbor4.750.8012.3
Crystalmyhtml(+modest)5.981.2212.2
CrystalCrystagiri(libxml2)14.20-31.7
Ruby 2.7Nokogiri(libxml2)18.6792.69398.4

Running on Apple M1.

LangLibParse time, sCss time, sMemory, MiB
Crystallexbor2.770.6226.4
Ruby 2.7Nokolexbor(lexbor)3.411.11268.8
Ruby 2.7Nokogiri(libxml2)18.2287.21232.8
CrystalCrystagiri(libxml2)126.25-26.8