Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni

🤖🚫 Контент вільний від AI. Цей пост на 100% написаний людиною, як і все на моєму блозі. Насолоджуйтесь!

12.04.2023

Парсинг та обробка HTML в Go

Якщо в Go доведеться парсити HTML, то для того є непоганий офіційний пакет golang.org/x/net/html. Він здійснює потокову обробку документа; тобто ніякого DOM-дерева не будує, а замість того пропонує пройтись по документу циклом та відреагувати на всі потрібні елементи. Це дуже відрізняється від роботи з HTML у JavaScript та від культової бібліотеки Nokogiri для Ruby.

Сучасні вебінженери звикли бачити HTML як дерево, та адресувати це дерево селекторами CSS: div#header a.nav-link. Це просто в розумінні, але складно алгоритмічно: бо потребує спочатку побудови дерева, а потім ще й пошуку по ньому.

Натомість при потоковій обробці ми маємо заздалегідь запланувати, що хочемо отримати з документа, та власноруч стежити за станом обробки. Наприклад, коли зустрінемо тег div, то перевіримо, чи є в нього атрибут id==header, та якщо є, увімкнемо змінну inHeader = true. А коли зустрінемо тег a, то перевіримо, чи увімкнена змінна inHeader, та якщо так, запишемо в масив navLinks.

Якщо ми хочемо отримати з документа не єдиний “селектор”, а декілька, то стану стає багато, та відстежити що до чого стає складніше. Тому потокова обробка тільки для особливо вибагливих до швидкодії випадків.

Але є ситуація, де потокова обробка прямо набагато краще. Це коли документ ми змінюємо. Річ у тім, що розбір документа в дерево — операція зазвичай незворотна; вона втрачає нюанси форматування, та особливо — помилки синтаксису. А з таким неформатним форматом як HTML, помилка синтаксису цілком може бути помилкою тільки для даного парсера — та її “виправлення” навпаки документ поламає (прибере “неправильний” тег, наприклад). Тому й варто нічого не міняти без потреби.

З потоковою обробкою оригінальний зміст документа не втрачається; те, що нам не цікаво, ми просто копіюємо у вихідний документ — байт в байт. А зміни можна робити як на рівні блоків, так і на рівні тегів або навіть атрибутів — як забажаємо.