jueves, 1 de julio de 2010

Crawler 403 Forbidden


En uno de los proyectos en los que estamos trabajando tenemos que incorporar un navegador Web desarrollado con tecnología Java que permita efectuar peticiones HTTP y devolver la respuesta al usuario junto con alguna que otra información relacionada con frecuencias de items y similares.


Para desarrollarlo, el primer paso es el de desarrollar un agente que efectúe peticiones HTTP y devuelva una cadena con el HTML retornado por el servidor, para que los siguientes agentes efectúen su trabajo antes de la previsualización.


En resumen, el código a utilizar es el mismo que el de un crawler (robot) pero sin necesidad de ir más allá del nivel inicial.


Haciendo pruebas para ver que todo funciona correctamente, nos encontramos de lleno con un 403 Forbidden cuando el usuario decide navegar a Google y efectuar una búsqueda.


Investigando un poco nos encontramos con la siguiente línea en el contrato de licencia de Google: "5.3 Ud. se compromete a no acceder (o tratar de acceder) a los Servicios por ningún otro medio distinto de la interfaz facilitada por Google, salvo que Ud. haya sido autorizado a ello específicamente en virtud de un contrato suscrito por separado con Google."


Lo que nos da al olfato con un posible problema, Google está detectando de algún modo que quien realiza la petición es un agente programado y no un navegador Web, sobre todo porque el mismo código escrito en .Net no revierte ningún problema.


¿Pero qué significa la frase de la licencia "por ningún otro medio distinto de la interfaz facilitada por Google"? Entendemos que se refiere al acceso directo a sus bases de datos, porque si se refiere a la interfaz Web que facilitan y que vemos en un navegador, no es más que la representación que ese navegador quiera hacer en la capa de aplicación de lo que realmente se cuece en la capa de transporte del protocolo HTTP/IP, que por cierto (y gracias!) ni es de Google, ni es de Microsoft, ni es de Apple, entre otros...


Pues bien, bajando a ese nivel existe una aplicación muy interesante denominada Fiddler, similar a Wireshark que cualquier administrador de red ha utilizado seguro en Linux, pero limitando el análisis al tráfico HTTP. Veámos qué análisis hace para la petición de .Net y para la de Java:


En ambos casos la petición enviada es:

GET /search?hl=es&source=hp&q=fiddler&aq=f&aqi=&aql=&oq=&gs_rfai= HTTP/1.1


Y en el caso de .Net envía además la siguiente información de transporte:


Connection: Keep-Alive
Host: www.google.com

Y no envía ninguna información adicional de identificación de cliente, ni ninguna otra, recibiendo como respuesta:

HTTP/1.1 200 OK


En cambio, en el caso de Java se envía la siguiente información de transporte:


Connection: Keep-Alive
Host: www.google.com

Y además la siguiente información acerca del cliente que efectúa la solicitud:

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: Java/1.6.0_06

Recibiendo como respuesta:

HTTP/1.1 403 Forbidden


Por su parte, un navegador como Chrome, ante la misma URL, envía la misma petición GET HTTP, y le pasa la siguiente información de transporte:


Connection: keep-alive
Host: www.google.es

Y por su parte, la siguiente información de identificación del cliente:

Accept: application/xml,application/xhtml+xml,text/html;
q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

Accept-Encoding: gzip,deflate,sdch

Accept-Language: es-ES,es;q=0.8

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US)
AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86
Safari/533.4

Además de otra información relativa a cookies y cache que no influyen en la aceptación/denegación de respuesta del servidor, y recibiendo por tanto como respuesta:

HTTP/1.1 200 OK


Para asegurarnos, probamos también con otro navegador, con IE7, comprobando que envía, además de los datos de transporte de igual modo que los anteriores, la siguiente identificación de cliente:


User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1;
InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727;
.NET CLR 3.0.04506.648; .NET CLR 3.5.21022; MS-RTC LM 8)

Recibiendo la respuesta correcta:

HTTP/1.1 200 OK


El tema pues está bastante claro, la identificación como cliente Java a Google no le gusta. Seguramente cuando se den cuenta la identificación nula tampoco le gustará, aunque es algo optativo en el protocolo HTTP, es una manera de blindarse ante otro tipo de crawlers como pueda ser uno escrito en Perl (seamos conscientes, casi nadie que se dedica a esto utiliza .Net, curiosamente porque es bastante potente, pero eso es otro tema).


¿Y cómo lo solucionamos? Pues muy fácil, diciéndole a Google que nuestro agente no es Java sino cualquier navegador aceptado por el mismo, por ejemplo nuestro propio navegador "Corex Navigator v1.6".


¿Y cómo se le dice eso al crawler? Pues eso el que lo quiera saber que contacte conmigo que gustosamente se lo diré, que aquí mucho leer pero nadie escribe nada :-)


Y disfrutad con los problemas, son los que nos hacen crecer!!