Parsing the Way a Human Would

For years, extracting structured data from messy HTML meant writing brittle selectors and regex. Large language models change the calculus: you can hand an LLM raw text or HTML and ask for a structured record, and it will handle irregular layouts, implicit meaning, and natural language that no selector could capture reliably. The trick is using them surgically, not as a hammer.

When LLMs Earn Their Cost

LLM calls are slower and more expensive than CSS selectors, so reserve them for jobs where they shine:

  • Unstructured or semi-structured pages: press releases, biographies, reviews, legal filings.
  • Field extraction across many layouts: pulling "salary", "deadline", and "location" from hundreds of differently formatted job pages.
  • Normalization and inference: deciding that "NYC", "New York", and "NY" are the same place.
  • Fallback parsing: when your fast selector pipeline fails a drift check, hand the page to an LLM instead of dropping it.

Constrained Output

Never ask an LLM for free-form text and then parse it with regex—that defeats the purpose. Ask for structured output against a schema. Modern APIs support JSON mode or tool/function calling, which constrains generation to valid JSON matching your field definitions. Good prompts specify the exact field names, types, allowed values (enums), and what to emit when information is missing (null, not a guess).

schema = {
    "type": "object",
    "properties": {
        "company": {"type": "string"},
        "role": {"type": "string"},
        "salary_min": {"type": ["number", "null"]},
        "salary_max": {"type": ["number", "null"]},
        "remote": {"type": "boolean"},
    },
    "required": ["company", "role"],
}

Reducing Token Cost

HTML is bloated. Strip <script>, <style>, navigation, and boilerplate before sending the page; feed only the main content region. Cache extraction results keyed by page content hash so re-processing never calls the model twice. For repetitive layouts, use a small, cheap model to extract and a larger model only on pages that fail validation.

Determinism and Validation

LLMs are stochastic. Set temperature to zero where supported, pin a specific model version, and validate every output against your schema plus business rules (salary_min ≤ salary_max, dates parse, URLs resolve). Reject and retry malformed records, and log the raw input alongside the output so failures are reproducible. Keep the extraction prompt under version control—it is code.

The Hybrid Pipeline

The most robust architectures are layered:

  1. Fast path: selectors and regex handle the predictable majority.
  2. Drift detection: if the expected DOM landmarks are missing or counts are off, route the page to the LLM.
  3. Validation: schema and business-rule checks gate every record.
  4. Audit: store inputs, outputs, model version, and prompt version for reproducibility.

This gives you the cost and speed of deterministic scraping with the resilience of language-model understanding exactly where it is needed. Treat the LLM as a well-paid specialist you escalate to, not a worker you task with everything.

Prompting for Reliable Extraction

Small prompt changes produce large accuracy differences, so treat the prompt as a tested artifact. Give the model a precise role ("extract structured records from a web page"), the exact schema, explicit instructions on missing values, and at least one worked example of the desired output. Include a rule for ambiguity: if the page does not contain a field, emit null rather than inferring it. Ask the model to ignore navigation, ads, and boilerplate and to extract only from the main content. Finally, version every prompt and record which version produced each record—when accuracy shifts, the prompt diff is the first place to look.

Grounding and Hallucination

The most dangerous failure mode is a confident fabrication: a salary that was never on the page, a date inferred from context. Guard against it by requiring the model to quote the exact supporting span for each extracted field, then verify that the span actually appears in the source text. If the quote is absent, discard the record. This grounding check converts hallucination from a silent data-quality bug into a detectable, rejectable event, and it pairs naturally with the audit log: every extracted value can be traced to the sentence it came from.