Парсинг HTML на Go

Как разбирать HTML в Golang: руководство

В этой статье я покажу, как парсить HTML в Go с помощью встроенного пакета net/html. Мы разберем основы, а также я познакомлю вас с несколькими другими библиотеками, которые могут лучше подойти для конкретных задач. К концу вы сможете парсить HTML, извлекать структурированные данные и использовать Go для веб-скрапинга на профессиональном уровне. Давайте начнем!

Пререквизиты

Прежде чем погружаться в парсинг HTML на Go, убедитесь, что у вас есть следующее:

  1. Если 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

Лучшей альтернативой, доступной сейчас, являются наборы данных. Ознакомьтесь с моей статьей о лучшие сайты с датасетами. If you are in a hurry, here’s a TL;DR of the top 5 dataset providers:

  1. Яркие данные — Настраиваемые и готовые наборы данных по различным отраслям.
  2. Statista — Подробная статистика и отчеты для бизнеса и исследований.
  3. Datarade — Маркетплейс премиальных data-продуктов от разных поставщиков.
  4. AWS Data Exchange Наборы данных сторонних поставщиков, интегрированные с сервисами AWS.
  5. Zyte — Веб-скрейпинг и пользовательские наборы данных, адаптированные под потребности бизнеса.

Я не связан ни с одним из упомянутых поставщиков.

Шаг 1: получение HTML с веб-страницы

Чтобы парсить HTML, сначала нужно получить необработанный HTML-контент со страницы. Для этого отправляют HTTP-запрос по URL нужной страницы, которую вы хотите скрапить. В Go для этого можно использовать пакет net/http.

Вот пример того, как выполнить простой HTTP GET-запрос:

package главная
импорт (
"fmt"
"io"
"net/http"
)
func главная() {
url := "https://example.com" // Replace with your target URL
resp, err := http.Get(url)
если err != nil {
fmt.Println("Ошибка при получении URL:", err)
возврат
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
если err != nil {
fmt.Println("Ошибка при чтении тела ответа:", err)
возврат
}
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 главная
импорт (
"fmt"
"net/http"
"golang.org/x/net/html"
"io"
)
func главная() {
url := "https://example.com"
resp, err := http.Get(url)
если err != nil {
fmt.Println("Ошибка при получении URL:", err)
возврат
}
defer resp.Body.Close()
doc, err := html.Parse(resp.Body)
если err != nil {
fmt.Println("Ошибка при разборе HTML:", err)
возврат
}
traverse(doc)
}
// Recursively traverse the HTML nodes and print their tag names
func traverse(n *html.Node) {
если n.Type == html.ElementNode {
fmt.Println("Tag:", n.Data)
}
для 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 главная
импорт (
"fmt"
"net/http"
"golang.org/x/net/html"
"strings"
"io"
)
func главная() {
url := "https://example.com/ecommerce"
resp, err := http.Get(url)
если err != nil {
fmt.Println("Ошибка при получении URL:", err)
возврат
}
defer resp.Body.Close()
doc, err := html.Parse(resp.Body)
если err != nil {
fmt.Println("Ошибка при разборе HTML:", err)
возврат
}
processProducts(doc)
}
// Recursively process the HTML nodes to extract product details
func processProducts(n *html.Node) {
если n.Type == html.ElementNode && n.Data == "li" {
// Look for product name
var name string
var price string
var imageURL string
для c := n.FirstChild; c != nil; c = c.NextSibling {
switch c.Data {
case "h2":
если c.FirstChild != nil && c.FirstChild.Type == html.TextNode {
name = c.FirstChild.Data
}
case "span":
для _, a := ассортимент c.Attr {
если a.Key == "class" && strings.Contains(a.Val, "цена") {
если c.FirstChild != nil && c.FirstChild.Type == html.TextNode {
price = c.FirstChild.Data
}
}
}
case "img":
для _, a := ассортимент c.Attr {
если a.Key == "src" {
imageURL = a.Val
}
}
}
}
fmt.Println("Product Name:", name)
fmt.Println("Цена:", price)
fmt.Println("URL изображения:", imageURL)
}
для 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` для изображений) убедитесь, что атрибут существует, прежде чем использовать его.

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

Альтернативные библиотеки для парсинга HTML в Go

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

Goquery

Goquery Goquery — популярная библиотека Go с jQuery-подобным синтаксисом для обхода и манипулирования HTML-документами. Goquery основана на пакете net/html, но предоставляет более удобный API, позволяющий запрашивать элементы с помощью CSS-селекторов. Это упрощает извлечение конкретных данных без ручного обхода дерева HTML.

Вот пример с использованием Goquery для извлечения наименований товаров со страницы:

package главная
импорт (
"fmt"
"github.com/PuerkitoBio/goquery"
"net/http"
)
func главная() {
url := "https://example.com/ecommerce"
res, err := http.Get(url)
если err != nil {
fmt.Println("Ошибка:", err)
возврат
}
defer res.Body.Close()
doc, err := goquery.NewDocumentFromReader(res.Body)
если err != nil {
fmt.Println("Ошибка при разборе HTML:", err)
возврат
}
doc.Find("li").Each(func(i int, s *goquery.Selection) {
name := s.Find("h2").Text()
fmt.Println("Product Name:", 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-документа.

Заключение

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.

Похожие записи