āš™ļø Panduan Lengkap: Skrip Otomatis Perbaikan HTML

Sebuah rangkuman perjalanan dari error hingga solusi final dengan Python & BeautifulSoup.

Dalam proses mengelola banyak file HTML, seringkali kita menemukan error-error kecil yang berulang. Memperbaikinya satu per satu tentu membuang waktu. Solusinya? Membuat skrip otomatis! Halaman ini merangkum proses pembuatan skrip Python dari awal, termasuk cara mengatasi berbagai kendala yang muncul di lingkungan Linux modern.


Tahap 1: Kendala Instalasi 🚧

Langkah pertama dalam membuat skrip ini adalah menginstal library yang dibutuhkan: `BeautifulSoup4` dan `lxml`. Namun, di distro Linux modern, kita seringkali disambut dengan error:

pip install beautifulsoup4 lxml
error: externally-managed-environment

Kenapa Error Ini Muncul?

Error ini adalah sebuah fitur keamanan. Sistem operasi Linux (seperti Ubuntu/Debian) ingin melindungi paket Python internalnya agar tidak rusak oleh instalasi `pip` yang dilakukan pengguna. Jadi, ia "mengunci" lingkungan Python sistem.

Solusi Terbaik: Virtual Environment (`venv`)

Cara paling profesional adalah dengan membuat lingkungan kerja yang terisolasi. Dengan begitu, kita bebas menginstal paket apa pun tanpa mengganggu sistem utama.

# 1. Buat folder lingkungan virtual bernama 'venv'
python3 -m venv venv

# 2. Aktifkan lingkungan tersebut
source venv/bin/activate

Tahap 2: Error Shell yang Tidak Kompatibel 🐟

Setelah membuat `venv`, beberapa pengguna (terutama pengguna `fish` shell) akan menemukan error baru saat mencoba mengaktifkannya:

source venv/bin/activate
venv/bin/activate: 'case' builtin not inside of switch block

Kenapa Error Ini Muncul?

Skrip `activate` standar ditulis untuk shell `bash`. Shell lain seperti `fish` memiliki sintaks yang berbeda dan tidak bisa menjalankannya. Untungnya, `venv` sudah menyediakan solusinya.

Solusi: Gunakan Skrip Aktivasi yang Tepat

Cukup gunakan file aktivasi yang berakhiran `.fish`.

# Perintah aktivasi yang benar untuk fish shell
source venv/bin/activate.fish

Setelah perintah ini, terminal Anda akan menampilkan `(venv)` di depannya, menandakan Anda sudah berada di lingkungan virtual dan siap untuk melanjutkan instalasi.


Tahap 3: Skrip Final Perbaikan HTML šŸ

Setelah berhasil mengatasi masalah lingkungan, inilah skrip final `fix_html.py` yang kita kembangkan. Skrip ini tidak hanya memperbaiki error struktural, tetapi juga membersihkan spasi berlebih dan membuat file log yang rapi.

Fitur Utama Skrip:
1. Memperbaiki tag yang rusak.
2. Memindahkan konten yang salah tempat ke dalam `<body>`.
3. Membersihkan tag `<script>` JSON-LD.
4. Menghapus `<div>` kosong.
5. Membersihkan spasi dan baris baru di dalam tag (misal: `<strong>`).
6. Membuat file log `perbaikan_log.txt` dengan ringkasan.

import os
import re
from bs4 import BeautifulSoup, Comment, NavigableString

LOG_FILE = "perbaikan_log.txt"

def strip_whitespace_in_tags(soup):
    tags_to_exclude = {'pre', 'code', 'style', 'script'}
    for tag in soup.find_all(lambda t: t.name not in tags_to_exclude):
        for content in list(tag.contents):
            if isinstance(content, NavigableString):
                cleaned_string = str(content).replace('\xa0', ' ').strip()
                if cleaned_string != str(content):
                    if cleaned_string:
                        content.replace_with(cleaned_string)
                    else:
                        content.extract()

def fix_html_file(file_path):
    log_messages = []
    has_changes = False
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()

×
if "times;" in content:
×
content = content.replace("times;", "×") log_messages.append(" - Memperbaiki <span> penutup pencarian yang rusak.") has_changes = True end_marker = '</html>' if end_marker in content and content[content.rfind(end_marker) + len(end_marker):].strip(): log_messages.append(f" - Menemukan konten setelah </html> yang akan dipindahkan.") has_changes = True soup = BeautifulSoup(content, 'lxml') if not soup.body: return log_messages json_scripts = soup.find_all('script', type='application/ld+json') json_cleaned_count = 0 for script in json_scripts: if script.string: original_string = script.string # Perbaikan di sini: karakter < dan > harus di-escape cleaned_json = re.sub(r'<[^>]+>|', '', original_string, flags=re.DOTALL) if cleaned_json.strip() != original_string.strip(): script.string = cleaned_json.strip() json_cleaned_count += 1 if json_cleaned_count > 0: log_messages.append(f" - Membersihkan {json_cleaned_count} blok skrip JSON-LD.") has_changes = True empty_divs_removed = 0 for div in soup.find_all('div'): if not any(isinstance(c, Comment) or (isinstance(c, str) and c.strip()) or hasattr(c, 'name') for c in div.contents): div.decompose() empty_divs_removed += 1 if empty_divs_removed > 0: log_messages.append(f" - Menghapus {empty_divs_removed} tag <div> kosong.") has_changes = True strip_whitespace_in_tags(soup) log_messages.append(" - Membersihkan spasi berlebih di dalam tag HTML.") has_changes = True if has_changes: output_path = file_path.replace('.html', '_fixed.html') with open(output_path, 'w', encoding='utf-8') as f: f.write(soup.prettify(formatter="html5")) print(f" [āœ“] Perbaikan & pembersihan diterapkan: {os.path.basename(output_path)}") else: print(f" [-] Tidak ada perbaikan yang diperlukan.") return log_messages except Exception as e: print(f" [āœ—] Gagal memproses {file_path}: {e}") return [f" - ERROR: {e}"] def main(): all_logs = {} if os.path.exists(LOG_FILE): os.remove(LOG_FILE) html_files_to_process = sorted([f for f in os.listdir('.') if f.endswith('.html') and not f.endswith('_fixed.html')]) if not html_files_to_process: print("šŸ¤·ā€ā™‚ļø Tidak ada file .html yang ditemukan.") return print(f"Ditemukan {len(html_files_to_process)} file untuk diproses...\n") for filename in html_files_to_process: print(f"[*] Memproses file: {filename}...") log_messages = fix_html_file(os.path.join('.', filename)) if log_messages: all_logs[filename] = log_messages print("\nšŸŽ‰ Proses selesai.") if all_logs: with open(LOG_FILE, 'w', encoding='utf-8') as log_file: log_file.write(f"================ SUMMARY ================\n") log_file.write(f"Total file yang diproses dan dibersihkan: {len(all_logs)}\n") log_file.write(f"=======================================\n\n") for filename in sorted(all_logs.keys()): log_file.write(f"Log untuk file: {filename}\n") for msg in all_logs[filename]: log_file.write(f"{msg}\n") log_file.write("-" * 40 + "\n") print(f"šŸ“ Catatan log dengan summary telah dibuat di: {LOG_FILE}") if __name__ == "__main__": main()

Tahap 4: Cara Penggunaan & Hasil šŸš€

Langkah-langkah Eksekusi

  1. Simpan kode di atas sebagai `fix_html.py`.
  2. Letakkan di folder yang sama dengan file-file HTML Anda.
  3. Buka terminal di folder tersebut.
  4. Aktifkan lingkungan virtual (`source venv/bin/activate.fish`).
  5. Jalankan skrip: `python fix_html.py`.

Hasil Akhir

Skrip akan menghasilkan dua hal:

  • File `*_fixed.html` untuk setiap file yang diperbaiki.
  • Satu file log `perbaikan_log.txt` yang berisi ringkasan dan detail semua perbaikan.
Contoh Log:
================ SUMMARY ================
Total file yang diproses dan dibersihkan: 1
=======================================

Log untuk file: contoh.html
  - Memperbaiki <span> penutup pencarian yang rusak.
  - Menemukan konten setelah </html> yang akan dipindahkan.
  - Membersihkan spasi berlebih di dalam tag HTML.
----------------------------------------

Semoga Berhasil.


×