     [Answers](https://scrapfly.io/blog)   /  [data-parsing](https://scrapfly.io/blog/tag/data-parsing)   /  [How to scrape HTML table to Excel Spreadsheet (.xlsx)?](https://scrapfly.io/blog/answers/html-table-to-xlsx-python-beautifulsoup)   # How to scrape HTML table to Excel Spreadsheet (.xlsx)?

 by [Bernardas Alisauskas](https://scrapfly.io/blog/author/bernardas) Oct 30, 2026 2 min read [\#data-parsing](https://scrapfly.io/blog/tag/data-parsing) [\#python](https://scrapfly.io/blog/tag/python) 

 [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhtml-table-to-xlsx-python-beautifulsoup "Share on LinkedIn") [  ](https://x.com/intent/tweet?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhtml-table-to-xlsx-python-beautifulsoup&text=How%20to%20scrape%20HTML%20table%20to%20Excel%20Spreadsheet%20%28.xlsx%29%3F "Share on X") [  ](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhtml-table-to-xlsx-python-beautifulsoup "Share on Facebook")    

 

 

Summarize this article with

 [  ](https://chat.openai.com/?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhtml-table-to-xlsx-python-beautifulsoup) [  ](https://claude.ai/new?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhtml-table-to-xlsx-python-beautifulsoup) [  ](https://x.com/i/grok?text=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhtml-table-to-xlsx-python-beautifulsoup) [  ](https://www.perplexity.ai/search/new?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhtml-table-to-xlsx-python-beautifulsoup) [  ](https://www.google.com/search?udm=50&aep=11&q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fanswers%2Fhtml-table-to-xlsx-python-beautifulsoup) 



To save an HTML table to an Excel spreadsheet we can use Python with [How to Parse Web Data with Python and Beautifulsoup](https://scrapfly.io/blog/posts/web-scraping-with-python-beautifulsoup#parsing-html-with-beautifulsoup) and [xlsxwriter](https://pypi.org/project/xlsxwriter/) + HTTP client like [requests](https://pypi.org/project/requests/).

shell

```shell
pip install beautifulsoup4 xlsxwriter requests
```



Then fetch the page, read the table rows with BeautifulSoup and write them to an `.xlsx` file with `xlsxwriter`:

python

```python
from bs4 import BeautifulSoup
import requests
import xlsxwriter

# 1. Retrieve the HTML. w3schools answers the default python-requests
#    User-Agent with 403 Access Denied, so send a browser one.
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36"
}
response = requests.get("https://www.w3schools.com/html/html_tables.asp", headers=headers)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")

# 2. Find the table and read every row, taking th and td cells together
#    so row-label cells and the header row are both kept.
table = soup.find("table", {"id": "customers"})
rows = []
for tr in table.find_all("tr"):
    cells = tr.find_all(["th", "td"])
    if cells:
        rows.append([cell.get_text(strip=True) for cell in cells])

# 3. Write the rows to an .xlsx file. The table's header row lands in row 1.
workbook = xlsxwriter.Workbook("output.xlsx")
worksheet = workbook.add_worksheet()
for i, row in enumerate(rows):
    worksheet.write_row(i, 0, row)
workbook.close()
```



Taking `th` and `td` cells together is the part that matters. Stats and spec tables often mark the first cell of each body row as `<th scope="row">`, and `row.find_all('td')` alone skips it, so every row comes out one column short and its values shift under the wrong headers, with no error. Writing every row in document order also avoids guessing which row is the header: the table's own header row becomes row 1 of the sheet, and a table without one loses no data. For tables rendered by JavaScript or built with `colspan` and `rowspan`, see [how to scrape tables with BeautifulSoup](https://scrapfly.io/blog/answers/how-to-scrape-tables-with-beautifulsoup).



 

   [  Add as a preferred source ](https://google.com/preferences/source?q=scrapfly.io)   Join the Newsletter  Get monthly web scraping insights 

 

  



Scale Your Web Scraping

Anti-bot bypass, browser rendering, and rotating proxies, all in one API. Start with 1,000 free credits.

  No credit card required  1,000 free API credits  Anti-bot bypass included 

 [Start Free](https://scrapfly.io/register) [View Docs](https://scrapfly.io/docs/onboarding) 

 Not ready? Get our newsletter instead. 

 

 ## Related Articles

 [     

 http python 

### Guide to Python requests POST method

Discover how to use Python's requests library for POST requests, including JSON, form data, and file uploads, along with...

 

 ](https://scrapfly.io/blog/posts/how-to-python-requests-post) [     

 http python 

### Web Scraping with Python

Introduction tutorial to web scraping with Python. How to collect and parse public data. Challenges, best practices and ...

 

 ](https://scrapfly.io/blog/posts/web-scraping-with-python) [     

 python tools 

### Python lxml Tutorial: How to Parse HTML and XML

In this tutorial, we'll take a deep dive into lxml, a powerful Python library that allows for parsing HTML and XML effec...

 

 ](https://scrapfly.io/blog/posts/intro-to-parsing-html-xml-python-lxml) 

  ## Related Questions

- [ Q How to scrape tables with BeautifulSoup? ](https://scrapfly.io/blog/answers/how-to-scrape-tables-with-beautifulsoup)
- [ Q What are some BeautifulSoup alternatives in Python? ](https://scrapfly.io/blog/answers/what-are-some-beautifulsoup-alternatives)
- [ Q What are some ways to parse JSON datasets in Python? ](https://scrapfly.io/blog/answers/what-are-some-ways-to-parse-json-datasets-in-python)
- [ Q How to use CSS Selectors in Python? ](https://scrapfly.io/blog/answers/how-to-use-css-selectors-in-python)
 
  



   



 Extract structured data with AI, **1,000 free credits** [Start Free](https://scrapfly.io/register)