24/1/2007 16:00 Augusto Ruiz

Creando un Web Crawler con .NET

Hola!

Este artículo tratará sobre dos temas: Las capacidades de red del Framework de .NET (sin entrar en WCF) y las expresiones regulares. Y para mostrar un ejemplo sencillo de cómo utilizar ambas, vamos a desarrollar un Web Crawler, que no es nada más que una aplicación que tomando como punto de partida una URL, examina la página de dicha URL buscando enlaces, y los sigue para completar un mapa de la web. Este proceso se lleva a cabo de forma recursiva, y para evitar que se quede corriendo indefinidamente le indicaremos la profundidad máxima que puede explorar.

Además, como las páginas pueden tener enlaces comunes, iremos marcando las páginas que ya se han visitado, e incluso podríamos usar un sistema de puntos o pesos para ver qué páginas son las que más enlaces reciben. Esto a una escala mayor, y con un sistema de pesos más complejo (aparte de un análisis del contenido, cosa que no haremos) es básicamente lo que realizan los robots de los buscadores para alimentar sus bases de datos.

Primero vamos a olvidarnos de cómo obtener el HTML de las páginas web (que veréis que es muy sencillo) y vamos a centrarnos en cómo procesarlo para obtener los enlaces y las rutas de los mismos. Aquí es donde entran en juego las expresiones regulares. Utilizaremos dos: Una para detectar los enlaces en el HTML (realmente vamos a buscar los href="...", que aparecen también en CSS, y otros tags), y la otra para procesar URLs.

private Regex urlRegex = new Regex(@"^(?<s1>(?<s0>[^:/\?#]+):)?(?<a1>"
                + @"//(?<a0>[^/\?#]*))?(?<p0>[^\?#]*)" 
                + @"(?<q1>\?(?<q0>[^#]*))?" 
                + @"(?<f1>#(?<f0>.*))?");
 
private Regex hrefRegex = new Regex("href\\s*=\\s*(?:(?:\\\"(?<url>[^\\\"]*)\\\")|(?<url>[^\\s]* ))");

Una vez que tenemos listas las expresiones regulares, podremos obtener todos los href presentes en la página actual. Para seguir avanzando en profundidad, simplemente debemos pedir el recurso al que apunta, y repetir el proceso. De ahí que utilicemos la recursión.

El segundo tema a tratar es cómo pedir las páginas: .NET provee de clases en el namespace System.Net que nos permiten hacer peticiones HTTP de forma sencilla. Nosotros usaremos System.Net.WebRequest, System.Net.HttpWebRequest y System.Net.HttpWebResponse

Un posible uso de estas clases es el siguiente:

HttpWebRequest req = (HttpWebRequest) WebRequest.Create(currentURL); 
HttpWebResponse resp = (HttpWebResponse) req.GetResponse();
if(resp.ContentType.ToLower().IndexOf("text/html") > -1)
{
    Stream istrm = resp.GetResponseStream();
    StreamReader rdr = new StreamReader(istrm);
    string pageHtml = rdr.ReadToEnd();
 
    ...
}
resp.Close();

Podéis ver los detalles de la implementación del crawler en el código del adjunto.

Saludos! 

Comparte este post:

# re: Creando un Web Crawler con .NET

Wednesday, January 24, 2007 4:21 PM by patanpatan

buenas... interesante la idea. Sabés si el httpwebrequest se peude usar "al revés"?

o sea... tengi una página asp q hace un post a un cgi, no puedo llamar al cgi directamente porq el cgi hace un request del form, asi q si mando parametros por get no los toma.

Hay forma de "engañar" al cgi haciendole creer q el post se lo hizo el asp pero enviarle HTML o algo parecido? (necesito no usar asp, sino llamar al cgi desde el aspx)

# re: Creando un Web Crawler con .NET

Wednesday, January 24, 2007 4:28 PM by Augusto Ruiz

Sí, podrías utilizar la propiedad Method de la clase HttpWebRequest, indicandole que es un POST, con lo que debería actuar como si se estuviese enviando un formulario.

Además de eso, tendrás que rellenar las propiedades ContentType y ContentLength, obtener el stream de la petición, y enviar los datos como un array de bytes.

Tienes un ejemplo bastante sencillo aquí:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemnethttpwebrequestclassmethodtopic.asp

# re: Creando un Web Crawler con .NET

Wednesday, January 24, 2007 5:36 PM by Tio_Luiso

A mi, en cierta ocasión se me ocurrió intentar hacer un bot para OGame, que hiciera de forma automática o programada ciertas acciones. O de forma más genérica, un bot que pudiera realizar un conjunto de acciones sobre una(s) página(s).

Obviando la dificultad de la estructura de la página, y de localizar en esta los controles que nos pueden interesar, había un tema muy curioso que tiene su dificultad aparte. La sesión. Según entiendo, mecanismos para preservar la sesión hay: Por cookie, por hidden field, y por parámetro en la querystring (parece que ogame utiliza este último). También se me ocurre que estaría el potencial problema de la autenticación.

Se me ocurren estos problemas, que también podrían existir para el crawler que comentas. Claro que podrían quedar como mejoras a implementar en la versión 2.0, ¿verdad?

# re: Creando un Web Crawler con .NET

Wednesday, January 24, 2007 6:01 PM by Augusto Ruiz

Hola Tio_Luiso

En principio la estructura de la página no es relevante para mandar un POST siempre y cuando conozcas los IDs de los controles, ya que los datos que envias son utilizando el ID del control como identificador.

En cuanto a la sesión, si sabes cual es el mecanismo, siempre puedes ver en la respuesta qué identificador de sesión se te está asignando y usarlo de forma apropiada (bien sea por cookie, por querystring, o como sea)...

# re: Creando un Web Crawler con .NET

Thursday, January 25, 2007 10:51 AM by Tio_Luiso

No, si está claro que es posible. Sólamente algo más complicado. En cualquier caso, la parte chunga pienso que sería hacer un crawler / bot genérico. Uno para una aplicación concreta sería más sencillo.

Para un crawler no sería necesario conocer nada más que los links que contiene cada página. La aplicación que yo tenía en mente, también tenía que extraer (vampirizar) contenido de la página. Por ejemplo, si en la página de mensajes tienes un mensaje que dice que el usuario xxxxxx te está atacando, y que llegarán en nosecuantos minutos, saber extraer la información pertinente para poder informar al usuario, o actuar de forma automática. Pero me estoy yendo de madre. En efecto, para un crawler no sería necesario.

Una pregunta. Y si el sitio web tiene AJAX? Cómo podrías hacer crawling?

# re: Creando un Web Crawler con .NET

Thursday, January 25, 2007 11:03 AM by Augusto Ruiz

Hola Tio_Luiso

Buena pregunta ;) Si el sitio web tiene AJAX, en principio se desencadenan las peticiones a raíz de pulsar en enlaces o botones, pero lo que hace es ejecutar javascript. Esto complica un poco las cosas, ya que probablemente tengas que ejecutar dicho javascript, y para ello, probablemente tengas que mantener una instancia de un WebBrowser con el HTML de la petición anterior, en la que "pulsarías" el link, y compararías el contenido del documento HTML antes y después de pulsar para ver las diferencias, para procesarlas.

Vamos, que no sería sencillo, pero tampoco imposible.

# re: Creando un Web Crawler con .NET

Sunday, February 04, 2007 11:06 PM by neto

Hola

A ver si me puedes ayudar.

necesito pasar datos desde una aplicacion de escritorio (en C#) a una aplicacion web en asp, necesito pasarle los datos por post.

He estado mirando las clases HTTPWEBREQUEST y HTTPWEBRESPONSE pero no tengo bien claro su uso.

me podrias decir la forma de hacer lo que deseo?

gracias

# re: Creando un Web Crawler con .NET

Tuesday, February 06, 2007 5:02 PM by Augusto Ruiz

En principio, lo único que hace falta es:

  - Crear el objeto HttpWebRequest (con el método estático Create de la clase WebRequest)

  - Establecer la propiedad Method de este objeto a "POST" (por defecto es GET)

  - Rellenar los datos del post, usando los nombres de los controles que quieres rellenar. Para eso, tienes que crear un string que contenga una ristra nombreControl=valorControl&nombreControl2=valorControl2&..., obtener los bytes de ese string usando un objeto ASCIIEncoding, y escribir esa ristra en el stream del objeto HttpWebRequest.

  - Establecer el valor de la propiedad ContentType del objeto HttpWebRequest a "application/x-www-form-urlencoded"

  - Establecer el valor de la propiedad ContentLength del objeto HttpWebRequest a la longitud del string de los datos.

Un código de ejemplo:

string datosPost="nombreControl="+valorControl;

ASCIIEncoding encoding=new ASCIIEncoding();

byte[]  bytesDatosPost=encoding.GetBytes(datosPost);

// Establecemos el ContentType

miHttpWebRequest.ContentType="application/x-www-form-urlencoded";

// Set the content length of the string being posted.

miHttpWebRequest.ContentLength=datosPost.Length;

Stream reqStream=myHttpWebRequest.GetRequestStream();

reqStream.Write(bytesDatosPost,0,bytesDatosPost.Length);

Console.WriteLine("El valor de 'ContentLength' después de escribir los datos es {0}",miHttpWebRequest.ContentLength);

// Cerramos el stream.

reqStream.Close();

Espero que te sirva! Saludos!

# re: Creando un Web Crawler con .NET

Thursday, February 22, 2007 1:25 PM by Nano

Hola, debo hacer un robot, capaz de ingresar a una pagina, ingresar el usuario y password. Luego debe seleccionar el valor para dos combobox e ingresar un valor a dos textbox mas. Despues de esto, llego a una pagina en la cual debo capturar los datos. Esto último (del combobox en adelante) lo debo hacer millones de veces. Para ser sincero no tengo idea como hacerlo, solo se que debo hacerlo en .NET :S.

Cualquier tipo de ayuda es bienvenida...

# re: Creando un Web Crawler con .NET

Friday, March 02, 2007 11:57 AM by Augusto Ruiz

Hmmmmm....

Yo lo que haría sería lo siguiente:

Examina bien cómo está hecha esa aplicación. Seguramente el formulario de login y password enviará esos datos a otra página, y o bien genera una sesión, o genera una cookie para identificarte. Por lo tanto, usando el objeto WebRequest puedes utilizar el método POST para enviar los datos a la página que aparezca en el action del formulario de esa página.

Comprueba si hay una cookie o una sesión creada, y para las pantallas siguientes utilizalas. Pero no automatices la selección de los combos y la inserción de los datos. Fíjate dónde los envía, y envíalos directamente a dicha pantalla. Para capturar los datos, supongo que tendrás que examinar el HTML que te devuelve la aplicación después de enviarle los datos, y capturarlos.

Saludos!

# re: Creando un Web Crawler con .NET

Friday, March 16, 2007 9:21 PM by wachino

Hola, estoy intendando hacer una especie de xmltv, que recoja los links de una web determinada y lo transforme en xml, podrias darme alguna idea?

# re: Creando un Web Crawler con .NET

Monday, March 19, 2007 3:57 PM by Augusto Ruiz

No sé exactamente qué es el xmltv... ?

Si quieres recoger los links de una web, eso es exactamente lo que hace el crawler del ejemplo... Y para "transformarlo en xml", eso dependerá del formato de salida del xml.

Aun así, quizá te sea más sencillo hacerte una xsl que transforme los elementos <a> de la página que estás procesando en el xml de salida que te interese para una página dada...

# re: Creando un Web Crawler con .NET

Tuesday, November 06, 2007 3:48 PM by Jou

Hola,

me gustaria utilizar este programa pero para navegar por todas las páginas de wikipedia. En wikipedia los enlaces internos no van por href sino que entre corchetes ( [[enlace]]).

Como puedo hacerlo? Como puedo hacer también que guarde un registro de el numero de paginas que ha encontrado, la pagina que tiene más enlaces, ...

Muchas gracias.

# re: Creando un Web Crawler con .NET

Tuesday, November 06, 2007 7:11 PM by Augusto Ruiz

Uf... ¿¿¿Para navegar por TODA la wikipedia???

Tal y como está el código, va a recorrer todos los enlaces que encuentre, no solo los que estén en la wikipedia. Si sabes seguro que los artículos se referencian como indicas, basta con que cambies la expresión regular que se utiliza para buscar los enlaces.

Tal cual está el código va anotando el número de veces que pasa por cada página (es decir, el número de enlaces que llegan a ella). Podrías crearte una clase que contenga todos los datos que quieres guardar de cada página, y cambiar la tabla hash que se usa en el código (es para .NET 1.1, sin generics) por un Dictionary<string, TU CLASE>.

# re: Creando un Web Crawler con .NET

Monday, November 12, 2007 5:28 AM by Antonio

Muy interesante. A ver si me podeis ayudar. Visito regularmente una página que me presenta datos en forma de tabla, pero lo hace a través de scripts de java. El caso es que con .net y htmlelement del control webbrowser he conseguido examinar la página, pero sólo veo líneas como ...writeline(...). Sin embargo en pantalla el control webbrowser si me presenta los datos en forma de tabla. ¿No hay forma de acceder a esos datos para gestionarlos desde mi aplicación?

Gracias.

# re: Creando un Web Crawler con .NET

Monday, November 12, 2007 1:58 PM by Augusto Ruiz

Hmmm...

Si lo que te está mostrando es un applet de Java, no podrás acceder al contenido. Si es HTML, debería dejarte a través del DOM de la página actual (es decir, el objeto HTMLDocument de System.Windows.Forms).

Si sabes qué estructura tiene la página web, podrías llamar al método GetElementById si el texto se incluye en un elemento que tenga un Id. Si no tiene Id, puedes probar a usar GetElementsByTagName, y de ahí ir buscando el que te convenga.

Si tuvieses un ejemplo de la página podría ayudarte más, pero así es difícil.

# re: Creando un Web Crawler con .NET

Tuesday, January 15, 2008 5:04 PM by Blas

Buenas,

Lo que estoy intentando es hacer un webCrawler que tenga como base el GoogleReader. No tengo problemas para insertar la cookie y llegar a la página principal. Sin embargo, a partir de allí, los enlaces no están en modo href sino que los obtiene a través de funciones javascript que supongo estarán alojadas en el servidor.

Cómo puedo solucionar este problema?

Gracias de antemano.

# re: Creando un Web Crawler con .NET

Friday, January 18, 2008 5:35 PM by Augusto Ruiz

Hola Blas,

Me temo que en tu caso, en el que tienes que ser capaz de interactuar con la página y con el javascript que tienes en ella, tendrás que utilizar un control WebBrowser. El HtmlRequest puede hacer peticiones HTML y obtener la respuesta del servidor (el stream de respuesta), pero no interpreta el HTML ni ejecuta javascripts.

Saludos,

# re: Creando un Web Crawler con .NET

Wednesday, April 23, 2008 5:29 PM by Carlos U

Hola como puedo aparte de que busca todos los link, me busque un tag o una funcion especifica en el cuepo del html

# re: Creando un Web Crawler con .NET

Thursday, April 24, 2008 10:23 AM by Augusto Ruiz

Carlos U:

Para que te busque un tag tienes que modificar la expresión regular hrefRegEx. Según el tag que quieras buscar tendras que usar expresiones regulares distintas, o bien hacer una expresión regular para todos los tags y decidir en función del nombre del tag qué hacer (esto sería más pesado, mucho más proceso).

También puedes crear varias expresiones regulares, unirlas con un OR y darlas nombre, de manera que para cada token encontrado puedas saber exactamente cual es si tener que examinarlo (a partir del nombre que le has asignado).

# re: Creando un Web Crawler con .NET

Thursday, August 07, 2008 11:12 PM by necesito hacer un crawler en c++

como puedo hacerlo en c++, que estructuras usarian?