Parseo de HTML en Swift (iOS/macOS) con SwiftSoup
Al desarrollar aplicaciones para iOS y macOS, a menudo surge la necesidad de extraer datos de páginas HTML. Ya sea para parsear un sitio de noticias, obtener tipos de cambio o analizar contenido web, no se puede prescindir de una herramienta confiable. En el mundo de Swift, el estándar de facto es la librería SwiftSoup, un puerto puro en Swift del popular parser Java Jsoup.
SwiftSoup proporciona una API conveniente para cargar, parsear y manipular documentos HTML, utilizando selectores CSS y métodos de recorrido del DOM. La librería está completamente escrita en Swift, no tiene dependencias externas y es compatible con todas las plataformas Apple: iOS (desde 11.0), macOS (10.13+), watchOS y tvOS.
Instalación de SwiftSoup mediante Swift Package Manager
Agregue la dependencia en Package.swift de su proyecto o a través del menú de Xcode: File → Add Packages...
// Package.swiftdependencies: [ .package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.6.0")],targets: [ .target( name: "YourTarget", dependencies: ["SwiftSoup"])]
// O en Xcode: https://github.com/scinfu/SwiftSoup.git, versión 2.6.0Después de la instalación, importe la librería en el archivo correspondiente:
import SwiftSoupParseo básico de una cadena HTML
La forma más sencilla de empezar es parsear una cadena HTML obtenida, por ejemplo, de URLSession:
let html = """<html> <body> <h1>¡Hola, mundo!</h1> <p class="content">Este es el texto dentro del párrafo</p> <a href="https://example.com">Enlace</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("Título: \\(title)") print("Párrafo: \\(paragraph ?? "no encontrado")") print("Enlace: \\(link ?? "no encontrado")")} catch { print("Error de parseo: \\(error)")}Carga y parseo de HTML desde la red
La mayoría de las veces, el HTML se obtiene por HTTP. Aquí hay un ejemplo de carga de una página y extracción de datos:
import Foundationimport 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) // Extraer todos los enlaces 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)") } // Extraer encabezados h2 let headings = try doc.select("h2") for heading in headings { print("Encabezado: \\(try heading.text())") } } catch { print("Error: \\(error)") }}
// UsoTask { await fetchAndParse(urlString: "https://example.com")}Trabajo con selectores CSS
SwiftSoup admite prácticamente todos los selectores CSS estándar, lo que hace que la búsqueda de elementos sea intuitiva:
tag— por nombre de etiqueta:try doc.select("div")#id— por identificador:try doc.select("#main-content").class— por clase:try doc.select(".article-title")[attribute]— por atributo:try doc.select("[data-id]")parent > child— hijo directo:try doc.select("ul > li")el:contains(t