Skip to content
Oeiuwq Faith Blog OpenSource Porfolio

ericchiang/pup

Parsing HTML at the command line

ericchiang/pup.json
{
"createdAt": "2014-09-01T01:31:29Z",
"defaultBranch": "master",
"description": "Parsing HTML at the command line",
"fullName": "ericchiang/pup",
"homepage": "",
"language": "HTML",
"name": "pup",
"pushedAt": "2024-05-02T13:43:38Z",
"stargazersCount": 8361,
"topics": [],
"updatedAt": "2025-11-24T08:14:50Z",
"url": "https://github.com/ericchiang/pup"
}

pup is a command line tool for processing HTML. It reads from stdin, prints to stdout, and allows the user to filter parts of the page using CSS selectors.

Inspired by jq, pup aims to be a fast and flexible way of exploring HTML from the terminal.

Direct downloads are available through the releases page.

If you have Go installed on your computer just run go get.

go get github.com/ericchiang/pup

If you’re on OS X, use Homebrew to install (no Go required).

brew install https://raw.githubusercontent.com/EricChiang/pup/master/pup.rb
Terminal window
$ curl -s https://news.ycombinator.com/

Ew, HTML. Let’s run that through some pup selectors:

Terminal window
$ curl -s https://news.ycombinator.com/ | pup 'table table tr:nth-last-of-type(n+2) td.title a'

Okay, how about only the links?

Terminal window
$ curl -s https://news.ycombinator.com/ | pup 'table table tr:nth-last-of-type(n+2) td.title a attr{href}'

Even better, let’s grab the titles too:

Terminal window
$ curl -s https://news.ycombinator.com/ | pup 'table table tr:nth-last-of-type(n+2) td.title a json{}'
Terminal window
$ cat index.html | pup [flags] '[selectors] [display function]'

Download a webpage with wget.

Terminal window
$ wget http://en.wikipedia.org/wiki/Robots_exclusion_standard -O robots.html

By default pup will fill in missing tags and properly indent the page.

Terminal window
$ cat robots.html
# nasty looking HTML
$ cat robots.html | pup --color
# cleaned, indented, and colorful HTML
Terminal window
$ cat robots.html | pup 'title'
<title>
Robots exclusion standard - Wikipedia, the free encyclopedia
</title>
Terminal window
$ cat robots.html | pup 'span#See_also'
<span class="mw-headline" id="See_also">
See also
</span>
Terminal window
$ cat robots.html | pup 'th[scope="row"]'
<th scope="row" class="navbox-group">
Exclusion standards
</th>
<th scope="row" class="navbox-group">
Related marketing topics
</th>
<th scope="row" class="navbox-group">
Search marketing related topics
</th>
<th scope="row" class="navbox-group">
Search engine spam
</th>
<th scope="row" class="navbox-group">
Linking
</th>
<th scope="row" class="navbox-group">
People
</th>
<th scope="row" class="navbox-group">
Other
</th>

CSS selectors have a group of specifiers called [“pseudo classes”]!( https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes) which are pretty cool. pup implements a majority of the relevant ones them.

Here are some examples.

Terminal window
$ cat robots.html | pup 'a[rel] !:empty'
<a rel="license" href="//creativecommons.org/licenses/by-sa/3.0/" style="display:none;">
</a>
Terminal window
$ cat robots.html | pup ':contains("History")'
<span class="toctext">
History
</span>
<span class="mw-headline" id="History">
History
</span>
Terminal window
$ cat robots.html | pup ':parent-of([action="edit"])'
<span class="wb-langlinks-edit wb-langlinks-link">
<a action="edit" href="//www.wikidata.org/wiki/Q80776#sitelinks-wikipedia" text="Edit links" title="Edit interlanguage links" class="wbc-editpage">
Edit links
</a>
</span>

For a complete list, view the [implemented selectors]!(#implemented-selectors) section.

These are intermediate characters that declare special instructions. For instance, a comma , allows pup to specify multiple groups of selectors.

Terminal window
$ cat robots.html | pup 'title, h1 span[dir="auto"]'
<title>
Robots exclusion standard - Wikipedia, the free encyclopedia
</title>
<span dir="auto">
Robots exclusion standard
</span>

When combining selectors, the HTML nodes selected by the previous selector will be passed to the next ones.

Terminal window
$ cat robots.html | pup 'h1#firstHeading'
<h1 id="firstHeading" class="firstHeading" lang="en">
<span dir="auto">
Robots exclusion standard
</span>
</h1>
Terminal window
$ cat robots.html | pup 'h1#firstHeading span'
<span dir="auto">
Robots exclusion standard
</span>

For further examples of these selectors head over to [MDN]!( https://developer.mozilla.org/en-US/docs/Web/CSS/Reference).

Terminal window
pup '.class'
pup '#id'
pup 'element'
pup 'selector + selector'
pup 'selector > selector'
pup '[attribute]'
pup '[attribute="value"]'
pup '[attribute*="value"]'
pup '[attribute~="value"]'
pup '[attribute^="value"]'
pup '[attribute$="value"]'
pup ':empty'
pup ':first-child'
pup ':first-of-type'
pup ':last-child'
pup ':last-of-type'
pup ':only-child'
pup ':only-of-type'
pup ':contains("text")'
pup ':nth-child(n)'
pup ':nth-of-type(n)'
pup ':nth-last-child(n)'
pup ':nth-last-of-type(n)'
pup ':not(selector)'
pup ':parent-of(selector)'

You can mix and match selectors as you wish.

Terminal window
cat index.html | pup 'element#id[attribute="value"] !:first-of-type'

Non-HTML selectors which effect the output type are implemented as functions which can be provided as a final argument.

Print all text from selected nodes and children in depth first order.

Terminal window
$ cat robots.html | pup '.mw-headline text{}'
History
About the standard
Disadvantages
Alternatives
Examples
Nonstandard extensions
Crawl-delay directive
Allow directive
Sitemap
Host
Universal "*" match
Meta tags and headers
See also
References
External links

Print the values of all attributes with a given key from all selected nodes.

Terminal window
$ cat robots.html | pup '.catlinks div attr{id}'
mw-normal-catlinks
mw-hidden-catlinks

Print HTML as JSON.

Terminal window
$ cat robots.html | pup 'div#p-namespaces a'
<a href="/wiki/Robots_exclusion_standard" title="View the content page [c]" accesskey="c">
Article
</a>
<a href="/wiki/Talk:Robots_exclusion_standard" title="Discussion about the content page [t]" accesskey="t">
Talk
</a>
Terminal window
$ cat robots.html | pup 'div#p-namespaces a json{}'
[
{
"accesskey": "c",
"href": "/wiki/Robots_exclusion_standard",
"tag": "a",
"text": "Article",
"title": "View the content page [c]"
},
{
"accesskey": "t",
"href": "/wiki/Talk:Robots_exclusion_standard",
"tag": "a",
"text": "Talk",
"title": "Discussion about the content page [t]"
}
]

Use the -i / --indent flag to control the intent level.

Terminal window
$ cat robots.html | pup -i 4 'div#p-namespaces a json{}'
[
{
"accesskey": "c",
"href": "/wiki/Robots_exclusion_standard",
"tag": "a",
"text": "Article",
"title": "View the content page [c]"
},
{
"accesskey": "t",
"href": "/wiki/Talk:Robots_exclusion_standard",
"tag": "a",
"text": "Talk",
"title": "Discussion about the content page [t]"
}
]

If the selectors only return one element the results will be printed as a JSON object, not a list.

Terminal window
$ cat robots.html | pup --indent 4 'title json{}'
{
"tag": "title",
"text": "Robots exclusion standard - Wikipedia, the free encyclopedia"
}

Because there is no universal standard for converting HTML/XML to JSON, a method has been chosen which hopefully fits. The goal is simply to get the output of pup into a more consumable format.

Run pup --help for a list of further options