Prompt
How do I turn messy HTML pages into a clean CSV dataset?
Latest observation
Oct 4, 2026
OpenAI APIWeb search: off
Turning messy HTML into a clean CSV usually means building a small extraction pipeline:
- Fetch the page
- Parse the HTML
- Identify the repeating records
- Extract fields
- Clean/normalize values
- Write to CSV
- 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 + BeautifulSouporpandas.read_html - Complex HTML:
lxml+ XPath/CSS selectors - JavaScript-rendered pages:
PlaywrightorSelenium - 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
- Inspect one page manually
- Write selectors for one record
- Test extraction on 5–10 items
- Add cleaning
- Add pagination
- Save CSV
- 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