Khi làm việc với dữ liệu từ web, việc trích xuất nội dung bảng HTML và lưu dưới dạng tệp Excel là một nhu cầu phổ biến. Bài viết này trình bày cách thực hiện tự động hóa quy trình này bằng các thư viện Python tiêu chuẩn.
Yêu cầu hệ thống
Cài đặt ba thư viện cần thiết:
bs4(Beautiful Soup) — phân tích cú pháp tài liệu HTML/XHTMLpandas— xử lý cấu trúc dữ liệu dạng bảngopenpyxl— ghi định dạng Excel (.xlsx)
Chạy lệnh sau để cài đặt:
pip install beautifulsoup4 pandas openpyxl
Phân tích bảng HTML
Giả sử có một đoạn HTML chứa bảng đơn giản như sau:
<html>
<body>
<table border="1">
<thead>
<tr><th>Họ tên</th><th>Tuổi</th><th>Nghề nghiệp</th></tr>
</thead>
<tbody>
<tr><td>Nguyễn Văn A</td><td>28</td><td>Lập trình viên</td></tr>
<tr><td>Trần Thị B</td><td>32</td><td>Thiết kế đồ họa</td></tr>
</tbody>
</table>
</body>
</html>
Đoạn mã sau đọc nội dung HTML, xác định tất cả các bảng, rồi trích xuất tiêu đề và dữ liệu từng hàng:
from bs4 import BeautifulSoup
def extract_html_tables(html_path):
with open(html_path, "r", encoding="utf-8") as file:
doc = BeautifulSoup(file, "html.parser")
tables = []
for table_tag in doc.find_all("table"):
# Lấy tiêu đề từ <th> trong <thead> hoặc hàng đầu tiên
header_row = table_tag.find("thead")
if not header_row:
header_row = table_tag.find("tr")
headers = [th.get_text(strip=True) for th in (header_row.find_all("th") or header_row.find_all("td"))] if header_row else []
# Lấy dữ liệu từ <tbody> hoặc các hàng <tr> còn lại
body = table_tag.find("tbody") or table_tag
rows = body.find_all("tr")
data_rows = []
for row in rows:
cells = row.find_all(["td", "th"])
if cells and not all(cell.get_text(strip=True) == "" for cell in cells):
data_rows.append([cell.get_text(strip=True) for cell in cells])
# Loại bỏ hàng tiêu đề nếu đã được lấy ở trên
if headers and data_rows and data_rows[0] == headers:
data_rows = data_rows[1:]
tables.append({"headers": headers, "rows": data_rows})
return tables
Xuất ra tệp Excel
Sau khi thu thập dữ liệu, dùng pandas để tạo DataFrame và ghi vào tệp Excel:
import pandas as pd
def save_tables_to_excel(tables, base_name="exported_table"):
for idx, tbl in enumerate(tables, 1):
if not tbl["headers"] or not tbl["rows"]:
continue
df = pd.DataFrame(tbl["rows"], columns=tbl["headers"])
filename = f"{base_name}_{idx}.xlsx"
df.to_excel(filename, index=False, engine="openpyxl")
print(f"Đã lưu bảng {idx} vào {filename}")
# Sử dụng
tables_data = extract_html_tables("data.html")
save_tables_to_excel(tables_data, "bang_du_lieu")
Mở rộng chức năng
Để xử lý nhiều bảng trong cùng một tệp HTML và đảm bảo tính ổn định với cấu trúc không đồng nhất, có thể thêm kiểm tra lỗi và chuẩn hóa dữ liệu:
def robust_table_export(html_path, output_prefix="sheet"):
try:
tables = extract_html_tables(html_path)
if not tables:
print("Không tìm thấy bảng nào trong tài liệu.")
return
with pd.ExcelWriter(f"{output_prefix}.xlsx", engine="openpyxl") as writer:
for i, t in enumerate(tables, 1):
if t["headers"] and t["rows"]:
df = pd.DataFrame(t["rows"], columns=t["headers"])
sheet_name = f"Bang_{i}"[:31] # Giới hạn tên sheet Excel
df.to_excel(writer, sheet_name=sheet_name, index=False)
print(f"Xuất thành công {len(tables)} bảng vào {output_prefix}.xlsx")
except Exception as e:
print(f"Lỗi khi xuất: {e}")