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