What tool (preferably for Linux) can select the content of an HTML element based on its CSS path?


For example, consider the following HTML document:

  <div class="header">
  <div class="content">
      <tr><td class="data">Tabular Content 1</td></tr>
      <tr><td class="data">Tabular Content 2</td></tr>
  <div class="footer">

What command-line program (e.g., a kind of "cssgrep") can extract values using a CSS selector? That is:

cssgrep page.html "body > div.content > table > tbody > tr > td.data"

The program would write the following to standard output:

Tabular Content 1
Tabular Content 2

Related Links

Thank you!

4 Answers 4


Use the W3C tools for HTML/XML parsing and extraction of content using CSS selectors. For example:

hxnormalize -l 240 -x filename.html | hxselect -s '\n' -c "td.data"

Will produce the desired output:

Tabular Content 1
Tabular Content 2

Using a line length of 240 characters ensures that elements with long content will not be split across multiple lines. The hxnormalize -x command creates a well-formed XML document, which can be used by hxselect.

  • 3
    For macOS users, brew install html-xml-utils.
    – anishpatel
    May 5, 2018 at 20:11
  • @dave-jarvis If I use the hxnormalize -x on a RSS file, I loose out the results in the end somehow : hxnormalize -l 240 -x rss.html | hxselect -s '\n' -c 'item > link' but if I don't normalize by just using a cat rss.html | hxselect -s '\n' -c 'item > link', then I get all the results.
    – SebMa
    Jul 24, 2021 at 19:31
  • To retrieve an attribute's value, use the syntax <node>::attr(<attribute>). In OP's example, td::attr(class) will yield data\ndata. Aug 21, 2021 at 6:26
  • @dave-jarvis, thank you very much for the answer. The tools are quite fantastic to use. You can even use pseudo-classes like: <node>.class:first-of-type.
    – rolandog
    Nov 25, 2021 at 22:43

CSS Solution

The Element Finder command will partially accomplish this task:

For example:

elfinder -j -s td.data -x "html"

This renders the result in JSON format, which can be extracted.

XML Solution

The XML::Twig module ("sudo apt-get install xml-twig-tools") comes with a tool named xml_grep that is able to do just that, provided that your HTML is well-formed, of course.

I'm sorry I'm not able to test this at the moment, but something like this should work:

xml_grep -t '*/div[@class="content"]/table/tbody/tr/td[@class="data"]' file.html
  • The current elfinder (v0.5.2) does not output the 25 results it claims to have found on my RSS file : elfinder -s 'item > link' -f rss.html, be it in text or JSON format.
    – SebMa
    Jul 24, 2021 at 19:47

https://github.com/ericchiang/pup has a CSS-based query language that conforms closely to your example. In fact, with your input, the following command:

pup "body > div.content > table > tbody > tr > td.data text{}"


Tabular Content 1
Tabular Content 2

The trailing text{} removes the HTML tags.

One nice feature is that the full path need not be given, so that again with your example:

$ pup 'td.data text{}' < input.html
Tabular Content 1
Tabular Content 2

One advantage of pup is that it uses the golang.org/x/net/html package for parsing HTML5.

  • 1
    +1 CSS selectors are more concise than xpath, though less powerful. Pup also comes packaged in a single executable.
    – ATorras
    Apr 28, 2021 at 19:05

Node can do that with JQuery and a fake DOM.

I made a Docker image for that (https://hub.docker.com/r/phil294/jquery-jsdom/):

docker run --rm -i phil294/jquery-jsdom '$("body > div.content > table > tbody > tr > td.data").text()' < page.html

Second argument is JavaScript code, so you can do anything you want, really.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.