C#MailCrawler
[Batidora de correos-e]

Fecha: 21/Jun/2004 (20/Jun/2004)
Revisado: 07/Mar/2006
(link a uno de los ZIP)
Autor: Unai Zorrilla Castro Escríbeme

 


C#MailCrawler es una 'batidora' de correos electrónicos. Muchos de nosotros colocamos nuestras direcciones de correo en foros, listas etc... un ejemplo de ello es este artículo en el cual pongo un enlace a mi mail para el envío de dudas o sugerencias. Pues bien con unos pequeños patrones es posible recuperar direcciones de correo ayudándose de las Expresiones regulares ( System.Text.RegularExpressions ). La clase MatchCollection nos proporciona un conjunto de coincidencias para un patrón determinado, con lo cual nos bastaría con obtener el texto de una Uri para buscar en ella las coincidencias.

System.Net a través de WebRequest nos permite obtener el contenido de una Uri para así buscar en ella. Para probar todas estas funcionalidades he creado una aplicación sencilla ( Ver figura 1 ) en la que se puede ver las direcciones uri en las cuales se busca un determinado patrón y las coincidencias de este.


( Figura 1 )

Tras unos pocos segundos vemos la cantidad de link's encontrados a partir de una uri inicial ( http://www.elguille.info ) y las coincidencias con el patrón de correos electrónicos. En principio parece que la única utilidad de una aplicación como esta es la búsqueda de correos para hacer 'Span', bueno pues esto no es así, la búsqueda de patrones es un tema interesante ( muy interesante diría yo ) el cual os podría ayudar mucho.


Aplicación de Ejemplo: - 10.2 KB
Codigo del Crawler: - 2.17 KB (07/Mar/06 revisado el nombre del fichero, que estaba mal)


El código:

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Net;
using Crawler.Exceptions;
using System.Text.RegularExpressions;
using System.IO;

/*
 * C#MailCrawler ,escrito por Unai Zorrilla Castro
 * Junio del 2004
 */
namespace Crawler
{
    public class Crawler
    {
        #region ATRIBUTOS

        private string _uribegin;
        /// 
        /// Obtiene  el link inicial para el 'batido web'
        /// 
        public string LinkBegin
        {
            get { return this._uribegin;}
        }

        #endregion

        #region EVENTOS Y DELEGADOS

        public delegate void HandlerNewUri(string NewUri);
        public event HandlerNewUri OnNewUri;
        public delegate void HandlerNewMail(string NewMail,string SourceUri);
        public event HandlerNewMail OnNewMail;
        public delegate void HandlerCrawler();
        public event HandlerCrawler OnSearch;
        public event HandlerCrawler OnStop;
        public delegate void HandlerCrawlerFin(int CountMail,int Uri);
        public event HandlerCrawlerFin OnFin;

        #endregion

        #region CONSTANTES

        const string PAGEHTML = "text/html";

        #endregion

        private int _countMail = 0;
        private int _countUri = 0;
        private bool stop = false;
        Queue uriqueue;
        Hashtable hashlinks;
        Hashtable hashmail;
        public Crawler(string Link,bool NoProxy)
        {
            if(NoProxy)
                GlobalProxySelection.Select = new WebProxy();
            else
                GlobalProxySelection.Select = WebProxy.GetDefaultProxy();
            this._uribegin = Link;
            uriqueue = new Queue();
            hashlinks = new Hashtable();
            hashmail = new Hashtable();
        }

        #region METODOS PUBLICOS


        public void Start()
        {
            try
            {
                OnSearch();
                if(!IsHtmlPage(LinkBegin))
                    throw new ApplicationException("El Link inicial no es una pagina html.\n Revise sus datos",null);
                uriqueue.Enqueue(LinkBegin);
                while((uriqueue.Count>0) && (!this.stop))
                {
                    object link =  uriqueue.Dequeue();
                    string pageData;
                    if(IsHtmlPage((string)link))
                    {
                        GetPageData((string)link,out pageData);
                        GetPageLinks((string)link,
                            pageData,
                            "a",
                            "href"
                            );
                        // <frame src=
                        GetPageLinks((string)link,
                            pageData,
                            "frame",
                            "src"
                            );
                        // <area href=
                        GetPageLinks((string)link,
                            pageData,
                            "area",
                            "href"
                            );
                        // <link href=
                        GetPageLinks((string)link,
                            pageData,
                            "link",
                            "href"
                            );
                        //Para este link buscamos todos los correos
                        GetEmailLinks(pageData,(string)link);
                    }
                }
                OnFin(_countMail,_countUri);
            }
            catch(CrawlerException)
            {
                throw new ApplicationException("Por favor asegurese que está conectado a internet.",null);
            }
        }
        public void Stop()
        {
            this.stop = true;
            OnStop();
        }


        #endregion

        #region METODOS PRIVADOS


        private bool IsHtmlPage(string Link)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(Link));
                request.Method = "HEAD";
                HttpWebResponse resp = (HttpWebResponse)request.GetResponse();
                WebHeaderCollection header = resp.Headers;
                string ContenType = header["Content-Type"];
                if(ContenType != null)
                    return true;
                else
                    return false;
                
            }
            catch(UriFormatException)
            {
                return false;
            }
            catch(Exception)
            {
                return false;
            }
        }
        private void GetEmailLinks(string pageBody,string Link)
        {


            /*
             *  Pattern para el correo electrónico
             */ 
            string tagPattern = @"[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}.";
            Regex reg = new Regex(tagPattern,RegexOptions.CultureInvariant);
            MatchCollection tagMatches = reg.Matches(pageBody);
            string mail = string.Empty;
            for(int i = 0 ; i< tagMatches.Count ; i++ )
            {
                mail = tagMatches[i].Value.ToString().Trim();
                mail = mail.Substring(0,mail.Length -1);
                if(!hashmail.ContainsKey(mail))
                {
                    hashmail.Add(mail,"mail");
                    OnNewMail(mail,Link);
                    _countMail++;
                }
            }
        }
        private void GetPageLinks(string pageUri,string pageBody,string tag,string attribute)
        {
            string tagPattern = string.Format("< *{0} +[^<>]*>", tag);
            string attributePattern = string.Format("{0} *= *([^ >])*", attribute);
            
            pageBody = Regex.Replace(pageBody, "(\\n|\\r|\\t)"," ");
            MatchCollection tagMatches = Regex.Matches(pageBody, tagPattern, RegexOptions.IgnoreCase);
            foreach(Match m in tagMatches)
            {
                if(m.Groups[0].Success)
                {
                    //Ahora buscamos el atributo
                    string tagData = m.Groups[0].Captures[0].ToString();
                    Match attributeMatch = Regex.Match(tagData, 
                        attributePattern, 
                        RegexOptions.IgnoreCase);
                    if(attributeMatch.Groups[0].Success)
                    {
                        string linkString = attributeMatch.Groups[0].Captures[0].ToString();
                        linkString = Regex.Replace(linkString, "[ \"']","");
                        linkString = linkString.Substring(attribute.Length+1);
                        try
                        {
                            linkString = new Uri(linkString).AbsoluteUri; 
                            if(!hashlinks.ContainsKey(linkString.Trim()))
                            {
                                hashlinks.Add(linkString.Trim(),"uri");
                                uriqueue.Enqueue((object)linkString);
                                OnNewUri(linkString);
                                _countUri++;
                            }
                        }
                        catch(UriFormatException)
                        { /*  */ }
                        catch(ArgumentException)
                        { /*  */ }
                    }
                }
            }
        }
        private void GetPageData(string uriLink,out string PageData)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriLink);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                StreamReader reader = new StreamReader(response.GetResponseStream());
                PageData = reader.ReadToEnd();
            }
            catch(Exception)
            {
                PageData = string.Empty;
            }
        }
        #endregion
    }
}

ir al índice

Índice de la sección dedicada a punto NET (en el Guille)