HTML Table to CSV
Paste the markup of a table, or upload a page you saved, and get a CSV back. Merged cells are unmerged, line breaks inside a cell survive, and a page carrying several tables gives you a list to pick from. Your browser's own parser does the reading, in this tab, with nothing sent anywhere.
Need to clean the columns up afterwards? Open the app
First, get the HTML
Worth saying plainly, because half the tools in this category imply otherwise: this page does not visit web addresses. It reads HTML you give it. A browser tab is not allowed to fetch another site's page and read it, and the tables people actually want are usually behind a login anyway. Getting the markup yourself takes about ten seconds and works on pages no fetcher could ever reach.
- Copy it from the page. Right-click inside the table, choose Inspect, walk up the tree until the highlighted element is the
<table>tag, then right-click that line and pick Copy, Copy outerHTML. Paste it here. Same two menu items in Chrome, Edge, Firefox and Safari. - Save the whole page. Ctrl+S or Cmd+S gives you an .html file. Upload it and every table in it is found at once.
- Use the file a system already sent you. Monitoring alerts, invoices, nightly reports and older BI exports all arrive as HTML tables in an attachment or an email body.
After that it is the usual suspects. An admin screen with no export button. A wiki or Confluence page holding the only copy of a lookup table. A vendor portal that renders results but will not download them. A documentation page listing status codes, currencies, tax rates or country codes that you need as data rather than as reading material.
Worked example: a table with merged cells
This is what a real report looks like once someone has tidied it for humans. East owns two rows, and a name has been broken over two lines:
<table>
<thead>
<tr><th>Region</th><th>Rep</th><th>Units</th></tr>
</thead>
<tbody>
<tr><td rowspan="2">East</td><td>Ada<br>Lovelace</td><td>120</td></tr>
<tr><td>Grace Hopper</td><td>98</td></tr>
<tr><td>West</td><td>Alan Turing</td><td>140</td></tr>
</tbody>
</table>
The CSV that comes out:
Region,Rep,Units
East,"Ada
Lovelace",120
East,Grace Hopper,98
West,Alan Turing,140
Three things happened there. East was written into both of the rows its rowspan covered, so row two is a complete record rather than a row starting with a blank. The <br> became a real line break, and the field around it was quoted, which is exactly how a spreadsheet reads a two-line cell back. Everything else was whitespace: the indentation and newlines that wrap the markup are the author's formatting, not data, so they are collapsed away.
Header detection is the other decision made here. Every cell in the first row is a <th>, so that row becomes the column names. When the first row is not all header cells, nothing is promoted: the columns come out as column_1, column_2 and so on, and your first row of data stays a row of data. Guessing wrong in that direction quietly deletes a record.
Columns that span, and pages with several tables
A header cell stretched across two columns is the most common shape in a report, and it has a consequence worth seeing:
<tr><th>Region</th><th colspan="2">2026</th></tr>
<tr><td>East</td><td>120</td><td>140</td></tr>
Region,2026,2026_2
East,120,140
The value is repeated across the columns it covers, which for a header means the same name twice. Duplicate column names lose data in most tools that read CSV, so the second one gets a numbered suffix and you are told about it: 1 duplicate header name was renamed so no column is lost: "2026" became "2026_2". Two stacked header rows behave the same way. Only the first becomes the column names, and the second arrives as your first data row, ready to delete.
- rowspan fills downward. The value is written into every row the span covers. A rowspan of 0, which means "to the end of this section", fills to the last row, and a rowspan that overshoots the table is capped rather than inventing empty rows.
- Several tables become a checklist. Every table on the page is listed with its row and column counts, all ticked. Untick the ones you do not want.
- One left ticked gives a CSV. Two or more gives a zip, one CSV per table, with a note saying so.
- Captions become filenames. A table with
<caption>People by team</caption>is listed under that caption and lands in the zip as People-by-team.csv. Tables without one are Table 1, Table 2 and so on.
Gotchas worth knowing
- Bring the <table> tags with you. Rows on their own do not parse. A browser discards
<tr>elements that are not inside a table, so a fragment of rows produces No tables were found in that HTML. Copy outerHTML on the table node, not on a row. - Links keep their text and lose their address. A cell holding
<a href="/x">Ada</a>becomes Ada. The href is not written to a second column, so if the URLs are the point, that is a job for the app. - Hidden text still counts. A cell with a screen-reader label or a span hidden by CSS contributes its text, and it is joined without a space, so you may see hiddenAda where the page shows Ada. Search the output for anything that looks glued together.
- A table nested inside a cell is skipped. Nested tables are usually layout, not data, so they are not exported separately and you get a message saying how many were left out. Their text stays in the parent cell, run together.
- Entities are decoded.
écomes through as é and a non-breaking space becomes an ordinary one, so the CSV holds text rather than markup. - Numbers stay as written. A cell reading 1,200 is quoted so the comma cannot split the row, but it is not converted to 1200. Currency symbols, percent signs and footnote markers come through too, because they were in the table.
- Sorting, paging and lazy loading are invisible. You get the rows that were in the markup at the moment you copied it. If a grid shows 25 of 500 rows, copy the table on each page, or find the export the developers hid in a menu.
Frequently Asked Questions
Can I give it a web address instead of HTML?
No. This page reads HTML you hand it, either pasted or uploaded, and it never fetches a URL. A browser tab cannot read another site's page without that site's permission, and most of the tables people want are behind a login anyway. Copying the table's markup takes about ten seconds and works on pages a fetcher could never reach.
How do I copy a table's HTML out of a page?
Right-click anywhere in the table and choose Inspect. In the panel that opens, walk up the tree until the highlighted element is the <table> tag, right-click that line, then Copy and Copy outerHTML. Paste the result into the box on this page. Chrome, Edge, Firefox and Safari all have the same two menu items.
What happens to merged cells?
They are unmerged by repeating the value. A cell with colspan="3" is written into all three columns it covers, and a cell with rowspan="4" is written into all four rows underneath it. CSV has no notion of a merged cell, so the alternative would be blanks that break every filter and pivot you point at the file.
Why are my columns named 2026 and 2026_2?
A header cell that spans two columns produces the same name twice, and duplicate column names lose data in most tools that read CSV. The second one is renamed with a numbered suffix and a message tells you which name was changed. Rename them properly in a spreadsheet afterwards, or drop the top header row before you paste.
Why did I get a zip instead of a CSV?
Because more than one table was selected. Every table on the page is found and listed with its row and column counts, all ticked to begin with. Leave one ticked and the download is a plain CSV. Leave several and each becomes its own CSV inside a zip, named after the table's caption where it has one.
I pasted the rows and it says no tables were found.
The <table> tags have to come with them. A browser throws away <tr> and <td> elements that are not inside a table, so a fragment of rows parses to nothing and you get: No tables were found in that HTML. This reads the <table> elements on the page. Copy outerHTML on the table node rather than on a row, or wrap what you have in <table> and </table>.
Get that table out of the page
Free, no account, no upload. Paste the markup or drop a saved page, pick the tables you want, take the CSV.
Back to the converter