domingo, 1 de febrero de 2015

[Parte 5] Web Scraping

Web scraping en paginas autenticadas

Sitios autenticados

Aunque la mayoria de los sitios webs no estan asegurados y puedan ser accedidos a traves de cURL, muchas de las mas importantes aseguran con diferentes maneras la autenticacion. Una de las maneras mas comunes para asegurar una pagina es utilizando autenticacion basica HTTP. Para acceder al contenido tenemos que autenticarnos por lo cual necesitamos utilizar la extension cURL de PHP. Pero antes de ello diremos unas pocas palabras acerca de la autenticacion basica HTTP.

Autenticacion basica HTTP

Autenticacion basica HTTP es una de las maneras mas faciles y mas rapidas para asegurar paginas web, ya que no requiere cookies, manejo de sesiones, o la creacion de paginas de inicio de sesion. En su lugar, la autenticacion basica HTTP utiliza encabezados HTTP estaticos, lo que significa que no hay handshakes (apretones de manos) necesarios entre clientes y servidores. Cada vez que se entre a la pagina el navegador solicitara una autenticacion basica HTTP. Los encabezados de la misma se muestran a continuacion.

HTTP/1.1 401 Access Denied
WWW-Authenticate: Basic realm="Mi Servidor"
Content-Length: 0


Esta solicitud debera ser enviada mediante HTTP 401 Not Authorized el codigo de respuesta contiene un encabezado WWW-Authenticate HTTP. La mayoria de los navegadores mostrara un cuadro de dialogo de inicio de sesion cuando recibe esta respuesta, lo que permite al usuario introducir un nombre de usuario y contraseña. Un ejemplo se muestra a continuacion. Cuando el user agent como navegador quiere enviar las credenciales de autenticacion al servidor, puede utilizar el encabezado de autorizacion. La cabecera de autorizacion se construye como sigue:

* Nombre de usuario y la contrase se combinan en una cadena "usuario:contraseña".
* La cadena resultante literal se codifica usando base64.
* El metodo authorization y un espacio es decir "Basic" se pone a continuacion, antes de la cadena codificada.

Por ejemplo, si el navegador utiliza "Patrick" como nombre de usuario y "thementalist" como contraseña y quiere acceder a algunos archivos de forma segura en el servidor ejemplo.com/archivosseguros/, las cabeceras enviadas por el navegador seran como el siguiente.

GET /archivosseguros/ HTTP/1.1
Host: www.ejemplo.com
Authorization: Basic UGF0cmljazp0aGVtZW50YWxpc3Q=


En PHP podemos codificar nombre de usuario y contraseña de cadena a base 64 utilizando el siguiente.

echo base64_encode('Patrick:thementalist');

Autentificacion basica HTTP con cURL

Ahora que estamos familiarizados con la autentificacion basica vamos a ver como podemos enviar la informacion de autentificacion utilizando cURL. El siguiente ejemplo nos permite acceder a un sitio con autenticacion basica HTTP utilizando cURL. Esto utiliza la opcion CURL_USERPWD para pasar el nombre de usuario y la contraseña para el servidor remoto para la autenticacion. Tenga en cuenta que cURL maneja todos los problemas de codificacion en base64 por nosotros. Solo tenemos que especificar las opciones adecuadas para cURL y se encarga del resto por nosotros. Las principales opciones en este ejemplo son CURLOPT_HTTPAUTH, CURLAUTH_BASIC.

<?php
$user = "admin";
$pass = "adminautenticacion";
$s = curl_init();
curl_setopt($s, CURLOPT_URL, 'http://ejemplo.com/index.php');
curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
curl_setopt($s, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($s, CURLOPT_USERPWD, "$user:$pass");
curl_setopt($s, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
$salida= curl_exec($s);
curl_close($s);
echo $salida;
?>


Incluso el tipo favorito de autenticacion, la autenticacion basica sin embargo esta perdiendo terreno a otras tecnicas debido a su debil naturaleza. Por ejemplo, con la autenticacion basica, no hay manera de cerrar sesion sin cerrar su navegador. Tampoco hay manera de cambiar el aspecto de la forma de autenticacion debido a que el navegador lo crea y el usuario no tiene control sobre eso. Es importante destacar que la autenticacion basica no es muy segura, ya que el navegador envia las credenciales de acceso al servidor en texto sin cifrar.

Almacenamiento y envio de cookies

La mayoria de los servidores despues de la autenticacion devuelven algo de informacion de la cookie que se requiere para trabajar correctamente con el resto del sitio una vez estamos con exito mas alla de la autenticacion. Necesitamos almacenar estos datos de las cookies en algun lugar para que podamos utilizarlo mas tarde con otras paginas. cURL hace que este trabajo sea mas facil para nosotros con la opcion CURLOPT_COOKIEJAR. Esta opcion tiene un nombre de archivo en el que la informacion de las cookies del sitio se almacenan; la hemos llamado "cookie.txt" en nuestro ejemplo a continuacion. A continuacion, podemos utilizar los datos de las cookies tarde como se requiere para trabajar con otras paginas.

<?php
$username = "admin";
$password = "adminautenticacion";
$s = curl_init();
curl_setopt($s, CURLOPT_URL, 'http://ejemplo.com/');
curl_setopt($s, CURLOPT_HEADER, 1);
curl_setopt($s, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($s, CURLOPT_USERPWD, "$username:$password");
curl_setopt($s, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt($s, CURLOPT_TIMEOUT, 30);
curl_setopt($s, CURLOPT_RETURNTRANSFER, TRUE);
$page_data = curl_exec($s);
echo $page_data;
?>


Mas tarde, cuando queramos acceder a una pagina que require las cookies creadas anteriormente durante la autenticacion, podemos utilizar la opcion de curl CURLOPT_COOKIEFILE para cargar los datos de las cookies, que luego se envian al servidor cuando se solicita una pagina. A continuacion se da un ejemplo de codigo.

$s = curl_init();
curl_setopt($s, CURLOPT_URL, 'http://ejemplo.com/pagina2.php');
curl_setopt($s, CURLOPT_COOKIEFILE, 'cookie.txt');
curl_setopt($s, CURLOPT_TIMEOUT, 30);
curl_setopt($s, CURLOPT_RETURNTRANSFER, TRUE);
$page_data = curl_exec($s);


Ademas de la autenticacion HTTP basica, tambien existe la autenticacion estandar usuario/contraseña en un formulario, utilizado en la mayoria de los sitios. Los datos de autenticacion son normalmente enviados por metodo HTTP POST. En el siguiente ejemplo veremos como usar cURL para trabajar con este tipo de autenticaciones.

Autenticacion de sesion

A diferencia de la autenticacion basica, en las credenciales de acceso se envian cada vez que se solicita una pagina, la autenticacion de sesion valida a los usuarios una vez y crea un valor de sesion que representa la autenticacion. El formulario de inicio de sesion estandar usuario/contraseña utilizan autenticacion de sesion. Una vez que el usuario se autentica correctamente una sesion se crea con la ayuda de las cookies y los valores de sesion se pasan a cada peticion de la pagina posterior para indicar que el usuario es autenticado. Hay dos metodos basicos para el empleo de sesion de autenticacion con cookies y con cadenas de consulta. En el siguiente ejemplo vamos a ver como podemos usar cURL para iniciar sesion en un sitio de administracion de WordPress utilizando autenticacion de sesion.

Ingresando a un sitio de administracion WordPress con cURL

Actualmente WordPress es uno de los CMS mas instalados en el mundo, y hay millones de sitios que ejecutan esta plataforma versatil. El siguiente ejemplo muestra como se puede acceder a una seccion de administracion de WordPress remota utilizando cURL y agarrar cualquier contenido de interes. Por ejemplo si desea comprobar automaticamente los intervalos regulares del numero de comentarios publicados en su blog, puede utilizar el siguiente codigo para lograrlo. El siguiente ejemplo utiliza cURL para enviar los datos de acceso a su pagina de administracion de WordPress. Esto se logra mediante la opcion CURLOPT_POSTFIELDS junto con algunas otras opciones requeridas. Despues del inicio de sesion correcto WordPress devuelve un conjunto de cookies que se quedaran almacenadas en un archivo local utilizando CURLOPT_COOKIEJAR. Estos datos de cookies seran utilizados despues por nuestro codigo que solicito otras paginas de administracion.

<?php
$blog_url = "http://www.wordpress-blog.com/";
$blog_name = "wordpress-blog.com";
$username = "admin";
$password = "your-admin-password";
$post_data = "log={$username}&pwd={$password}&wp-submit=Acceder&redirect_to=http%3A%2F%2F{$blog_name}%2Fwp-admin%2F&testcookie=1";
$s = curl_init();
curl_setopt($s, CURLOPT_URL, $blog_url . 'wp-login.php');
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);
?>


Una vez correctamente en la cuenta para admin, entonces podemos conseguir cualquier pagina de administracion requerida y raspar el contenido. Esto, sin embargo, sera necesario que establezcan las opciones correctas con cURL. El siguiente es otro ejemplo que se permitira el acceso a la administracion de WordPress y permitira obtener el contenido de la pagina para el enlace 'Todas las entradas'.

Un cambio importante a señalar aqui es la opcion CURLOPT_COOKIEFILE. Esto le permite continuar con la sesion cURL iniciada despues de inicio de sesion. cURL utiliza datos de la cookie de este archivo al mismo tiempo que solicita la nueva pagina.

/* Ahora que nosotros tenemos iniciada la sesion correctamente, podemos pedir la nueva pagina */
curl_setopt($s, CURLOPT_URL, $blog_url . 'wp-admin/edit.php');
curl_setopt($s, CURLOPT_COOKIEFILE, "cookie.txt");
$html = curl_exec($s);
/* $html ahora contiene los datos de la pagina ‘edit.php’ */
echo $html;


Una vez que tenemos el contenido de la pagina, podemos utilizar simplehtmldom para encontrar el elemento DOM relevante y devolver el numero total de comentarios. El recuento de los comentarios pendientes se almacena en el siguiente elemento span en el DOM. Tenga en cuenta que esto podria variar dependiendo de la version de WordPress, asi que asegurese de que esta comprobando el elemento de DOM correcto.

<span class="pending-count">6</span>

Ahora usamos el metodo "find" para obtener el recuento de comentario. Esto se logra mediante la siguiente linea. Devolvemos el primer nodo que se ajuste a los parametros de busqueda. Esto se especifica mediante el segundo parametro para 'find', '0' en nuestro ejemplo.

$data = @$html->find('span[class=pending-count]', 0);

Tambien podemos especificar el parametro de busqueda como a continuacion.

$data = $html->find('span.pending-count', 0);

Una vez encontrado el elemento relevante devolvemos los datos adecuados del objeto.

echo @$data->plaintext;

En el ejemplo anterior usted puede preguntarse como hemos llegado hasta los datos para la variable $post_data. La mejor manera es abrir el panel Firebug y enviar el formulario de WordPress. Ahora va conseguir todo el contenido solicitado en el panel de Firebug en la pestaña de red. Las urls mostradas en el panel seran tipicas de la administracion de WordPress despues del envio de formulario de inicio de sesion que se mostrara a continuacion. Se puede ver facilmente que los datos del formulario de inicio de sesion se han enviado en el archivo 'wp-login.php' utilizando el metodo POST. Tambien puede ver los detalles de POST y otras cabeceras haciendo clic en el enlace 'wp-login.php'. Una muestra parcial de lo capturado usando Firebug se mostrara a continuacion. El contenido de POST se muestra despues del campo 'Content-Length'. Solo tienes que copiar eso y reemplazar el nombre de usuario/contraseña correcta.

POST /wp-login.php HTTP/1.1
Host: www.ejemplo.com
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:16.0) Gecko/20100101 Firefox/16.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.ejemplo.com/wp-login.php
Cookie: __utma=101293715.944295703.1353556559; Content-Type: application/x-www\
-form-urlencoded
Content-Length: 102
log=admin&pwd=test&wp-submit=Acceder&redirect_to=http%3A%2F%ejemplo.com%2Fwp-ad\
min%2F&testcookie=1
HTTP/1.1 200 OK
Date: Fri, 08 Mar 2013 04:32:18 GMT
Server: Apache
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
x-frame-options: SAMEORIGIN
Set-Cookie: wordpress_test_cookie=WP+Cookie+check; path=/
Last-Modified: Fri, 08 Mar 2013 04:32:19 GMT
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8


Con estos dos tipos de autenticacion debe ser capaz de obtener acceso a la mayoria de los sitios web. La otra arquitectura de autenticacion que necesitamos explorar es utilizar ajax para validar. Esto lo veremos mas adelante.


No hay comentarios:

Publicar un comentario en la entrada