Skip to main content

html-shrinker

Simple Python helper library that can significantly reduce LLM input tokens by removing unnecessary page code (configurable).

AI scraping usually involves sending the whole page code to an LLM + instructions + output format. 99.9% of the time the information needed is somewhere in the body tag of the page, thus we can safely remove the whole head tag which contains a ton of styles and scripts and metadata that are not needed. This alone reduces the tokens/costs significantly. Further optimizations can be made, like removing specific html tags, attributes or even the innertext.

What it does

  • Removes noisy tags/attributes or keeps only a whitelist
  • Strips inner text
  • Removes comments
  • Flattens repeated single-child div > div wrappers, even if they are nested many levels deep
  • Collapses whitespace between tags

Quick install

pip install html-shrinker

Quick start

from html_shrinker import HTMLShrinker
from html_shrinker.defaults import tags

raw_html = """
<html>
  <head><script>ignore me</script></head>
  <body>
    <div><div><p>Hello world</p></div></div>
    <script>alert("x")</script>
  </body>
</html>
"""

shrinker = HTMLShrinker(
    tags=list(tags),
)
result = shrinker.shrink(raw_html)
print(result)

API

from html_shrinker import HTMLShrinker

shrinker = HTMLShrinker(
    tag_mode="remove",
    tags=["script", "style", "head"],
    attribute_mode="remove",
    attributes=["class", "id", "style"],
    strip_innertext=False,
    remove_comments=True,
    flatten_single_child_divs=True,
    collapse_between_tags=True,
)

output = shrinker.shrink("<html>...</html>")

Default presets are available from:

from html_shrinker.defaults import tags, arguments

Invalid HTML input raises InvalidHTMLInputError:

from html_shrinker import HTMLShrinker, InvalidHTMLInputError

try:
    HTMLShrinker().shrink("<div>fragment</div>")
except InvalidHTMLInputError as exc:
    print(exc)

Configuration

HTMLShrinker(...) constructor parameters:

  • tag_mode: "remove" or "keep" (default: "remove")
  • tags: list[str]
    • If tag_mode="remove": these tags are removed.
    • If tag_mode="keep": only these tags are kept.
  • attribute_mode: "remove" or "keep" (default: "remove")
  • attributes: list[str]
    • If attribute_mode="remove": these attributes are removed.
    • If attribute_mode="keep": only these attributes are kept.
  • strip_innertext: bool (default: False)
    • If True: removes text nodes.
    • Example: <p>secret</p> becomes <p></p>.
  • remove_comments: bool (default: True)
    • If True: removes HTML comments such as <!-- comment -->.
  • flatten_single_child_divs: bool (default: True)
    • If True: flattens nested div > div wrappers when a div contains only one child div.
    • This is applied repeatedly, so a deep chain like <div><div><div><p>...</p></div></div></div> becomes <div><p>...</p></div>.
    • These large div chains appear very often when shrinking aggresively.
  • collapse_between_tags: bool (default: True)
    • If True: removes whitespace between tags, so > < becomes ><.

Notes:

  • Default tags is empty ([]), so no tags are removed by default.
  • Default attributes is empty ([]), so no attributes are removed by default.
  • If tag_mode="keep", tags must be non-empty.
  • If attribute_mode="keep", attributes must be non-empty.

Usage patterns

1) Remove mode (default)

from html_shrinker import HTMLShrinker

shrinker = HTMLShrinker(
    tag_mode="remove",
    tags=["script", "style", "head"],
    attribute_mode="remove",
    attributes=["class", "id", "style"],
)
clean = shrinker.shrink(raw_html)

2) Keep mode

from html_shrinker import HTMLShrinker

shrinker = HTMLShrinker(
    tag_mode="keep",
    tags=["main", "article", "h1", "h2", "p", "ul", "ol", "li", "a"],
    attribute_mode="keep",
    attributes=["href"],
)
clean = shrinker.shrink(raw_html)

3) Strip inner text

from html_shrinker import HTMLShrinker

shrinker = HTMLShrinker(strip_innertext=True)
clean = shrinker.shrink("<html><body><p>secret text</p></body></html>")
# <html><body><p></p></body></html>

License

MIT

Metadata

Release files for html-shrinker 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for html-shrinker 0.1.0
File Size Uploaded
html_shrinker-0.1.0.tar.gz 5.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for html-shrinker 0.1.0
File Interpreter ABI Platform
html_shrinker-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 12.4 kB

Release files / html_shrinker-0.1.0.tar.gz

Download URL html_shrinker-0.1.0.tar.gz
Size 5.7 kB
Tags Source
SHA-256 checksum
How to use checksums
98d3e96700e7c9c5f68082c5b0804524e7a560eb988423b8668dbfbc4b71e939
BLAKE2b-256 checksum
How to use checksums
ca96a60b54edf40774d0ef7fdcbc0e0638b83fc0abc9154fee0df89f4ef23876
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.0

Release files / html_shrinker-0.1.0-py3-none-any.whl

Download URL html_shrinker-0.1.0-py3-none-any.whl
Size 6.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
28c9b2e3a1dffc75feeefc4d9bd5027baab6e4a71f2a61030351784af753b7e8
BLAKE2b-256 checksum
How to use checksums
60ee7ac93e9ed1395795e7dd3cf38274ec42062a9e1bbd222921600968be03c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.0

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page