Парсинг HTML в Swift (iOS/macOS) с помощью SwiftSoup
При разработке приложений для iOS и macOS часто возникает необходимость извлечь данные из HTML-страниц. Будь то парсинг новостного сайта, получение курсов валют или анализ веб-контента — без надёжного инструмента не обойтись. В мире Swift таким стандартом де-факто является библиотека SwiftSoup — чистый Swift-порт популярного Java-парсера Jsoup.
SwiftSoup предоставляет удобный API для загрузки, парсинга и манипуляции HTML-документами, используя CSS-селекторы и методы обхода DOM. Библиотека полностью написана на Swift, не имеет внешних зависимостей и поддерживает все платформы Apple: iOS (начиная с 11.0), macOS (10.13+), watchOS и tvOS.
Установка SwiftSoup через Swift Package Manager
Добавьте зависимость в Package.swift вашего проекта или через меню Xcode: File → Add Packages...
// Package.swift
dependencies: [
.package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.6.0")
],
targets: [
.target(
name: "YourTarget",
dependencies: ["SwiftSoup"])
]
// Или в Xcode: https://github.com/scinfu/SwiftSoup.git, версия 2.6.0
После установки импортируйте библиотеку в нужном файле:
import SwiftSoup
Базовый парсинг HTML-строки
Самый простой способ начать работу — распарсить HTML-строку, полученную, например, из URLSession:
let html = """
<html>
<body>
<h1>Привет, мир!</h1>
<p class="content">Это текст внутри параграфа</p>
<a href="https://example.com">Ссылка</a>
</body>
</html>
"""
do {
let doc: Document = try SwiftSoup.parse(html)
let title = try doc.title()
let paragraph = try doc.select("p.content").first()?.text()
let link = try doc.select("a").first()?.attr("href")
print("Заголовок: \(title)")
print("Параграф: \(paragraph ?? "не найден")")
print("Ссылка: \(link ?? "не найдена")")
} catch {
print("Ошибка парсинга: \(error)")
}
Загрузка и парсинг HTML из сети
Чаще всего HTML получают по HTTP. Вот пример загрузки страницы и извлечения данных:
import Foundation
import SwiftSoup
func fetchAndParse(urlString: String) async {
guard let url = URL(string: urlString) else { return }
do {
let (data, _) = try await URLSession.shared.data(from: url)
guard let html = String(data: data, encoding: .utf8) else { return }
let doc = try SwiftSoup.parse(html)
// Извлекаем все ссылки
let links = try doc.select("a[href]")
for link in links {
let href = try link.attr("href")
let text = try link.text()
print("\(text) -> \(href)")
}
// Извлекаем заголовки h2
let headings = try doc.select("h2")
for heading in headings {
print("Заголовок: \(try heading.text())")
}
} catch {
print("Ошибка: \(error)")
}
}
// Использование
Task {
await fetchAndParse(urlString: "https://example.com")
}
Работа с CSS-селекторами
SwiftSoup поддерживает практически все стандартные CSS-селекторы, что делает поиск элементов интуитивным:
tag— по имени тега:try doc.select("div")#id— по идентификатору:try doc.select("#main-content").class— по классу:try doc.select(".article-title")[attribute]— по атрибуту:try doc.select("[data-id]")parent > child— прямой потомок:try doc.select("ul > li")el:contains(text)— по содержимому:try doc.select("p:contains(Важно)")
Пример комбинированного запроса:
let items = try doc.select("div.product-item:has(.price)")
for item in items {
let name = try item.select("h3.product-name").text()
let price = try item.select("span.price").text()
print("\(name): \(price)")
}
Извлечение и изменение атрибутов
Помимо текста, можно получать и изменять атрибуты элементов:
Также в библиотеке
Рекомендаций