How to Convert an HTML Table to CSV (Browser, Excel & Python)
Updated July 25, 2026
🛠️ This guide pairs with our free HTML Table to CSV — Auto-detect every table in pasted HTML and export to CSV, JSON or Markdown.
HTML tables hold a huge share of the web’s structured data — pricing pages, financial statements, sports statistics, Wikipedia — and getting one into a spreadsheet or script cleanly is a daily task that goes wrong in predictable ways: merged cells shift columns, nested markup pollutes values, and multi-table pages defeat copy-paste. Here are four methods, from zero-code to fully automated, and when each one is right.
Method 1: copy-paste (works more often than you’d think)
Select the table in your browser, copy, and paste into Excel or Google Sheets. Both apps parse the HTML on the clipboard and often reconstruct the grid correctly.
When it breaks: merged cells (colspan/rowspan) shift data into wrong columns; images, line breaks and links inside cells produce garbage; and there’s no way to grab only the third table on a page. When any of that happens, move to method 2.
Method 2: browser converter (no code, handles the messy cases)
Our free HTML Table to CSV converter takes the page’s HTML — paste the full source (Ctrl+U, copy) or just the table markup — auto-detects every table, and shows a preview of each so you pick the right one. Two things it does that copy-paste and most converters don’t:
- Correct merged-cell flattening. A cell spanning three columns becomes three cells (value repeated or blank — your choice), and rowspans carry down into the rows they cover, so the grid stays rectangular and columns stay aligned.
- Multiple output formats: CSV, TSV (most reliable for pasting into Excel), JSON keyed by header row, or a Markdown table for READMEs and docs.
Conversion runs entirely in your browser — nothing is uploaded — so it’s safe for internal dashboards and non-public reports.
Tip for JavaScript-rendered tables: if Ctrl+U source doesn’t contain the table (common on modern sites), open DevTools, right-click the <table> element → Copy → Copy outerHTML, and paste that.
Method 3: Excel and Google Sheets built-ins
- Google Sheets:
=IMPORTHTML("https://example.com/page", "table", 1)pulls the first table straight from a URL and refreshes periodically. Great for live dashboards; limited control over parsing. - Excel: Data → Get Data → From Web walks you through selecting a table with Power Query, which also handles refresh-on-open.
Both fail on JavaScript-rendered tables and pages behind logins — for those, get the HTML manually and use method 2.
Method 4: Python with pandas (automation)
For recurring jobs, pandas.read_html is a one-liner that parses every table on a page into DataFrames:
import pandas as pd
tables = pd.read_html("https://example.com/page") # list of DataFrames
df = tables[0] # pick your table
df.to_csv("table.csv", index=False)
Under the hood it uses lxml/BeautifulSoup and handles most colspan/rowspan cases properly. Three practical notes:
- JavaScript pages:
read_htmlsees only the raw HTML. Pair it with Playwright (page.content()) to get the rendered DOM first. - Picking the right table: pass
match="Revenue"to keep only tables containing that text, instead of guessing indexes. - Multi-row headers: financial tables often produce a MultiIndex header — flatten with
df.columns = [' '.join(map(str, c)).strip() for c in df.columns].
If you’re at the stage of extracting specific cells rather than whole tables, you’ll want selectors — see our guide to CSS selectors vs XPath for scraping.
Choosing quickly
| Situation | Use |
|---|---|
| Clean, simple table, one-off | Copy-paste |
| Merged cells, multiple tables, messy markup | Browser converter |
| Live-refreshing spreadsheet | Sheets IMPORTHTML / Excel Power Query |
| Recurring or bulk extraction | pandas read_html |
The common thread: don’t fight a broken grid by hand. If your columns are shifting, the table has merged cells, and the fix is a converter that flattens them properly — repairing it manually in a spreadsheet takes longer and silently corrupts data.