Beranda BlogPengikisan web Cara mencari tabel HTML menggunakan Python

Cara mencari tabel HTML menggunakan Python

oleh Kadek
Elemen ditemukan di badan tabel. Jika Anda mengikuti logika kami, langkah selanjutnya adalah menyimpan setiap baris dalam satu objek dan mengulanginya untuk menemukan data yang Anda inginkan.

Pertama, mari kita coba memilih nama karyawan pertama di konsol browser kita menggunakan metode .querySelectorAll(). Fitur yang sangat berguna dari metode ini adalah kita dapat masuk lebih dalam ke dalam hierarki dengan menerapkan simbol lebih besar dari (>) untuk mengambil elemen induk (kiri) dan elemen anak yang ingin kita ambil (kanan), untuk didefinisikan.

document.querySelectorAll('table.stripe > tbody > tr > td')(0)

fitonfiton

Ini tidak bisa lebih baik lagi. Seperti yang Anda lihat, mari kita ambil semuanya terlebih dahulu

Elemen, ini menjadi daftar simpul. Karena kita tidak bisa mengandalkan kelas untuk menangkap setiap sel, kita hanya perlu mengetahui posisinya dalam indeks dan yang pertama, Nama, adalah 0.

Dari sana kita dapat menulis kode kita seperti ini:

for row in rows:
name = row.find_all('td')(0).text
print(name)

Sederhananya, kami mengambil setiap baris satu per satu dan mencari semua sel yang ada di dalamnya. Setelah kita memiliki daftarnya, kita hanya mengakses yang pertama di indeks (posisi 0) dan menyelesaikannya dengan metode .text untuk mengakses teks elemen dan mengabaikan data HTML yang tidak kita perlukan.

Pengikis mejaPengikis meja

Itu dia, daftar semua nama karyawannya! Selebihnya, kita cukup mengikuti logika yang sama:

position = row.find_all('td')(1).text
office = row.find_all('td')(2).text
age = row.find_all('td')(3).text
start_date = row.find_all('td')(4).text
salary = row.find_all('td')(5).text

Namun, mencetak semua data ini di konsol kami tidak terlalu membantu. Sebaliknya, mari simpan data ini dalam format baru yang lebih berguna.

5. Simpan data tabel ke file JSON

Meskipun kami dapat dengan mudah membuat file CSV dan mengirimkan data kami ke sana, format tersebut bukanlah format yang paling mudah dikelola jika kami dapat membuat sesuatu yang baru dengan data bekas.

Namun, berikut adalah proyek yang kami lakukan beberapa bulan lalu yang menjelaskan cara membuat file CSV untuk menyimpan data bekas.

Kabar baiknya adalah Python memiliki modul JSON sendiri untuk bekerja dengan objek JSON, jadi kita tidak perlu menginstal apa pun, cukup impor saja.

Namun sebelum kita dapat melanjutkan pembuatan file JSON, kita perlu mengubah semua data yang tergores ini menjadi sebuah daftar. Untuk melakukan ini, kita membuat array kosong di luar loop kita.

Dan kemudian tambahkan data ke dalamnya, dengan setiap loop menambahkan objek baru ke array.

employee_list.append({
	'Name': name,
	'Position': position,
	'Office': office,
	'Age': age,
	'Start date': start_date,
	'salary': salary
})

jika kita print(employee_list)inilah hasilnya:

Cetak FitonCetak Fiton

Masih agak berantakan, tapi kami memiliki banyak objek yang siap untuk dikonversi ke JSON.

Catatan: Sebagai ujian, kami mencetak panjangnya employee_list dan menghasilkan 57, yang merupakan jumlah baris yang benar yang telah kita gores (baris sekarang menjadi objek dalam array).

Mengimpor daftar ke JSON hanya memerlukan dua baris kode:

with open('json_data', 'w') as json_file:
json.dump(employee_list, json_file, indent=2)
  • Pertama kita buka file baru dan masukkan nama file yang diinginkan (json_data) dan 'w' karena kami ingin menulis data ke dalamnya.
  • Selanjutnya kita menggunakan .dump() Berfungsi untuk membackup data dari array (employee_list) Dan indent=2 Jadi setiap objek mempunyai garisnya masing-masing, bukan semuanya berada pada satu garis yang tidak terbaca.

6. Jalankan script dan kode lengkapnya

Jika Anda sudah mengikuti, Basis kode Anda akan terlihat seperti ini:

#dependencies
import requests
from bs4 import BeautifulSoup
import json

url = 'http://api.scraperapi.com?api_key=51e43be283e4db2a5afbxxxxxxxxxxx&url=https://datatables.net/examples/styling/stripe.html'

#empty array
employee_list = ()

#requesting and parsing the HTML file
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

#selecting the table
table = soup.find('table', class_ = 'stripe')

#storing all rows into one variable
for employee_data in table.find_all('tbody'):
rows = employee_data.find_all('tr')

#looping through the HTML table to scrape the data
for row in rows:
name = row.find_all('td')(0).text
position = row.find_all('td')(1).text
office = row.find_all('td')(2).text
age = row.find_all('td')(3).text
start_date = row.find_all('td')(4).text
salary = row.find_all('td')(5).text

#sending scraped data to the empty array
employee_list.append({
	'Name': name,
	'Position': position,
	'Office': office,
	'Age': age,
	'Start date': start_date,
	'salary': salary
})

#importing the array to a JSON file
with open('employee_data', 'w') as json_file:
json.dump(employee_list, json_file, indent=2)

Catatan: Kami telah menambahkan beberapa komentar untuk konteksnya.

Dan inilah tampilan tiga objek pertama dari file JSON:

berkas JSONberkas JSON

Dengan menyimpan data yang tergores dalam format JSON, kita dapat menggunakan kembali informasi tersebut untuk aplikasi baru atau

Mengikis tabel HTML dengan header yang rumit.

Mengikis data dari tabel HTML cukup mudah, namun apa yang terjadi jika Anda mengakses tabel dengan struktur yang lebih kompleks, seperti: Misalnya tabel bersarang? rowspansatau colspans? Dalam kasus ini, Anda mungkin perlu menerapkan logika penguraian yang lebih canggih.

Sebelum kita mulai, lihat seperti apa tabel target di bawah ini:

Mengikis tabel HTML dengan header yang rumitMengikis tabel HTML dengan header yang rumit

Seperti yang Anda lihat, tabel ini memiliki struktur header dua tingkat:

  • Baris pertama berisi kategori yang lebih luas: “Nama belakang", "posisi", Dan "Kontak“.

  • Baris kedua mengelompokkan kategori-kategori ini lebih lanjut.

Mari kita bersihkan mejanya!

Menyiapkan lingkungan pengikisan

Pertama kita perlu mengimpor perpustakaan yang diperlukan. ScraperAPI membantu kami menangani tindakan anti-scraping apa pun yang mungkin ada di situs web, termasuk mengelola header dan merotasi IP jika perlu:

import requests
from bs4 import BeautifulSoup
import pandas as pd

api_key = 'YOUR_API_KEY'
url = 'https://datatables.net/examples/basic_init/complex_header.html'

Membuat fungsi pengikisan

Mari beralih ke pembuatan fungsi scrape_complex_table Ini menangani seluruh proses pengikisan. Fungsi ini mengambil URL kita sebagai masukan dan mengembalikan Pandas DataFrame yang berisi data tabel terstruktur:

def scrape_complex_table(url):
    # Send a request to the webpage
    payload = {'api_key': api_key, 'url': url}
    response = requests.get('https://api.scraperapi.com', params=payload)
    soup = BeautifulSoup(response.text, 'html.parser')

Fungsi ini digunakan requests.get untuk mengirim permintaan GET ke ScraperAPI, yang kemudian mengambil situs web target. Kami kemudian mengurai konten HTML menggunakan BeautifulSoup.

Menemukan tabel target

Kami menemukan tabel dalam HTML yang diurai menggunakannya id Atribut.

# Find the target table
    table = soup.find('table', id='example')

Baris ini menemukan yang pertama

elemen dengan
id='example'.

Ekstrak dan gabungkan header

Kami mengekstrak judul tingkat pertama dan kedua dan menggabungkannya ke dalam satu daftar nama kolom.

# Extract and combine headers
    headers_level1 = (th.text.strip() for th in table.select('thead tr:nth-of-type(1) th'))
    headers_level2 = (th.text.strip() for th in table.select('thead tr:nth-of-type(2) th'))

    combined_headers = ()
    for i, header in enumerate(headers_level1):
        if header == 'Name':
            combined_headers.append(header)
        elif header == 'Position':
            combined_headers.extend((f"{header} - {col}" for col in ('Title', 'Salary')))
        elif header == 'Contact':
            combined_headers.extend((f"{header} - {col}" for col in ('Office', 'Extn.', 'Email')))

Di sini kami menggunakan pemilih CSS untuk menargetkan header. Kami kemudian mengulang header tingkat pertama dan menambahkan header tingkat kedua yang sesuai ke header kami, bergantung pada headernya combined_headers Daftar.

Mengekstraksi data dari badan tabel

Kami mengekstrak data dari setiap baris di badan tabel.

# Extract data from table body
    rows = ()
    for row in table.select('tbody tr'):
        cells = (cell.text.strip() for cell in row.find_all('td'))
        rows.append(cells)

Kode ini berlaku untuk semua orang

di

, extracts the text from each

, and
stores the data in the rows Daftar.

Membuat DataFrame

Kami membuat Pandas DataFrame menggunakan gabungan header dan data yang diekstraksi. DataFrame ini mengatur data kita dalam format terstruktur dengan nama kolom yang sesuai.

# Create DataFrame
    df = pd.DataFrame(rows, columns=combined_headers)
    return df

Jalankan scraper dan simpan data

Kami menyebutnya demikian scrape_complex_table fungsinya, tampilkan beberapa baris pertama DataFrame dan simpan ke file CSV.

result_df = scrape_complex_table(url)

# Display the first few rows of the result
print(result_df.head())

result_df.to_csv('complex_table_data.csv', index=False)
print("Data has been saved to 'complex_table_data.csv'")

Ini akan mencetak baris teratas DataFrame dan menyimpan semua data dalam file bernama complex_table_data.csv.

Menyatukan semuanya

Ini adalah tampilan kode lengkapnya setelah menggabungkan semua langkah:

import requests
from bs4 import BeautifulSoup
import pandas as pd

api_key = 'your_api_key_here'  # Replace with your actual ScraperAPI key

url = 'https://datatables.net/examples/basic_init/complex_header.html'

def scrape_complex_table(url):
   
    payload = {'api_key': api_key, 'url': url}
    response = requests.get('https://api.scraperapi.com', params=payload)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # Find the target table
    table = soup.find('table', id='example')
    
    # Extract and combine headers
    headers_level1 = (th.text.strip() for th in table.select('thead tr:nth-of-type(1) th'))
    headers_level2 = (th.text.strip() for th in table.select('thead tr:nth-of-type(2) th'))
    
    combined_headers = ()
    for i, header in enumerate(headers_level1):
        if header == 'Name':
            combined_headers.append(header)
        elif header == 'Position':
            combined_headers.extend((f"{header} - {col}" for col in ('Title', 'Salary')))
        elif header == 'Contact':
            combined_headers.extend((f"{header} - {col}" for col in ('Office', 'Extn.', 'Email')))
    
    # Extract data from table body
    rows = ()
    for row in table.select('tbody tr'):
        cells = (cell.text.strip() for cell in row.find_all('td'))
        rows.append(cells)
    
    
    df = pd.DataFrame(rows, columns=combined_headers)
    return df

# Scrape the table
result_df = scrape_complex_table(url)

# Display the first few rows of the result
print(result_df.head())

result_df.to_csv('complex_table_data.csv', index=False)
print("Data has been saved to 'complex_table_data.csv'")

Catatan: Pastikan Anda sudah menggantinya
'your_api_key_here' dengan kunci ScraperAPI Anda yang sebenarnya sebelum menjalankan skrip.

Mengikis tabel HTML yang diberi halaman dengan Python

Saat menangani kumpulan data yang besar, tabel sering kali dibagi menjadi beberapa halaman untuk meningkatkan waktu pemuatan dan pengalaman pengguna. Biasanya hal ini memerlukan pengaturan browser tanpa kepala menggunakan alat seperti Selenium. Namun, dengan menggunakan kumpulan perintah rendering ScraperAPI, kita dapat mencapai hasil yang sama dengan lebih efisien.

catatan: Lihat tutorial mendetail ini Pengikisan web dengan Selenium untuk mengetahui lebih lanjut.

Dasar-dasar menangani pagination

Dalam contoh kita, tabel ditandai dengan “>” dan “

Dasar-dasar menangani paginationDasar-dasar menangani pagination

Untuk mengekstrak semua data kita perlu melakukan hal berikut:

  • Muat halaman beranda
  • Klik tombol “>”.
  • Tunggu data baru dimuat
  • Ulangi proses ini sampai semua halaman diproses

Menggunakan set instruksi render ScraperAPI

Daripada mengontrol browser secara manual, kami dapat mengirimkan instruksi ke browser tanpa kepala ScraperAPI melalui API mereka.

Kumpulan instruksi render ScraperAPI memungkinkan Anda mengirim instruksi ke browser tanpa kepala melalui panggilan API, memberi tahu tindakan apa yang harus diambil saat merender halaman. Instruksi ini dikirim sebagai objek JSON di header permintaan API.

Mari kita dengan cepat mendemonstrasikan cara mengikis tabel yang diberi nomor halaman menggunakan kumpulan perintah render ScraperAPI:

Konfigurasikan ScraperAPI dan instruksi rendering

Pertama, kami menyiapkan kunci ScraperAPI dan URL target yang ingin kami hapus. Ingatlah untuk menggantinya 'your_api_key' dengan kunci ScraperAPI Anda yang sebenarnya.

api_key = 'your_api_key'  # Replace with your actual ScraperAPI key

target_url = 'https://datatables.net/examples/styling/stripe.html'

Sekarang mari kita tentukan kumpulan instruksi rendering.

# Configuration for ScraperAPI's render instructions
config = ({
    "type": "loop",
    "for": 5,  # Number of times to execute the instructions
    "instructions": (
        {
            "type": "click",
            "selector": {
                "type": "css",
                "value": "button.dt-paging-button.next" 
            }
        },
        {
            "type": "wait",
            "value": 3  # Wait time in seconds after clicking
        }
    )
})

Itu loop Pernyataan tersebut mengulangi set instruksi beberapa kali ("for": 5). Sementara pernyataan klik mensimulasikan a click Klik tombol “>” untuk menavigasi ke halaman berikutnya.

Buat permintaan ke ScraperAPI

Setelah kita menentukan instruksi rendering, kita perlu mengonversinya
config Konversikan kamus ke string JSON karena ScraperAPI mengharuskan pernyataan dalam format JSON saat disertakan dalam header permintaan.

config_json = json.dumps(config)

Kami kemudian menyiapkan header dan payload untuk permintaan GET ke ScraperAPI:

# Headers to include ScraperAPI instructions
headers = {
    'x-sapi-api_key': api_key,
    'x-sapi-render': 'true',
    'x-sapi-instruction_set': config_json
}

# Payload with the target URL
payload = {'url': target_url}

Dalam judul:

  • 'x-sapi-api_key' Di sini Anda memasukkan kunci ScraperAPI Anda untuk otentikasi.
  • 'x-sapi-render' disetel ke true untuk mengaktifkan rendering dengan browser tanpa kepala, memungkinkan eksekusi JavaScript dan pemuatan konten secara dinamis.
  • 'x-sapi-instruction_set' berisi instruksi rendering dalam format JSON yang telah kita konversi sebelumnya
    json.dumps(config).

Payload hanya mencakup 'url' kunci dengan itu
target_url Nilai yang menunjukkan halaman web yang ingin kita jelajahi.

Memproses data tabel

Setelah kita mendapatkan jawabannya, kita dapat mengolah data tabel menggunakan BeautifulSoup:

# Parse the HTML content
soup = BeautifulSoup(response.text, 'html.parser')
employee_list = ()

# Find and process the table
table = soup.find('table', class_='stripe')

# Extract data from all rows
for employee_data in table.find_all('tbody'):
    rows = employee_data.find_all('tr')
    
    for row in rows:
        cells = row.find_all('td')
        employee_list.append({
            'Name': cells(0).text,
            'Position': cells(1).text,
            'Office': cells(2).text,
            'Age': cells(3).text,
            'Start date': cells(4).text,
            'salary': cells(5).text
        })

# Save the data to a JSON file
with open('employee_data.json', 'w') as json_file:
    json.dump(employee_list, json_file, indent=2)

Keuntungan menggunakan instruksi render

Menggunakan instruksi render ScraperAPI menawarkan beberapa keuntungan dibandingkan otomatisasi browser tradisional:

  • Tidak perlu menginstal dan mengelola Selenium atau WebDriver
  • Kode yang lebih sederhana dengan lebih sedikit ketergantungan
  • Penanganan tindakan anti-bot yang lebih baik melalui ScraperAPI
  • Eksekusi yang lebih andal dengan waktu tunggu dan percobaan ulang bawaan
  • Itu dapat dengan mudah diterapkan ke server tanpa ketergantungan browser

Menangani kesalahan saat menggores tabel HTML

Tabel HTML di situs web nyata sering kali memiliki tata letak yang rumit, sehingga sulit dikuasai oleh pemula. Tabel ini bisa berisi tipe data campuran, elemen bertumpuk, sel gabungan, dan struktur rumit lainnya yang membuat tabel sulit diurai saat digores.

Mari jelajahi beberapa masalah umum dan solusinya untuk membuat pengikisan tabel Anda lebih efisien dan andal:

1. Menangani sel kosong dan data yang hilang

Sel kosong atau data yang hilang dapat menyebabkan skrip pengikisan Anda gagal atau memberikan hasil yang tidak lengkap. Berikut cara menanganinya dengan elegan:

def extract_cell_data(cell):
    # Handle empty cells
    if not cell:
        return "N/A"
    
    # Handle cells with only whitespace
    if cell.text.strip() == "":
        return "N/A"
        
    return cell.text.strip()

2. Tabel yang disuntikkan JavaScript

Beberapa tabel dibuat secara dinamis menggunakan JavaScript. Artinya, data tidak ada dalam respons HTML awal, namun dimasukkan ke dalam halaman setelah dirender oleh browser. Metode pengikisan tradisional mungkin tidak dapat mengambil konten ini karena tidak menjalankan JavaScript.

Kumpulan perintah rendering ScraperAPI memungkinkan Anda menyimulasikan interaksi pengguna dan menjalankan JavaScript di lingkungan browser tanpa kepala. Hal ini memungkinkan Anda mencari tabel yang dimuat secara dinamis tanpa harus menggunakan alat rumit seperti Selenium.

(
  {
    "type": "input",
    "selector": { "type": "css", "value": "#searchInput" },
    "value": "cowboy boots"
  },
  {
    "type": "click",
    "selector": {
      "type": "css",
      "value": "#search-form button(type=\"submit\")"
    }
  },
  {
    "type": "wait_for_selector",
    "selector": { "type": "css", "value": "#content" }
  }
)

Catatan: Untuk informasi lebih lanjut tentang menggores tabel Javascript, lihat panduan terperinci kami.

3. Tabel HTML salah

Beberapa tabel mungkin memiliki struktur HTML yang tidak valid atau tag penutup tidak ada. Parser yang lebih baik untuk kasus ini adalah html5lib. Berikut cara mengatasinya:

def clean_table_html(html_content):
    # Use html5lib parser for better handling of malformed HTML
    soup = BeautifulSoup(html_content, 'html5lib')
    
    # Function to check if table is valid
    def is_valid_table(table):
        if not table.find('tr'):
            return False
        rows = table.find_all('tr')
        if not rows:
            return False
        return True
    
    # Find all tables and process only valid ones
    tables = ()
    for table in soup.find_all('table'):
        if is_valid_table(table):
            # Clean up any invalid nested tables
            for nested_table in table.find_all('table'):
                nested_table.decompose()
            tables.append(table)
    
    return tables

4. Menggunakan Pandas sebagai pengganti MechanicalSoup atau BeautifulSoup

Menggunakan Pandas untuk mengikis tabel HTML menghemat banyak waktu dan membuat kode lebih andal karena Anda memilih seluruh tabel daripada elemen individual yang dapat berubah seiring waktu.

Itu read_html Metode ini memungkinkan Anda mengambil tabel secara langsung tanpa menguraikan seluruh dokumen HTML. Mengekstrak tabel jauh lebih cepat karena dioptimalkan untuk tugas khusus ini. Ini juga mengembalikan DataFrame secara langsung, sehingga memudahkan pembersihan, transformasi, dan analisis data.

Mengikis tabel HTML dengan Pandas

Sebelum Anda meninggalkan halaman ini, mari kita jelajahi pendekatan kedua untuk menggores tabel HTML. Dalam beberapa baris kode, kita dapat mengekstrak semua data tabel dari dokumen HTML dan menyimpannya dalam bingkai data menggunakan Pandas.

Buat folder baru di direktori proyek (kami beri nama pandas-html-table-scraper) dan buat nama file baru bernama pandas_table_scraper.py.

Mari buka terminal baru dan navigasikan ke folder yang baru saja kita buat (cd pandas-html-table-scraper) dan instal pandas dari sana:

Dan kami mengimpornya ke bagian atas file.

Pandas memiliki fungsi bernama read_html() yang pada dasarnya mengevaluasi URL target untuk kita dan mengembalikan semua tabel HTML sebagai daftar objek DataFrame.

Namun, agar ini berfungsi, tabel HTML setidaknya harus terstruktur dengan rapi, karena fungsinya mencari elemen seperti itu

untuk mengidentifikasi tabel dalam file.

Untuk menggunakan fungsi ini, kita membuat variabel baru dan meneruskannya ke URL yang kita gunakan sebelumnya:

employee_data = pd.read_html('http://api.scraperapi.com?api_key=51e43be283e4db2a5afbxxxxxxxxxxxx&url=https://datatables.net/examples/styling/stripe.html')

Pencetakan mengembalikan daftar tabel HTML pada halaman.

HTML FitonHTML Fiton

Jika kita membandingkan tiga baris pertama di DataFrame, baris tersebut sangat cocok dengan apa yang kita pilih menggunakan Beautiful Soup.

Untuk bekerja dengan JSON, Pandas memiliki fungsi .to_json() bawaan. Ini mengubah daftar objek DataFrame menjadi string JSON

Yang perlu kita lakukan hanyalah memanggil metode di DataFrame dan meneruskan jalur dan format (pemisahan, data, catatan, indeks, dll.) dan menambahkan indentasi untuk meningkatkan keterbacaan:

employee_data(0).to_json('./employee_list.json', orient='index', indent=2)

Sekarang ketika kita menjalankan kode kita, inilah file yang dihasilkan:

Pengikis mejaPengikis meja

Perhatikan bahwa kita harus memilih tabel kita dari indeks ((0)) karena .read_html() mengembalikan daftar dan bukan satu objek pun.

Berikut ini kode lengkap untuk referensi Anda:

import pandas as pd

employee_data = pd.read_html('http://api.scraperapi.com?api_key=51e43be283e4db2a5afbxxxxxxxxxxxx&url=https://datatables.net/examples/styling/stripe.html')

employee_data(0).to_json('./employee_list.json', orient='index', indent=2)

Berbekal pengetahuan baru ini, Anda akan siap untuk mencari hampir semua tabel HTML di web. Ingat: jika Anda memahami bagaimana situs web dibangun dan logika di baliknya, tidak ada yang tidak dapat Anda hapus.

Namun, metode ini hanya berfungsi selama datanya ada dalam file HTML. Jika Anda menemukan tabel yang dibuat secara dinamis, Anda perlu menemukan pendekatan baru. Untuk jenis tabel ini, kami telah membuat panduan langkah demi langkah untuk menyalin tabel JavaScript dengan Python tanpa memerlukan browser tanpa kepala.

Sampai jumpa lagi, selamat menggores!

Pos terkait

Tinggalkan Komentar