Obtener imágenes de un enlace (al estilo Facebook) usando YQL, JSON y jQuery

(Ejemplo directo en: http://jsfiddle.net/4lberto/mGxGB/12/)

En Facebook, Google+ y otros sitios actuales es posible compartir un enlace a una página web con nuestros contactos. Una de las características de estos enlaces es que suelen aparecer con imágenes asociadas como ilustración del enlace. En este post veremos cómo podemos obtener en tiempo real las imágenes de un enlace cualquiera para mostrárselas a un usuario.

La herramienta principal que usaremos será YQL, abreviatura de Yahoo Query Language. Se trata de una utilidad que permite utilizar la potencia de análisis de datos de yahoo mediante una interfaz de comandos al estilo SQL, de modo que se evita tener que programar engorrosos métodos de parseo para tratar la información en formato Web.  Permite muchas otras utilidades.

La llamada a la herramienta YQL la realizaremos a través de una llamada AJAX de jQuery por ejemplo y obtendremos como respuesta un JSON con la información requerida. En nuestro caso le pasaremos al motor de YQL una URL y como salida esperaremos un JSON con todos los elementos img que cumplan las caracterísicas que hemos demandado.

YQL tiene una interfaz web donde se pueden programar la consultas al estilo de los clientes SQL para bases de datos relacionales. En esta interfaz podremos tanto programar la consulta y ver sus resultados como configurar el formato de salida. Para ello se accede a http://developer.yahoo.com/yql/ . El acceso a la consola de pruebas es: http://developer.yahoo.com/yql/console/

Nuestra consulta estará basada en la siguiente:


select * from html where url="http://www.engagdet.com" and xpath="//img"

Esta consulta nos devuelve todos los elementos img de la URL http://www.engagdet.com. Si seleccionamos el formato JSON, además de metainformación de la consulta, el resultado que obtenemos será algo similar al siguiente:

"results": {
"img": [
{
"alt": " Foto: BBC MUNDO",
"height": "305",
"src": "http://p2.trrsf.com/image/get?src=http%3A%2F%2Fimages.terra.com%2F2012%2F10%2F27%2F01-morgue.jpg&w=407&h=305&o=cf",
"title": " Foto: BBC MUNDO",
"width": "407"
},
{
"alt": " Foto: BBC MUNDO",
"height": "41",
"src": "http://p2.trrsf.com/image/get?src=http%3A%2F%2Fimages.terra.com%2F2012%2F10%2F27%2F01-morgue.jpg&w=55&h=41&o=cf",
"title": " Foto: BBC MUNDO",
"width": "55"
},
{
"alt": " Foto: DIFUSION",
"height": "41",
"src": "http://p2.trrsf.com/image/get?src=http%3A%2F%2Fimages.terra.com%2F2012%2F10%2F27%2F02-oxford.jpg&w=55&h=41&o=cf",
"title": " Foto: DIFUSION",
"width": "55"
},

Como dentro de una página Web existen multitud de imágenes y no todas ellas están relacionadas con el contenido, se puede filtrar por tamaños, por lo que podemos exigir un tamaño mínimo que nos  evite estas imágenes. Desgraciadamente diferenciar por el contenido es una operación inviable. También podemos ordenar los resultados por tamaño de modo que los primeros sean los mayores. Es probable que las imágenes más grandes de una página Web sean las que acompañan a la noticia. Desafortunadamente aquellas foto que no tengan un tamaño específicos en los atributos width y height de img no podrán ser catalogadas.

La consulta con estas condiciones aparece a continuación:


select * from html where url="http://www.terra.com" and xpath="//img" and width>60 | sort(field='width', descending='true')
<pre>

Finalmente configuraremos el resultado en formato JSON que es lo que vamos a analizar con la llamada AJAX de jQuery. Tomamos la URL de llamada que nos indica YQL. La podemos encontrar en la zona inferior de la consola de YQL. En nuestro ejemplo la URL de llamada será la siguiente (* contiene saltos de línea para que sea legible) :


http://query.yahooapis.com/v1/public/yql?
q=select%20*%20from%20html%20where%20url%3D%22http%3A%2F%2F
www.terra.com%22%20and%20xpath%3D%22%2F%2Fimg%22%20and%20
width%3E60%20%7C%20sort(field%3D'width'%2C%20descending%3D'true')

Una vez tenemos la consulta hecha y probada ejecutando la URL en el navegador y probando la salida en servicios como http://json.parser.online.fr/, podemos pasar a programar la parte de Javascript con jQuery.

Tenemos que tener en cuenta de que se trata de una llamada AJAX a un dominio diferente al de residencia del Javascript. Este tema ya se trató en otro post de este blog (https://mysticalpotato.wordpress.com/2010/11/18/jsonp-salvando-la-limitacion-de-dominio-de-xhr-cuando-se-hace-cross-scripting-xss/). jQuery soluciona fácilmente esto añadiendo un parámetro de callback que completa automáticamente.

También habrá que parametrizar la URL del enlace. Para ello tenemos un formulario cualquiera con un input con id=”input_web”. Mejor lo vemos en código fuente:


function procesa_web() {

var url_web = $("#input_web").val()
//console.log("Valor completo:" + url_web);

$("#resultado").html("");

$.ajax({
url: 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22' + escape(url_web) + '%22%20and%0A%20%20%20%20%20%20
xpath%3D"%2F%2Fimg"%20and%20width%3E35%20and%20
height%3E35&format=json&diagnostics=true&callback=?',
async: false,
cache: false,
dataType: 'json',
success: function(data) {
imagenes_from_web = data.query.results.img; //asignamos a la variable global
var salida = "<b>Imágenes de Web</b><br />";
salida += "<a href=\"javascript:void(0);\" onclick=\"javascript:prev_image()\">Anterior</a>&nbsp;|&nbsp;";
salida += "<a href=\"javascript:void(0);\" onclick=\"javascript:next_image()\">Siguiente</a><br />";
salida += "<img id=\"img_from_web\" data-contador=\"0\" src=\"" + imagenes_from_web[0].src + "\"/>";

$('#resultado').html(salida);
}
});
}

Como se puede ver se lee el valor de la URL a procesar del input en la variable url_web y se escapa para incluirla en la URL. Adicionalmente se incluye el parámetro callback=? para salvar el cross-domain indicado anteriormente.

Los parámetros de AJAX son los utilizados en otros post: síncrono, sin caché porque son datos dinámicos y el tipo de datos JSON.

Dentro del sucess de la llamada AJAX se procesa el resultado. En primer lugar tomamos los valores obtenidos en el JSON para asignarlos a una variable global a la página que será compartida por todas las funciones.  Obviamente navegamos por el JSON para sacar sólo el listado de imágenes:

</pre>
imagenes_from_web = data.query.results.img

Posteriormente pintamos en la capa resultado la primera imagen y dos botones que permitirán navegar por las imágenes. Estos dos botones hacen referencia a dos funciones que no hacen otra cosa que ir refrescando el contenido de la imagen que se muestra en ese momento con el de la siguiente o la anterior del vector global a la página que almacena el resultado. Nótese que en el tag img dejamos el atributo data-contador para almacenar el índice del vector de imágenes. La posibilidad de incluir atributos para datos es una de las posibilidades que ofrece HTML5 (http://html5doctor.com/html5-custom-data-attributes/). Las funciones para navegar por las fotos son las siguientes:


function next_image() {

var contador = parseInt($('#img_from_web').attr("data-contador"));
contador++;
var url_imagen = imagenes_from_web[contador].src;

$('#img_from_web').attr("src", url_imagen);
$('#img_from_web').attr("data-contador", contador);
}

function prev_image() {

var contador = parseInt($('#img_from_web').attr("data-contador"));
contador--;
$('#img_from_web').attr("src", imagenes_from_web[contador].src);
$('#img_from_web').attr("data-contador", contador);
}​

El ejemplo acaba aquí, pero si queréis incluirlo al estilo Facebook para una noticia, simplemente, en el momento de que el usuario confirme el enlace, se tomará el índice del vector de imágenes y se leerá la URL para asignarla a un formulario o llamada AJAX.

El ejemplo completo y funcional podéis visitarlo en: http://jsfiddle.net/4lberto/mGxGB/12/

Anuncios

One comment

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s