Розбір HTML за допомогою Golang

Гайд: як парсити HTML у Golang

У цій статті я покажу, як розбирати HTML у Go за допомогою вбудованого пакета net/html. Ми розберемо основи, а також я познайомлю вас із кількома іншими бібліотеками, які можуть краще підійти для конкретних завдань. Наприкінці ви зможете розбирати HTML, витягувати структуровані дані й використовувати Go для вебскрапінгу як профі. Почнімо!

Prerequisites

Перш ніж занурюватися в парсинг HTML у Go, переконайтеся, що у вас є таке:

  1. Go встановлено: якщо у вас ще не встановлено Go, перейдіть до офіційний сайт Go і дотримайтеся інструкцій зі встановлення.
  2. Базове розуміння синтаксису Go: якщо ви новачок у Go, варто освіжити знання його синтаксису, зокрема роботи з пакетами, функціями та обробкою помилок.
  3. Знання HTML: Розуміння структури HTML є критично важливим, адже вам потрібно буде визначити теги й атрибути, які ви хочете витягнути.
  4. Go modules: Ensure that Go modules are initialized in your project by running go mod init <module-name> if you’re starting a new project.

Парсинг HTML за допомогою net/html

Стандартна бібліотека Go надає пакет net/html для парсингу HTML. Він пропонує два основні підходи до розбору: API токенізації та API розбору вузлів, що робить його одним із найкращих парсерів HTML. У цьому туторіалі ми насамперед зосередимося на API розбору вузлів, оскільки він забезпечує абстракцію вищого рівня і з ним простіше працювати. Втім, для повноти ми також коротко зачепимо API токенізації.

Альтернативи парсингу за допомогою Go

Найкраща альтернатива, що існує зараз, — це datasets. Перегляньте мою статтю про найкращі сайти з наборами даних. If you are in a hurry, here’s a TL;DR of the top 5 dataset providers:

  1. Bright Data — Налаштовувані та готові набори даних для різних галузей.
  2. Statista — Розширена статистика та звіти для бізнесу й досліджень.
  3. Datarade — Маркетплейс преміальних продуктів з даними від різних постачальників.
  4. AWS Data Exchange — Набори даних від сторонніх постачальників, інтегровані з сервісами AWS.
  5. Zyte — Вебскрапінг і індивідуальні набори даних, адаптовані до потреб бізнесу.

Я не пов’язаний із жодним із згаданих постачальників.

Крок 1: Отримання HTML зі вебсторінки

Щоб розпарсити HTML, спочатку потрібно отримати сирий HTML-контент із вебсторінки. Це робиться шляхом виконання HTTP-запиту до URL сторінки, з якої ви хочете виконати вебскрапінг. У Go для виконання HTTP-запитів можна використовувати пакет net/http.

Ось приклад того, як виконати простий HTTP GET-запит:

package main
import (
"fmt"
"io"
"net/http"
)
func main() {
url := "https://example.com" // Replace with your target URL
resp, err := http.Get(url)
if err != nil {
fmt.Println("Помилка під час отримання URL:", err)
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Помилка читання тіла відповіді:", err)
return
}
fmt.Println("Отриманий HTML:")
fmt.Println(string(body))
}

In this code, we use HTTP.Get() to send a GET request and retrieve the response body. The page’s HTML content is printed as a string.

Крок 2: Розбір HTML за допомогою API розбору вузлів

Now that we have the raw HTML, let’s parse it. The net/html package provides a function called html.Parse() which can parse an HTML document and return a tree of nodes. Each node in the tree represents an HTML element, attribute, or piece of text.

To parse the HTML, we pass the response body (which is a nio.Reader) to html.Parse(). This will return a root node that you can traverse recursively to extract the information you need.

Ось приклад, який розбирає HTML-документ і виводить назви тегів:

package main
import (
"fmt"
"net/http"
"golang.org/x/net/html"
"io"
)
func main() {
url := "https://example.com"
resp, err := http.Get(url)
if err != nil {
fmt.Println("Помилка під час отримання URL:", err)
return
}
defer resp.Body.Close()
doc, err := html.Parse(resp.Body)
if err != nil {
fmt.Println("Помилка під час парсингу HTML:", err)
return
}
traverse(doc)
}
// Recursively traverse the HTML nodes and print their tag names
func traverse(n *html.Node) {
if n.Type == html.ElementNode {
fmt.Println("Тег:", n.Data)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
traverse(c)
}
}

This code will output the tag names (e.g.,<html>,<body>,<div>, etc.) found in the HTML document.

Крок 3: Витягування конкретних даних з HTML

To extract specific data, you’ll need to inspect the HTML structure and identify the elements that contain the information you want. For example, you want to extract all product names, prices, and image URLs from an e-commerce page. You would need to look for specific tags (such as <h2> for product names, <span> for prices, and <img> for images) and extract their content.

Ось приклад функції, яка витягує назви товарів, ціни та URL зображень:

package main
import (
"fmt"
"net/http"
"golang.org/x/net/html"
"strings"
"io"
)
func main() {
url := "https://example.com/ecommerce"
resp, err := http.Get(url)
if err != nil {
fmt.Println("Помилка під час отримання URL:", err)
return
}
defer resp.Body.Close()
doc, err := html.Parse(resp.Body)
if err != nil {
fmt.Println("Помилка під час парсингу HTML:", err)
return
}
processProducts(doc)
}
// Recursively process the HTML nodes to extract product details
func processProducts(n *html.Node) {
if n.Type == html.ElementNode && n.Data == "li" {
// Look for product name
var name string
var price string
var imageURL string
for c := n.FirstChild; c != nil; c = c.NextSibling {
switch c.Data {
case "h2":
if c.FirstChild != nil && c.FirstChild.Type == html.TextNode {
name = c.FirstChild.Data
}
case "span":
for _, a := range c.Attr {
if a.Key == "class" && strings.Contains(a.Val, "price") {
if c.FirstChild != nil && c.FirstChild.Type == html.TextNode {
price = c.FirstChild.Data
}
}
}
case "img":
for _, a := range c.Attr {
if a.Key == "src" {
imageURL = a.Val
}
}
}
}
fmt.Println("Назва продукту:", name)
fmt.Println("Price:", price)
fmt.Println("URL зображення:", imageURL)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
processProducts(c)
}
}

In this example, the processProducts function recursively searches for <li> elements. Inside each <li>, it looks for <h2> (product name), <span> (price), and <img> (image URL). It then extracts the relevant text or attributes and prints the information.

Крок 4: Обробка помилок і крайових випадків

Під час роботи з HTML ви зіткнетеся з граничними випадками, такими як відсутні теги, порожні атрибути або некоректно сформований HTML. Важливо коректно обробляти помилки та переконатися, що ваш вебскрапер може впоратися з такими сценаріями.

Наприклад, коли ви витягуєте текст із вузлів, завжди перевіряйте, чи має вузол дочірні елементи та чи є дочірній елемент текстовим вузлом. Так само під час витягування атрибутів (наприклад, src для зображень) переконайтеся, що атрибут існує, перш ніж його використовувати.

if n.FirstChild != nil && n.FirstChild.Type == html.TextNode {
fmt.Println("Текст:", n.FirstChild.Data)
}

Альтернативні бібліотеки для розбору HTML у Go

Хоча net/html є найуживанішим пакетом Go для розбору HTML, інші бібліотеки пропонують додаткові можливості або альтернативні API, які можуть бути корисними залежно від вашого конкретного сценарію використання.

Goquery

Goquery є популярною Go-бібліотекою із синтаксисом, схожим на jQuery, для обходу та модифікації HTML-документів. Goquery побудована на пакеті net/html, але надає зручніший API, який дає змогу запитувати елементи за допомогою CSS-селекторів. Це спрощує витягування конкретних даних без ручного обходу дерева HTML.

Ось приклад із використанням Goquery для вилучення назв продуктів зі сторінки:

package main
import (
"fmt"
"github.com/PuerkitoBio/goquery"
"net/http"
)
func main() {
url := "https://example.com/ecommerce"
res, err := http.Get(url)
if err != nil {
fmt.Println("Помилка:", err)
return
}
defer res.Body.Close()
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
fmt.Println("Помилка під час парсингу HTML:", err)
return
}
doc.Find("li").Each(func(i int, s *goquery.Selection) {
name := s.Find("h2").Text()
fmt.Println("Назва продукту:", name)
})
}

Goquery allows you to easily select elements using CSS selectors like doc.Find(“li h2”).Text(), making the code much cleaner and easier to read.

Other Libraries

  • Go-html-transform: ця бібліотека надає API для перетворення HTML-документів за допомогою CSS-селекторів, подібно до Goquery, але з іншим підходом. Однак вона більше не підтримується активно.
  • Html2go: Цей інструмент переважно перетворює HTML-файли на Go-код (структури). Він може бути корисним, якщо вам потрібно статично визначити структуру HTML-документа.

Conclusion

Parsing HTML in Go is pretty simple with the net/html package. You can fetch raw HTML and use html.Parse() to go through the HTML tree and get the data you need. If you want something more convenient, libraries like Goquery offer jQuery-like features that make working with HTML even easier. Whether you’re building a quick web scraper or diving into a larger web crawling project, Go’s libraries and concurrency features make it a solid choice for handling HTML parsing efficiently.

Схожі записи