domingo, 1 de febrero de 2015

[Parte 7] Web Scraping

Scraping contenido Ajax

Javascript y el nacimiento de Ajax

Hace algunos años la mayoria del contenido de una pagina web, si se generaba dinamicamente o estaticamente en el servidor y luego era mostrado al cliente. Sin embargo, con la introduccion de ajax el contenido ahora podria ser llamado dinamicamente despues de que una pagina web ya habia sido cargada. Esto proporciono un nuevo reto para el web scraping. 
Con auge de javascript muchos sitios webs ahora utilizan ajax para recuperar el contenido fresco de una pagina web. Sin embargo, esto puede ser problematico para nuestros esfuerzos de web scraping, ya que el contenido recuperado por javascript no se puede analizar facilmente por PHP cuando se inserta de forma dinamica en el DOM por el navegador. Solo usando cURL para obtener los contenidos de la pagina devolvera los datos sin contenido ajax. Entonces, ¿Que hacemos para obtener el contenido dinamico generado por javascript?
Una solucion es utilizar una herramienta de navegador como Selenium. Sin embargo, Selenium es una herramienta de prueba y no puede ser facilmente integrado con PHP para recuperar el contenido dinamico. La otra solucion es utilizar 'phantom.js',  un programa de escritorio que les permite descargar paginas web y manipular el DOM usando javascript, lo que le permite recuperar el contenido ajax. phantomjs en realidad es un navegador sin la ventana normal, algo que se llama como un navegador sin cabeza. phantomjs utiliza javascript como lenguaje de scripting para procesar paginas descargadas. Vamos a mirar un poco phantomjs en este apartado, sin embargo nuestro objetivo principal es usar PHP para realizar web scraping. 
Cada solicitud de pagina ajax implica una llamada a una direccion URL del servidor que devuelve de nuevo algunos datos al navegador. Estos datos son utilizados por el navegador para actualizar el contenido relevante en la pagina. La parte importante para saber realizar web scraping en el contenido es encontrar la peticion URL. Entonces, ¿Como podemos llegar a la solicitud correcta de la URL de ajax?

Firebug al rescate

Aqui es donde el complemento firebug sera muy util. En el panel de 'red' de la ventana de firebug puedes ver todas las peticiones GET/POST realizadas por la pagina web. Una muestra la pantalla de diversas solicitudes de Javascript se muestra a continuacion.



Como puede ver hay muchas peticiones GET asi como POST. Es su tarea localizar el URL correcto que se utiliza para recuperar el contenido ajax que le interesa. Por ejemplo, una peticion GET puede tomar la forma de la siguiente URL, donde el parametro de pagina variara con cada solicitud. La url de abajo podra ser para recuperar una lista de libros para la categoria "ciencia". Puede haber un total de 600 libros, por 20 libros que se muestren por peticion, lo que eleva el numero de paginas a 30 paginas.

http://algun-sitio.com/respuesta/obtener-lista-libros.php?pagina=6&cat=10

Por supuesto, esta URL puede ser un poco mas compleja de lo que se muestra aqui. Para para ejemplos bien vamos con el de arriba. Una vez que conocemos la URL correcta, entonces podemos usarla en nuestra solicitud cURL para llegar al contenido real. En el ejemplo que figura a continuacion tenemos que conseguir todo el contenido de ajax para las paginas 0-20. Con cada iteracion del bucle 'for' modificamos el parametro pagina y enviamos una nueva solicitud. No hemos añadido ninguna gestion de errores, pero usted debe comprobar si la solicitud devolvio cualquier dato valido o esta vacio.

<?php
$ch = curl_init();
for($i=0; $<=20; $i++)
{
$url = "http://algun-sitio.com/respuesta/obtener-lista-libros.php?pagina={$i}&limit=10";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, 6);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$page_data = curl_exec($ch);
/* Hacemos algo con los datos */
}
?>


Para el contenido ajax con muchas paginas, como en el ejemplo anterior, por lo general prefieren almacenar en el cache el contenido recuperado en un archivo local, que hace mas facil la parte de raspar como comprobar repetidamente el codigo diferente en las paginas webs almacenadas en el cache. En pocas palabras, es la forma de recuperar el contenido de las paginas con peticiones ajax.
Algunas solicitudes de javascript aunque pueden usar POST en lugar de GET. Sin embargo, esto no cambia nada. Usted puede obtener los detalles adicionales de la solicitud POST del Firebug como antes. En el codigo que se muestra a continuacion podemos ver que javascript ha publicado a la url 'login.php' con dos parametros username y password. A veces esta solicitud podria ser mas compleja, con docenas de parametros. Sin embargo, la logica sigue siendo la misma. La respuesta enviada por el servidor por la solicitud esta disponible en la pestaña de "Respuesta". La respuesta puede ser enviada en HTML, texto plano, JSON o formato XML. La tarea de decodificar la respuesta en algunos formatos adecuados cae en el web scraper. El siguiente ejemplo muestra como utilizar cURL para enviar esta URL junto a sus dos parametros.

<?php
$url = "http://ejemplo/login.php?login=1";
$username = "arthusu";
$password = "tu-password";
$post_data = "username={$username}&password={$password};
$s = curl_init();
curl_setopt($s, CURLOPT_URL, $url);
curl_setopt($s, CURLOPT_TIMEOUT, 30);
curl_setopt($s, CURLOPT_POST, true);
curl_setopt($s, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($s, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($s, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($s, CURLOPT_COOKIEJAR, "cookie.txt");
curl_setopt($s, CURLOPT_RETURNTRANSFER, TRUE);
$downloaded_page = curl_exec($s);
?>


Por supuesto Firebug no es la unica herramienta para observar el trafico de red. Google Chrome y Safari tienen excelentes herramientas de desarrollo integradas en el navegador para que usted se sienta comodo. La decodificacion de llamadas ajax y extraer las direcciones URL correctas es una habilidad que va adquirir con el tiempo. Es un arte, y requiere un poco de paciencia y ensayo y error para hacer las cosas bien, pero vale la pena el esfuerzo.

PhantomJS

Como se ha descrito anteriormente en este capitulo, PhantomJS es un Webkit scriptable sin cabeza con API de javascript. Tiene soporte rapido y de origen por varios estandares web: manipulacion DOM, selectores CSS, JSON, Canvas y SVG. Puede utilizar PhantomJS para capturar mediante programacion contenidos web, incluyendo SVG y Canvas, crear capturas de pantallas del sitio web, acceder y manipular paginas web con la API DOM estandar, o utilizarlo con las liberias junto a jQuery. Debido a que PhantomJS puede cargar y manipular una pagina web, es perfecto para llevar a cabo diversas automatizaciones de la pagina incluyendo web scraping, nuestro objetivo primordial. Puede descargar PhantomJS desde el siguiente enlace: http://phantomjs.org/download.html. PhantomJS se corre desde la linea de comandos, asi que asegurese que la aplicacion se encuentre disponible con el PATH. Para probar si la aplicacion esta funcionando correctamente copie las siguientes lineas en un archivo de texto en blanco y guardelo como 'Prueba.js'.

console.log('Hola, Mundo!');
phantom.exit(); 


Ahora puede ejecutar estos comandos haciendo pasar el archivo PhantomJs.

c:\>phantomjs prueba.js

Esto imprimira la cadena Hola, Mundo! en la ventana de la consola. A continuacion se muestra un ejemplo sencillo para descargar una pagina web e imprimir el contenido en la consola.

var page = require('webpage').create();
page.open('http://phantomjs.org', function(status) {
if ( status === "success" ) {
console.log(page.content);
}
phantom.exit();
});


PhantomJS es relativamente un buen tema con un gran numero de funciones y metodos que no podemos cubrir en este apartado. Este sitio web tiene una documentacion decente que se puede utilizar para codear. Tenga en cuenta que PhantomJS supone que tiene muy buen conocimiento de javascript.
 
 

No hay comentarios:

Publicar un comentario