A little help goes a long way. Find a tool/

Developer FIELD NOTES · 4 MIN READ

Taking HTML Apart: Extracting Tags, Classes, and Attributes

How to inventory an HTML page: tag counts, classes and IDs, attribute values, why void elements make the counts unequal, and why not regex.

View-source shows you everything at once, which is another way of saying it shows you nothing in particular. When you want to know what a page is actually made of — which tags appear, how many, what classes the stylesheets are aiming at, which IDs exist — you want the parts list, not the document. Tag extraction turns markup into an inventory: counts, names, and the attribute values that bind the HTML to its CSS and scripts.

What an inventory counts

Feed the extractor a small document and it reports several tallies at once — opening tags, closing tags, comments, and whether a doctype is present. For this input:

<!DOCTYPE html>
<!-- header nav -->
<html>
  <body class="page dark">
    <div id="main" class="wrap">
      <p>Hi</p><p data-x="1">Yo</p>
      <img src="a.png" alt="A">
    </div>
  </body>
</html>

the numbers come back as 6 opening tags, 5 closing tags, 1 comment, and a doctype — with a per-tag breakdown: html 1, body 1, div 1, p 2, img 1. Each opening tag also comes with its raw source text and character position, so <body class="page dark"> is reported verbatim and can be located in the original file.

The count that is allowed to be unequal

Six opening tags, five closing tags, and the document is fine. The <img> element is void: HTML defines it as having no content and no closing tag, and the same goes for br, input, meta, link, hr, and friends. So an opening-versus-closing mismatch is not automatically an error — it is expected whenever void elements appear. What the mismatch is good for is spotting real sloppiness: a document with twelve <div>s and eleven </div>s has a structural bug, and the per-tag counts expose exactly which element is unbalanced.

Classes, IDs, and the attributes that matter

Classes and IDs are where HTML meets CSS and JavaScript, so the extractor treats them specially. A class attribute is split on whitespace — class="page dark" contributes two entries, page and dark — and the tool reports both the unique list (here page, dark, wrap) and how many times each appears, which is a quick way to see which style hooks a page leans on. IDs come back deduplicated, since they are supposed to be unique anyway. Beyond those, common attributes are collected with their values: src has a.png, alt has A, href, title, name, type, value, rel, and target fill out the set. Attribute values are HTML-decoded, so title="Tom &amp; Jerry" is reported as Tom & Jerry — the way entities work is covered in How HTML Entities Work.

Why not just run a regex

The temptation is always "it's just find <(\w+)". It fails on the first realistic page: a quoted attribute value can contain a >, comments can contain complete fake tags, and <p data-x="1"> must yield p with attributes, not a tag named p-data-x. Regular expressions match flat text and cannot balance nesting — How Regular Expressions Work explains why nested structures are their hard limit. A small purpose-built scanner that walks the markup, skips comments, and tracks quoted attribute values gets all of these right because it is doing one narrow job.

Inventory, not validator

The tool answers "what is here", not "is this correct". Unbalanced counts, duplicate IDs, and classes nothing styles will all show up in the report — but as observations, not verdicts. That is the right contract for the common tasks: auditing which CSS hooks exist before refactoring styles, checking that a CMS-generated page emits the elements you expect, counting images for an accessibility pass, or diffing two pages' structure by comparing their inventories.

Try it yourself

Paste the sample document above into the HTML Tag Extractor and verify the counts — then paste a page from a real project and see how fast the class list grows. To see the opposite operation, the HTML to Text converter strips the tags and keeps the words, and the HTML Minifier shows what the same markup looks like once every removable byte is gone.

Frequently asked questions

How is tag extraction different from converting HTML to text?
They are opposite reductions. HTML-to-text strips the tags and keeps the words — the content view. Tag extraction keeps the tags and reports the structure — tag names, counts, classes, IDs, attributes — while the prose is ignored. Use to-text when you want what a page says; use the extractor when you want what it is built from.
Why are there more opening tags than closing tags?
Void elements never close. An <img> tag has no </img> by definition, and the same applies to br, input, meta, link, and hr. So a document with one image legitimately shows 6 opening and 5 closing tags. A mismatch only signals a bug when it appears within a tag type that does close — say twelve <div>s against eleven </div>s.
Which attributes does it collect?
The commonly load-bearing set: href, src, alt, title, class, id, name, type, value, rel, and target. class values are split on whitespace so class="page dark" yields two entries, and both a unique list and a per-class count are reported. IDs are deduplicated, since they are meant to be unique in the first place.
Does it decode HTML entities in attribute values?
Yes. Attribute values are reported after entity decoding, so title="Tom &amp; Jerry" comes back as Tom & Jerry — the same way a browser reads it. If you need the raw escaped form instead, that is the job of an entity encoder, which reverses the process.
Can it tell me whether my HTML is valid?
No — it is an inventory, not a validator. It will surface symptoms such as unbalanced div counts or duplicate IDs, but it will not judge nesting or report spec violations, and unequal open/close counts are often perfectly legal because of void elements. Treat the report as a parts list you interpret, not a verdict.