Publicidad:
La Coctelera

Sugerencia de presentación

He nacido para vago

29 Enero 2007

El feed de los que no tienen feed

Desde hace unos días tenía pendiente un favorcillo que alguien me pidió. No es (reconozcámoslo) que me apeteciera mil porque me olía que la solución, conociéndome a mí y conociendo el problema, sería guarra a más no poder. Pero como quien me lo pidió es alguien adorable que bien merece dedicarle algunos minutos (y mucho más), pues me puse a la tarea, ayer, con pijama, manta, y la ola de frío al otro lado de la puerta. Por supuesto, en Ruby, el lenguaje sexy y buzz-compliant.

Hete aquí que cuando acabo (sí, amigos, por una vez el cuento acaba bien) me encuentro con que mi buen amigo Felipe acaba de publicar una solución completamente diferente a un problema completamente igual (aunque en realidad su script hace alguna cosa más). También en Ruby. Y como, para mi gusto (esto es como con los hijos), mi solución es más limpia, bonita y fácil, heme aquí compartiéndola, con él, y con todos los demás.

La tarea es simple, obtener un feed de una página que no lo tiene, para poder usarlo en un agregador, incluírlo en otra página, o para cualquiera de las cosas chupis y bonitas que se pueden hacer con un feed. Para ello no queda más remedio que parsear el HTML de la página, buscar el contenido relevante, y luego construir con él el feed. Se dice rápido. Y se hace casi más.

scrAPI es una librería de Ruby que sirve exactamente para eso: scrapear (si tuviera que traducir la palabra, diría guarrear, y me parece un poco ofensivo =:-P) HTML.

Para hacerlo, hemos de definir, con un minilenguaje al efecto, las estructuras de datos que se van a buscar, y mapear en qué elementos HTML se encuentran, usando selectores CSS. Se entiende más fácil que se explica (perdón por la ausencia de sangrado):

 recording = Scraper.define do
   process 'a img', :img => "@src"
   process 'div.datosGrabacion h3 a', :author => :text, :url => "@href"
   process 'p', :title => :text
   result :url, :author, :title, :img
 end
 

Con ese código definimos una estructura llamada recording, formada por url, autor, título e imagen, y los selectores que nos permiten encontrar esos atributos.

Alguno dirá (yo lo diría): "¡Qué mierda de filtro! Si buscas por 'a img' o por 'p' vas a encontrar mogollón de resultados que no te interesan". Una de las cosas que más molan de scrAPI es que se pueden definir las estructuras de forma anidada, lo cual permite afinar mucho más, y además es DRY:

 recordings = Scraper.define do
   array :recordings
   process "div#contenido ul.listado li", :recordings => recording
   result :recordings
 end
 

Con ésto definimos una estructura llamada recordings (nótese el plural), compuesta de muchos recording (la estructura que definimos antes), cada uno de ellos dentro de un "div#contenido ul.listado li". Ahora sí que no podemos fallar =;-)

Así pues, ya sólo nos queda aplicar este scraper a la página en cuestión:

 recordings_data = recordings.scrape(URI.parse("http://thebellemusic.com/grabaciones.asp"))
 

Y crear el feed con FeedTools, que además de ser muy fácil ya lo contó Manuel hace poco", así que no hace falta mucho detalle, ¿no?

El script completo:

 require 'rubygems'
 require 'scrapi'
 require 'feed_tools'
 
 recording = Scraper.define do
   process 'a img', :img => "@src"
   process 'div.datosGrabacion h3 a', :author => :text, :url => "@href"
   process 'p', :title => :text
   result :url, :author, :title, :img
 end
 
 recordings = Scraper.define do
   array :recordings
   process "div#contenido ul.listado li", :recordings => recording
   result :recordings
 end
 
 recordings_data = recordings.scrape(URI.parse("http://thebellemusic.com/grabaciones.asp"))
 
 recordings_feed = FeedTools::Feed.new
 recordings_feed.title = 'TBM - Grabaciones'
 recordings_feed.author = 'The Belle Music'
 recordings_feed.link = 'http://thebellemusic.com/'
 recordings_feed.language = 'es-ES'
 
 recordings_data.each do |recording|
   item = FeedTools::FeedItem.new
   item.title = "#{recording[:author]} - #{recording[:title]}"
   item.link = "#{recordings_feed.link}#{recording[:url]}"
   item.description = "\"#{recording[:title]}\""
   recordings_feed.items << item
 end
 
 puts recordings_feed.build_xml('rss', 2.0)
 

Por Dios, qué horror, sin sangrado ni colores; se recomienda bajarlo y abrirlo con un editor decente =;-)

Y bueno, para otro día dejamos la reflexión sobre qué pueden significar este tipo de técnicas para la web, permitiendo ir más allá, en cuanto al intercambio de contenidos, que los feeds (que ya es), y en definitiva de lo que el autor de los mismos haya tenido a bien prever. Y sin olvidar los microformatos, claro.

servido por porras 4 comentarios compártelo

4 comentarios · Escribe aquí tu comentario

Ale Muñoz

Ale Muñoz dijo

Hombre, pues esto nos va a venir de coña para la próxima barrabasada del departamento de chapa y pintura :D

Mi pregunta es... scrAPI o hPricot?

29 Enero 2007 | 11:58 PM

sergio

sergio dijo

Pues... si te fijas el post va d eeso porque Felipe usó hPricot.

La verdad, no sabría decir porque no he usado ninguno de los dos en profundidad. Mi intuición y primera impresión es que scrAPI es más limpio, fácil y bonito, y hPricot más potente. Potencia que el 90% de las veces no hace falta.

Pero prefiero no mojarme, no he entrado en profundidad...

Aunque... el Scraper.define do... me tiene enamorao! =xD

30 Enero 2007 | 12:10 AM

ana

ana dijo

Pues está quedando bien-bonito :) ...

Qué paciencia tenés! ;-)

30 Enero 2007 | 11:06 AM

Felipe

Felipe dijo

Jurrr!! No conocia esa libreria, la verdad no conocía ninguna y la primera que encontré fue hPricot, y me puse con ella.... pero vamos la verdad es que esta la veo mas elegante, habrá que usarla para el siguiente parseo...

De todas formas según lo que he podido ver en las dos, si el html a parsear esta bien marcado y usa css o usan xhtml no tendremos problemas con ninguna de las dos, pero si te hacen guarreridas de la calaña de meterte urls dentro de javascript y cositas así pues la cosa se complica y tienes que empezar a usar expresiones regulares y hacer pirulas como las que me tocó hacer a mi en el script.

Un saludo :-D

30 Enero 2007 | 12:48 PM

Escribe tu comentario


Sobre mí

Avatar de porras

Sugerencia de presentación

ver perfil »
contacto »

Me llamo Sergio Gil Pérez de la Manga, y mi madre se cabrea si escribo mi nombre con un sólo apellido. Vivo, trabajo y hago casi todo lo demás en Madrid.

Trabajo como programador porque es lo más parecido que he encontrado a no trabajar. Sobre todo si lo haces bien. Y en eso estoy, en hacerlo cada vez mejor para trabajar cada vez menos. Alguno lo llamaría vagancia, y yo ahí no me meto.

Algunas de las herramientas que en este momento me llevan al Nirvana de no dar un palo al agua son Ruby, Ruby on Rails, Textmate, cualquier sabor de Unix (en este momento principalmente MacOSX pero también Ubuntu Linux) y sus herramientas, o Rake. En ocasiones hablo de ellas aquí, pienso que a alguien le pueden servir y que no puedo ser el único al que no le gusta trabajar.

Y como no sólo de tecnología vive el hombre (bueno, el hombre no sé, pero desde luego yo no), por aquí aparece de vez en cuando la punta del iceberg de mis pequeños pensamientos; al menos la parte de ellos que no cabe en Twitter.

Bienvenidos todos.

Y ahora: ¿Y tú?

Fotos

porras todavía no ha subido ninguna foto.

¡Anímale a hacerlo!

Buscar

suscríbete

Selecciona el agregador que utilices para suscribirte a este blog (también puedes obtener la URL de los feeds):

¿Qué es esto?

Crea tu blog gratis en La Coctelera