Prompt

How do I turn messy HTML pages into a clean CSV dataset?

Technology / API Platforms1 observationLast seen Oct 4, 2026

Latest observation

Oct 4, 2026OpenAI APIWeb search: off

Turning messy HTML into a clean CSV usually means building a small extraction pipeline:

  1. Fetch the page
  2. Parse the HTML
  3. Identify the repeating records
  4. Extract fields
  5. Clean/normalize values
  6. Write to CSV
  7. Validate the output

1) Inspect the page structure

Open the page in your browser and use DevTools:

  • Right-click an item → Inspect
  • Look for:
    • repeated blocks for each record
    • stable CSS classes, IDs, or attributes
    • tables, lists, cards, or embedded JSON

If the data is already in a table, extraction is easy. If it’s in divs/spans, you’ll need selectors. If it’s rendered by JavaScript, you may need a browser automation tool.

2) Use the right tool

Common options:

  • Static HTML: requests + BeautifulSoup or pandas.read_html
  • Complex HTML: lxml + XPath/CSS selectors
  • JavaScript-rendered pages: Playwright or Selenium
  • Many pages / crawling: Scrapy

3) Basic Python example

For a simple table

import pandas as pd

url = "https://example.com/page-with-table"
tables = pd.read_html(url)
df = tables[0]   # choose the correct table
df.to_csv("output.csv", index=False)

For custom HTML

import requests
from bs4 import BeautifulSoup
import csv

url = "https://example.com"
html = requests.get(url, timeout=30).text
soup = BeautifulSoup(html, "html.parser")

rows = []
for item in soup.select(".product-card"):
    name = item.select_one(".name")
    price = item.select_one(".price")
    rows.append({
        "name": name.get_text(strip=True) if name else None,
        "price": price.get_text(strip=True) if price else None,
    })

with open("output.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "price"])
    writer.writeheader()
    writer.writerows(rows)

4) Clean the data

Messy HTML often includes:

  • extra whitespace
  • currency symbols
  • line breaks
  • missing values
  • duplicated text
  • relative URLs

Typical cleaning steps:

  • strip() text
  • convert prices to numeric values
  • standardize dates
  • resolve URLs with urljoin
  • remove null/duplicate rows

Example:

import re
from urllib.parse import urljoin

def clean_price(text):
    if not text:
        return None
    m = re.search(r"[\d,.]+", text)
    return float(m.group().replace(",", "")) if m else None

5) Handle JavaScript-rendered pages

If the data is not in the initial HTML source, use Playwright:

from playwright.sync_api import sync_playwright
from bs4 import BeautifulSoup

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto("https://example.com", wait_until="networkidle")
    html = page.content()
    browser.close()

soup = BeautifulSoup(html, "html.parser")

6) Prefer scraping the underlying JSON/API if available

Often the page loads data from an API call. This is much cleaner than scraping HTML:

  • check the Network tab in DevTools
  • look for XHR/fetch requests
  • call the API directly and save the JSON to CSV

7) Validate the CSV

Before calling it done:

  • check row count
  • verify columns and types
  • spot-check random records
  • look for duplicates or missing fields

8) If the site has multiple pages

You’ll need to loop through pagination:

  • page numbers
  • next links
  • infinite scroll
  • cursor-based API pagination

A practical workflow

  1. Inspect one page manually
  2. Write selectors for one record
  3. Test extraction on 5–10 items
  4. Add cleaning
  5. Add pagination
  6. Save CSV
  7. Verify data quality

If you want, I can help you with:

  • a generic scraping script
  • a specific HTML page you have
  • a Playwright solution for JavaScript-heavy sites
  • or a BeautifulSoup-to-CSV template for your exact case

Observation history

How did Obsurfable measure this prompt?

Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.

Which AI systems does Obsurfable collect answers from?

OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, Meta AI, Qwen.

How can brands improve their AEO?

Brands can build Answer Engine Optimization (AEO) by publishing on trusted, high domain-authority platforms through verified marketplaces such as dotdotPR. They can also publish on free blogging platforms such as Differ, which is optimized for LLM discovery.

Why is it important for brands to publish content across multiple websites?

Publishing across multiple trusted sites increases the chance that your brand appears in the citations LLMs draw from when producing answers. Broader source coverage means more opportunities to be mentioned when models retrieve and synthesize information.

Want this interpreted for your brand?

Explorer is the free public corpus. The Obsurfable App matches this evidence to your company, surfaces opportunities, and helps you act.