Data tabel yang kita butuhkan sering kali sudah tersaji di halaman web: rekap statistik resmi, daftar harga komoditas, jadwal transportasi, atau laporan internal yang ditampilkan lewat aplikasi perusahaan. Menyalin-tempel tabel semacam itu ke spreadsheet memakan waktu, mudah salah, dan tidak bisa diulang secara otomatis. Fungsi pd.read_html() menyelesaikan masalah ini dengan memindai semua elemen <table> di dalam dokumen HTML, lalu mengubah setiap tabel menjadi DataFrame yang siap dianalisis. Chapter ini membahas cara kerja read_html(), mencobanya pada string HTML tanpa jaringan, dan menutup dengan catatan praktis ketika tabel web tidak rapi.

Cara Kerja read_html() #

Fungsi read_html() menerima tiga jenis sumber secara bergantian: string berisi HTML (biasanya dibungkus io.StringIO), path file HTML lokal, atau URL halaman web. Pandas mencari seluruh elemen <table> di dokumen, memakai sel <th> sebagai nama kolom bila tabel memiliki baris header, dan menjadikan setiap baris data sebagai row DataFrame. Nilai kembalian selalu berupa list berisi DataFrame, bukan satu DataFrame, karena satu dokumen boleh memuat banyak tabel. Isi sel angka dikonversi otomatis menjadi int64 atau float64, sedangkan sel teks menjadi kolom bertipe str pada pandas 3.0.

Parser yang dipakai ditentukan parameter flavor: lxml sebagai pilihan default yang paling cepat, atau bs4 + html5lib yang paling toleran terhadap HTML tidak rapi. Bila parser yang dibutuhkan belum terpasang, pandas melempar ImportError beserta petunjuk library yang perlu diinstal. Dokumentasi resmi pandas.read_html merinci semua parameter, dan halaman IO Tools menempatkan read_html() dalam peta pembaca data pandas secara keseluruhan. Di lingkungan Course ini kedua parser sudah tersedia, sehingga contoh berikut bisa langsung dijalankan.

Membaca Tabel dari String HTML #

Agar contoh tetap runnable tanpa jaringan, kita memakai dokumen HTML kecil yang ditulis sebagai string lalu dibungkus io.StringIO. Dokumen latihan ini memuat dua tabel, masing-masing diberi judul lewat tag <caption>, sehingga kita bisa mengamati perilaku read_html() ketika ada lebih dari satu tabel sekaligus.

python
from io import StringIO

import pandas as pd

html_toko = """
<html>
  <body>
    <h1>Laporan Toko Segar Jaya</h1>
    <table>
      <caption>Stok Produk</caption>
      <tr><th>produk</th><th>harga</th><th>stok</th></tr>
      <tr><td>Kopi Gayo</td><td>85000</td><td>12</td></tr>
      <tr><td>Teh Melati</td><td>32000</td><td>30</td></tr>
      <tr><td>Gula Aren</td><td>24000</td><td>25</td></tr>
    </table>
    <table>
      <caption>Penjualan Hari Ini</caption>
      <tr><th>produk</th><th>terjual</th></tr>
      <tr><td>Kopi Gayo</td><td>5</td></tr>
      <tr><td>Teh Melati</td><td>9</td></tr>
    </table>
  </body>
</html>
"""

hasil = pd.read_html(StringIO(html_toko))
print("Jumlah tabel yang ditemukan:", len(hasil))
print()

df = hasil[0]
print(df)
print()
print(df.dtypes)
print()

df_penjualan = pd.read_html(StringIO(html_toko), match="Penjualan")[0]
print(df_penjualan)

Output yang Dihasilkan:

text
Jumlah tabel yang ditemukan: 2

       produk  harga  stok
0   Kopi Gayo  85000    12
1  Teh Melati  32000    30
2   Gula Aren  24000    25

produk      str
harga     int64
stok      int64
dtype: object

       produk  terjual
0   Kopi Gayo        5
1  Teh Melati        9

Baris demi baris, inilah yang terjadi pada skrip di atas:

  1. Baris 5-24 (html_toko): string dokumen HTML berisi dua <table>; tag <caption> memberi judul setiap tabel dan ikut terbaca oleh pandas.
  2. Baris 26-27 (hasil = pd.read_html(...)): pandas mem-parse dokumen dengan parser default lxml, menemukan 2 tabel, dan mengembalikan list berisi 2 DataFrame.
  3. Baris 30-33 (df = hasil[0]): tabel pertama dipilih lewat indexing list; kolom produk bertipe str, sedangkan kolom harga dan stok otomatis menjadi int64.
  4. Baris 36-37 (match="Penjualan"): parameter match memfilter tabel berdasarkan pola teks di dalamnya, termasuk caption, sehingga hanya tabel Penjualan Hari Ini yang dikembalikan.

Parameter yang Membantu Saat Tabel Web Berantakan #

Tabel di web nyata jarang sesempurna tabel latihan. Baris header bisa berada di tengah tabel, angka memakai titik sebagai pemisah ribuan, atau sel berisi catatan kaki. Parameter berikut sering menolong situasi tersebut:

ParameterPeran
matchMemilih tabel yang teksnya cocok dengan pola tertentu
headerMenentukan baris mana yang menjadi nama kolom
index_colMenjadikan satu kolom sebagai index DataFrame
thousandsMenghapus pemisah ribuan, misalnya "." pada "15.000"
skiprowsMelewati baris catatan sebelum data mulai
flavorMemilih parser lxml atau bs4 + html5lib

Hasil inferensi tipe data juga bisa meleset. Kolom harga yang berisi "Rp15.000" akan dibaca sebagai teks, bukan angka, sehingga kita perlu membersihkannya setelahnya dengan method string seperti Series.str.replace(). Kebiasaan yang sehat adalah memeriksa df.dtypes segera setelah read_html() dan memperbaiki tipe sebelum masuk ke analisis.

Materi mengambil tabel dari halaman web mengantar kita pada pertanyaan yang lebih umum: bagaimana membaca data yang tidak berupa file di disk, melainkan alamat di internet. Chapter berikutnya membahas persis topik tersebut, yaitu membaca dataset langsung dari URL beserta cara menangani ketergantungan jaringannya dengan bijak.