Web Crawler usando Agentes y AjSharp

Published on Author lopezLeave a comment

El pasado año, escribí un ejemplo de web crawler usando mensajes, detalles en los posts:

Distributed Web Crawler using AjMessages
Web Crawler distribuido usando AjMessages

Antes, escribí otros ejemplos usando DSS/CCR, tecnologías incluidas en Microsoft Robotics Developer Studio:

Distributed Agents using DSS/VPL
Web Crawler example using DSS (Decentralized Software Services)
Aplicaciones Distribuidas con AjMessages usando DSS/CCR
Ejemplo de Web Crawler usando DSS

Ahora, escribí un ejemplo local (no distribuido) usando agentes en AjSharp. Recordemos, cada agente se ejecuta en su propio thread, y sus invocaciones son encoladas, y ejecutadas de una en una. Más sobre agentes en AjSharp en:

Agents in AjSharp (Part 1)
Agentes en AjSharp (Parte 1)
Agents in AjSharp (Part 2)
Agentes en AjSharp (Parte 2)

Hace dos días, tomé el código de mis anteriores ejemplos, y lo reensamblé en agentes de AjSharp. Este es el primer resultado de ese experimiento. Primero, definí un objeto para armara una red de agentes que se ocupen de visitar un sitio, y lanzar el proceso:

// Build and launch agents
object WebCrawler
{
  sub Process(url, fn)
  {
    uri = new System.Uri(url);
    downloader = new Downloader();
    harvester = new Harvester();
    resolver = new Resolver(uri,5);
    processor = new Processor(fn);
    
    downloader.Harvester = harvester;
    downloader.Processor = processor;
    harvester.Resolver = resolver;
    resolver.Downloader = downloader;
    
    downloader.Process(uri, 0);
  }
}

El Downloader toma una URI, baja su contenido y envía el resultado a dos agentes asociados: Processor y Harvester. El parámetro Depth indica la profundidad de esta página en el proceso de crawling del sitio:

// Downloads a page
agent Downloader 
{
  sub Process(uri,depth)
  {
    client = new System.Net.WebClient();
    content = client.DownloadString(uri);
    PrintLine("Downloaded: " + uri);
    this.Harvester.Process(uri,depth,content);
    this.Processor.Process(uri, content);
  }
}

The Processor executes a user function/routine, receiving the URI and its retrieved content:

// Process the content retrieved
agent Processor
{
  function Processor(fn)
  {
    this.fn = fn; // function to invoke
  }
  
  sub Process(uri, content)
  {
    // Add your logic
    this.fn(uri, content);
  }
}

El Harvester detecta otros enlaces en el contenido, y los envía, uno a uno, a otro agente, el Resolver:

// Get links from page
agent Harvester
{
  sub Process(uri,depth,content)
  {
    matches = System.Text.RegularExpressions.Regex.Matches(content, "href=\\s*\"([^&\"]*)\"");
    results = new List();
    
    foreach (match in matches) {
      value = match.Groups[1].Value;
      
      if (!results.Contains(value))
        results.Add(value);
    }
    
    foreach (result in results) 
      if (result.StartsWith("http"))
        this.Resolver.Process(new System.Uri(result), depth+1);
  }
}

El Resolver mantiene una lista de URIs procesados, y filtra aquellas que no se encuentran en el host original. El proceso se limita entonces hasta una cierta profundidad de exploración y dentro del sitio original:

// Filter invalid or already processed links
agent Resolver
{
  var processed = new List();  
  
  function Resolver(uri,maxdepth)
  {
    this.host = uri.Host;
    this.maxdepth = maxdepth;
  }
  
  sub Process(uri,depth) 
  {
    if (depth > this.maxdepth)
      return;
      
    if (uri.Host != this.host)
      return;
    
    if (uri.Scheme != System.Uri.UriSchemeHttp && uri.Scheme != System.Uri.UriSchemeHttps)
      return;
      
    if (processed.Contains(uri))
      return;
      
    processed.Add(uri);
      
    PrintLine("New Link: " + uri);
    this.Downloader.Process(uri,depth);     
  }
}

Estos son ejemplos de uso, creando dos redes de agentes, dedicados a obtener el contenido de dos sitios:

// Example
WebCrawler.Process("http://ajlopez.wordpress.com", function(uri,content) { PrintLine("From ajlopez.wordpress "+uri);});
WebCrawler.Process("http://ajlopez.zoomblog.com", function(uri,content) { PrintLine("From ajlopez.zoomblog "+uri);});

Pueden bajar el AjSharp desde el trunk:

http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage

El código de web crawler está en Examples/WebCrawler.ajs dentro del proyecto AjSharp.Console. Despues de compilar a este programa de consola, pueden lanzar:

AjSharp.Console Examples/WebCrawler.ajs

Esta es una salida parcial:

Pueden ver el ejemplo completo en Pastie http://pastie.org/835926

Próximo paso: usar agentes distribuidos. Hay dos caminos a explorar: uno, declarar que algunos agentes sean distribuidos usando código adicional o configuración, pero sin cambiar el código original. Dos, hacer la distribución explícita en el código.

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Leave a Reply

Your email address will not be published. Required fields are marked *