Scrapeless Wiki

What Is Jsoup? – Definition and How It Works

Informational P3 what is jsoup

Learn what jsoup is, how its lenient HTML parser and CSS selectors work in Java, and where its limits are.

jsoup is a Java library for parsing HTML, traversing it with CSS selectors, extracting data, and sanitising untrusted markup. It parses the way a browser does β€” leniently β€” rather than requiring well-formed XML.

1. The Core API

Document doc = Jsoup.connect("https://example.com/products")
        .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
        .timeout(30_000)
        .get();

for (Element card : doc.select("div.product-card")) {
    String title = card.select("h2.title").text();
    String price = card.select("span.price").text();
    String href  = card.select("a[href]").attr("abs:href");
    System.out.printf("%s | %s | %s%n", title, price, href);
}

The abs: attribute prefix resolves a relative URL against the document's base β€” the single most useful convenience in the library, and the thing hand-written extraction most often gets wrong.

2. Lenient Parsing Is the Point

Real HTML is broken: unclosed tags, misnested elements, stray attributes, invalid nesting. An XML parser rejects it; jsoup applies the HTML5 parsing algorithm and builds the same tree a browser would.

That means the DOM you select against matches what the browser shows, including implied elements such as an inserted tbody β€” which explains why a selector copied from browser dev tools works.

3. Selector Support

jsoup implements a substantial CSS selector subset plus useful extensions:

Selector Matches
div.card > h2 Direct children
a[href^=/product/] Attribute prefix
li:nth-child(2n) Positional
p:contains(Sale) Text content
div:matches(^Price) Regex on text
:not(.hidden) Negation
td:matchesOwn(\\d+) Regex on own text only

:contains and :matches have no CSS equivalent and are frequently the cleanest way to locate an element whose only distinguishing feature is its text.

4. Fetching Versus Parsing

Jsoup.connect() is a convenience HTTP client, not a full one. It handles cookies, redirects, headers, and form posts, and that is enough for simple cases.

For anything serious β€” connection pooling, HTTP/2, retry policies, proxy rotation β€” fetch with a dedicated client and hand the string to Jsoup.parse():

String html = httpClient.get(url);
Document doc = Jsoup.parse(html, url);   // baseUri enables abs: resolution

Passing the base URI is what keeps abs:href working when you parse a string rather than fetch.

5. Sanitising Untrusted HTML

jsoup's other well-known role is XSS prevention through allowlist-based cleaning:

String safe = Jsoup.clean(userHtml, Safelist.basicWithImages());

This is genuinely different from escaping: it produces HTML that still renders, with only allowed elements and attributes surviving. For any application storing user-submitted markup, it is the standard Java answer.

6. What It Does Not Do

JavaScript. jsoup parses the HTML it is given. A client-rendered page yields an empty shell, and no jsoup configuration changes that β€” the fix is a rendering step upstream.

Browser behaviour. No cookies-across-navigation state machine, no fingerprint, no challenge handling.

XPath. Selectors only, which covers most needs but not all β€” XPath's ability to select a parent from a child has no direct CSS equivalent.

7. Practical Notes

  • Use text() for visible text and html() for markup. text() normalises whitespace, which is usually what you want.
  • Prefer selectFirst() over select().first() β€” it returns null rather than throwing on an empty result, so the null check is explicit.
  • Check for null on selectFirst(). A missing element is the normal case when a site changes, and an unchecked null becomes a NullPointerException in production.
  • Set a realistic timeout. The default is generous enough to hang a batch.
  • Handle maxBodySize β€” jsoup truncates large documents by default, which silently loses content on big pages.

That truncation default is the surprising one: a very large page parses successfully with its tail missing, which looks like a site change rather than a configuration limit.

8. Summary

jsoup parses real-world HTML the way a browser does, offers CSS selectors with useful text-matching extensions, resolves absolute URLs via abs:, and sanitises untrusted markup against an allowlist.

It does not execute JavaScript, so client-rendered pages need a rendering step first β€” and its default body-size limit will silently truncate very large documents unless raised.