To get HTML to Excel, hand the table markup to Excel and let it parse the rows. Excel reads table elements natively, so all four routes below produce cells rather than one lump of text.
The part that actually costs time is afterwards. Numbers arrive as text far more often than tables arrive broken.

Four ways to convert HTML to Excel
| Route | Repeatable | Keeps formatting | Best for |
|---|---|---|---|
| Select and paste | No | Some styling | One table, once |
| Open the file in Excel | No | Basic | A saved page with several tables |
| Data, From Web | Yes, refreshable | Values only | A table that changes |
| Script | Yes | What you choose | Many files or a pipeline |
Route 1: select and paste
Open the page, drag across the table, copy, and paste into a worksheet. Excel reads the table structure from the clipboard and fills cells accordingly.
Paste Special gives you control over what comes with it. Match Destination Formatting drops the page's colours and borders, which is usually what you want.
The limit is that you get a copy from one moment, and nothing records where it came from.
Route 2: open the file in Excel
If the page is saved as a file, open it from Excel directly. File, then Open, then set the file type filter to show all files and pick the .html file.
Excel parses every table in the document and puts them on a sheet in order. For a report page with several tables, this beats pasting each one.
If Excel refuses the file, renaming it to .xls usually works, because Excel's legacy reader accepts HTML with that extension. It will warn about the extension not matching the format; that warning is expected.
Route 3: Data, From Web
This is the route for a table that changes. Excel stores the address as a query rather than a one time paste.
- Data, then From Web.
- Enter the address of the page.
- Choose which table from the navigator pane. Excel lists them by name or by index.
- Load into a sheet.
After that, Refresh re-reads the page and updates the cells. You can also transform columns in the query editor so the type fixes happen automatically on every refresh.
The requirement is an address Excel can reach. A file on your own disk has none.

Giving a local file an address
If the table only exists in a file on your machine, paste the HTML into a NOS document. It renders as written and the document has its own address.
Copy the share link and use that in From Web. Turning HTML into a link is that step on its own, and table to link covers tables specifically.
Route 4: a script
For many files, or as part of a pipeline, read the markup and write a workbook.
import pandas as pd
tables = pd.read_html("report.html")
tables[0].to_excel("report.xlsx", index=False)
read_html returns every table it finds, so index into the one you want. Pass thousands="," and decimal="." to get numeric columns rather than text.
In JavaScript, SheetJS converts a table element into a worksheet:
const wb = XLSX.utils.table_to_book(document.querySelector('#data'));
XLSX.writeFile(wb, 'report.xlsx');
Fixing the columns after import
This is where the time goes. Excel decides a column is text as soon as one cell in it is not clean.
- Thousands separators and currency symbols.
$1,240is text. Strip the symbol, or set the column type in Power Query. - Non breaking spaces. Pages often contain them and they survive the paste invisibly. Find and replace with nothing.
- Dates. A date written
2026-09-16usually parses. One written16 Sepusually does not. - Percentages.
12.4%becomes text unless the column is typed as percentage.
Select the column, use Data, Text to Columns, click through to the last pane and set the format. For a refreshable query, do the same work once in the query editor and it repeats itself.

When the import gives you nothing
Two causes cover almost every case.
The table is not a table. A layout built from div elements with CSS grid looks like a table and has no rows for Excel to find. Nothing will import it as cells except a script that understands the specific structure.
The rows are drawn by script. If a chart library or a data table widget builds rows after the page loads, the saved markup has no rows in it. Copy from the rendered page rather than the source, or export from whatever produced the data.
The workbook is a snapshot
Once exported, the numbers are frozen and the file starts circulating. A week later, two people have two versions and neither knows which is current.
Keep the page as the live version and use the workbook for the calculation you need today. Put the page address in the first cell of the sheet so anyone who opens it can check.
If people need to edit the figures rather than only read them, an editable HTML table keeps the table on the page, where one address holds the current values and there is nothing to re-export.