Primeros pasos con Nokogiri

Instalación o configuración

Instrucciones detalladas sobre cómo configurar o instalar Nokogiri.

Cómo analizar HTML o XML en un documento XML o HTML de Nokogiri

No hay mucho que agregar al tutorial “Análisis de un documento HTML/XML” de Nokogiri, que es una introducción fácil al tema, así que comience allí y luego regrese a esta página para ayudar a llenar algunos vacíos.

El análisis básico de Nokogiri intenta limpiar un documento con formato incorrecto, a veces agregando etiquetas de cierre que faltan, y agregará algunas etiquetas adicionales para corregirlo.

Este es un ejemplo de decirle a Nokogiri que el documento que se está analizando es un archivo HTML completo, y Nokogiri descubre que no lo es:

require 'nokogiri'

doc = Nokogiri::HTML('<body></body>')
puts doc.to_html 

Qué salidas:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body></body></html>

Observe que se agregó la declaración DTD, junto con una etiqueta <html> de envoltura.

Si queremos evitar esto, podemos analizar el documento como un DocumentFragment:

require 'nokogiri'

doc = Nokogiri::HTML.fragment('<body></body>')
puts doc.to_html 

que ahora genera solo lo que realmente se pasó:

<body></body>

También hay una variante XML:

require 'nokogiri'

doc = Nokogiri::XML('<node />')
puts doc.to_xml

Qué salidas:

<?xml version="1.0"?>
<node/>

y:

doc = Nokogiri::XML.fragment('<node />')
puts doc.to_xml

Resultando en:

<node/>

Una variación más detallada de fragmento es usar DocumentFragment.parse, por lo que a veces lo verás escrito de esa manera.

De vez en cuando, Nokogiri tendrá que hacer algunas correcciones para intentar que el documento tenga sentido:

doc = Nokogiri::XML::DocumentFragment.parse('<node ><foo/>')
puts doc.to_xml

Con el código modificado ahora siendo:

<node>
  <foo/>
</node>

Lo mismo puede ocurrir con HTML.

A veces, el documento está destrozado más allá de la capacidad de Nokogiri para arreglarlo, pero lo intentará de todos modos, lo que dará como resultado un documento que tiene una jerarquía cambiada. Nokogiri no generará una excepción, pero proporciona una forma de verificar los errores y las acciones que tomó. Consulte “https://www.wikiod.com/es/nokogiri/primeros-pasos-con-nokogiri#Cómo comprobar si hay errores de análisis” para obtener más información.

Consulte la documentación de Nokogiri::XML::ParseOptions para conocer las diversas opciones que se utilizan al analizar.

Cómo verificar errores de análisis

Nokogiri es algo así como un navegador, en el sentido de que intentará proporcionar algo útil incluso si el HTML o XML entrante tiene un formato incorrecto. Lamentablemente suele hacerlo en silencio, pero podemos pedir una lista de los errores usando errors:

require 'nokogiri'

doc = Nokogiri::XML('<node><foo/>')
doc.errors
# => [#<Nokogiri::XML::SyntaxError: 1:13: FATAL: Premature end of data in tag node line 1>]

mientras que el XML correcto no generaría errores:

doc = Nokogiri::XML('<node><foo/></node>')
doc.errors
# => []

Esto también se aplica al análisis de HTML, pero, debido a que HTML es una forma relajada de XML, Nokogiri pasará por alto los nodos finales faltantes con frecuencia y solo informará nodos con formato incorrecto y más errores patológicos:

doc = Nokogiri::HTML('<html><body>')
doc.errors
# => []

doc = Nokogiri::HTML('<html><body><p')
doc.errors
# => [#<Nokogiri::XML::SyntaxError: 1:15: ERROR: Couldn't find end of Start Tag p>]

Si, después del análisis, no puede encontrar un nodo que pueda ver en su editor, esta podría ser la causa del problema. A veces ayuda pasar el HTML a través de un formateador y ver si el anidamiento ayuda a revelar el problema.

Y, debido a que Nokogiri intenta solucionar el problema, pero a veces no puede hacerlo correctamente, ya que puede ser algo muy difícil de hacer para el software, tendremos que procesar previamente el archivo y retocar las líneas antes de entregarlo. a Nokogiri. Cómo hacerlo depende del archivo y del problema. Puede variar desde simplemente encontrar un nodo y agregar un final >, hasta eliminar el marcado incrustado mal formado que fue inyectado por una mala rutina de raspado, por lo que depende del programador cuál es la mejor manera de interceder.

Cómo extraer texto de un nodo o nodos

Cómo extraer correctamente el texto de los nodos es una de las preguntas más populares que vemos, y casi invariablemente se hace más difícil por el mal uso de los métodos de “búsqueda” de Nokogiri.

Nokogiri admite el uso de selectores CSS y XPath. Estos son equivalentes:

doc.at('p').text   # => "foo"
doc.at('//p').text # => "foo"

doc.search('p').size   # => 2
doc.search('//p').size # => 2

Los selectores de CSS están ampliados con muchas de las extensiones de CSS de jQuery para mayor comodidad.

at y search son ​​versiones genéricas de at_css y at_xpath junto con css y xpath. Nokogiri intenta determinar si se está pasando un selector CSS o XPath. Es posible crear un selector que engañe a at o search, por lo que ocasionalmente no entenderá bien, razón por la cual tenemos las versiones más específicas de los métodos. . En general, uso las versiones genéricas casi siempre, y solo uso la versión específica si creo que Nokogiri lo malinterpretará. Esta práctica se incluye en la primera entrada de “Tres virtudes”.

Si está buscando un nodo específico y quiere su texto, entonces use at o una de sus variantes at_css o at_xpath:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<html>
  <body>
    <p>foo</p>
    <p>bar</p>
  </body>
</html>
EOT

doc.at('p').text # => "foo"

at es equivalente a buscar(...).primero, por lo que podría usar la versión más larga para escribir, pero ¿por qué?

Si el texto que se extrae se concatena después de usar search, css o xpath, agregue map(&:text) en lugar de simplemente usar text:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<html>
  <body>
    <p>foo</p>
    <p>bar</p>
  </body>
</html>
EOT

doc.search('p').text        # => "foobar"
doc.search('p').map(&:text) # => ["foo", "bar"]

Consulte la documentación text para NodeSet y Node para obtener información adicional.