用 C 语言编写一个网络蜘蛛

来源:互联网 发布:mysql 增量备份 编辑:程序博客网 时间:2024/05/09 11:16
 

用 C 语言编写一个网络蜘蛛来搜索网上出现的电子邮件地址


作者:zhoulifa
来源:http://bbs.chinaunix.net/viewthread.php?tid=821361

可能大家经常要去互联网上搜索特定的内容,比如收集大量邮件地址,如果用 google 之类的搜索引擎是没法实现这种特定功能的,所以用 C 语言来写一个吧。它的功能就是不断去取得网络上的页面,然后分析出网页上出现的邮件地址保存下来。象个蜘蛛一样,从网络上一个网页爬向另一个网页,不停止地搜索邮件地址。

 



即:分析程序运行时的参数,把各网页地址作为根节点加入到链表,然后从链表头开始处理各节点

对整个链表的处理是先处理兄弟节点,流程图如下:




然后再处理各节点的子节点,流程图如下:



当然,这里采用了递归调用方法,处理子节点的数据时和处理整个链表一样循环处理就是了。

/************关于本文档********************************************
*filename: 用 C 语言编写一个网络蜘蛛来搜索网上出现的电子邮件地址
*purpose: 一个邮址搜索程序的雏形
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2006-08-31 21:00:00
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
*********************************************************************/

程序在运行的过程中要建立一个树形链表结构,结构图如下:




程序启动时分析所带参数,把各参数加入到根网页节点,如果有多个参数则这个根网页有兄弟节点。
然后从根节点开始处理这一级上各节点,把各节点网页上出现的网页链接加到该节点的子节点上,处理完当前这一级后处理子节点这一级。



当然这只是一个原理展示程序,并没有进行优化。

这个程序的 main 函数流程图如下:

 源代码如下: 

 

 

#include <sys/types.h>
#include 
<sys/stat.h>
#include 
<fcntl.h>
#include 
<sys/mman.h>
#include 
<unistd.h>
#include 
<stdio.h>
#include 
<string.h>
#include 
<stdlib.h>
#include 
<netdb.h>
#include 
<errno.h>
#include 
<locale.h>

#define USERAGENT "Wget/1.10.2"
#define ACCEPT "*/*"
#define ACCEPTLANGUAGE "zh-cn,zh;q=0.5"
#define ACCEPTENCODING "gzip,deflate"
#define ACCEPTCHARSET "gb2312,utf-8;q=0.7,*;q=0.7"
#define KEEPALIVE "300"
#define CONNECTION "keep-alive"
#define CONTENTTYPE "application/x-www-form-urlencoded"

#define MAXFILENAME 14
#define DEBUG 1

typedef 
struct webnode {
        
char * host;                 /* 网页所在的主机 */
        
int port;                    /* 网络服务器所使用的端口 */
        
char * dir;                  /* 网页所在的目录 */
        
char * page;                 /* 网页文件名 */
        
char * file;                 /* 本地保存的文件名 */
        
char IsHandled;              /* 是否处理过 */
        
struct webnode * brother;    /* 兄弟节点链表指针 */
        
struct webnode * child;      /* 子节点链表指针 */
} WEBNODE;

struct sockaddr_in server_addr;
int sockfd = 0, dsend = 0, totalsend = 0, nbytes = 0, reqn = 0, i = 0, j = 0, ret = 0;
struct hostent *host;
char request[409600= "", buffer[1024= "", httpheader[1024= "";
int FileNumber = 0;
char e[2= "@/";
WEBNODE 
* NodeHeader, * NodeTail, * NodeCurr;
char * mapped_mem;

int GetHost(char * , char ** , char ** , int * , char ** ); /**/
void AnalyzePage(WEBNODE *); /**/
void AddInitNode(char *char *intchar * ); /**/
void HandleInitNode(WEBNODE *); /**/
void DisplayNode(WEBNODE *); /**/
void HandOneNode(WEBNODE *); /**/
void DoneWithList(int); /**/
void DoOnce(); /**/
void ConnectWeb(void); /**/
void SendRequest(void); /**/
void ReceiveResponse(void); /**/
void GetEmail(char * ); /**/
void GetLink(char * ); /**/
void GetBeforePos(char * , char ** ); /**/
void GetAfterPos(char * , char ** ); /**/
void AddChildNode(WEBNODE * , char * ); /**/
void GetAfterPosWithSlash(char * , char ** ); /**/
void GetMemory(char ** , int ); /**/
int IsExistWeb(WEBNODE * , char * , char * , int , char * ); /**/
void Rstrchr(char * , int , char ** ); /**/
int GetLocalAgent(char * UserAgent, char * Accept, char * AcceptLanguage, char * AcceptEncoding, char * AcceptCharset, char * KeepAlive, char * Connection, char * ContentType); /**/

 

/**************************************************************
功能:设置 HTTP 协议头内容的一些固定值
**************************************************************
*/
int GetLocalAgent(char * UserAgent, char * Accept, char * AcceptLanguage, char * AcceptEncoding, char * AcceptCharset, char * KeepAlive, char * Connection, char * ContentType)
{
  memcpy(UserAgent, USERAGENT, strlen(USERAGENT));
  memcpy(Accept, ACCEPT, strlen(ACCEPT));
  memcpy(AcceptLanguage, ACCEPTLANGUAGE, strlen(ACCEPTLANGUAGE));
  memcpy(AcceptEncoding, ACCEPTENCODING, strlen(ACCEPTENCODING));
  memcpy(AcceptCharset, ACCEPTCHARSET, strlen(ACCEPTCHARSET));
  memcpy(KeepAlive, KEEPALIVE, strlen(KEEPALIVE));
  memcpy(Connection, CONNECTION, strlen(CONNECTION));
  memcpy(ContentType, CONTENTTYPE, strlen(CONTENTTYPE));
  
return 0;
}

/**************************************************************
功能:在字符串 s 里搜索 x 字符,并设置指针 d 指向该位置
**************************************************************
*/
void Rstrchr(char * s, int x, char ** d)
{
        
int len = strlen(s) - 1;
        
while(len >= 0)        {
                
if(x == s[len]) {(*d) = s + len; return;}
                len
--;
        }
        (
*d) = 0;
}

/**************************************************************
功能:连接一个网站服务器
**************************************************************
*/
void ConnectWeb(void) { /* connect to web server */
  
/* create a socket descriptor */
  
if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1)
  {
    fprintf(stderr,
" Socket Error:%sa ",strerror(errno));
    exit(
1);
  }

  
/* bind address */
  bzero(
&server_addr, sizeof(server_addr));
  server_addr.sin_family 
= AF_INET;
  server_addr.sin_port 
= htons(NodeCurr->port);
  server_addr.sin_addr 
= *((struct in_addr *)host->h_addr);

  
/* connect to the server */
  
if(connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1)
  {
    fprintf(stderr, 
" Connect Error:%sa ", strerror(errno));
    exit(
1);
  }
}

/**************************************************************
功能:向网站发送 HTTP 请求
**************************************************************
*/
void SendRequest(void) { /* send my http-request to web server */
  dsend 
= 0;totalsend = 0;
  nbytes
=strlen(request);
  
while(totalsend < nbytes) {
    dsend 
= write(sockfd, request + totalsend, nbytes - totalsend);
    
if(dsend==-1)  {fprintf(stderr, " send error!%s ", strerror(errno));exit(0);}
    totalsend
+=dsend;
    fprintf(stdout, 
" Request.%d %d bytes send OK! ", reqn, totalsend);
  }
}

/**************************************************************
功能:接收网站的 HTTP 返回
**************************************************************
*/
void ReceiveResponse(void) { /* get response from web server */
  fd_set writefds;
  
struct timeval tival;
  
int retry = 0;
  FILE 
* localfp = NULL;

  i
=0; j = 0;
__ReCeive:
  FD_ZERO(
&writefds);
  tival.tv_sec 
= 10;
  tival.tv_usec 
= 0;
  
if(sockfd > 0) FD_SET(sockfd, &writefds);
  
else {fprintf(stderr, " Error, socket is negative! "); exit(0);}

  ret 
= select(sockfd + 1&writefds, NULL, NULL, &tival);
  
if(ret ==0 ) {
    
if(retry++ < 10goto __ReCeive;
  }
  
if(ret <= 0) {fprintf(stderr, " Error while receiving! "); exit(0);}

  
if(FD_ISSET(sockfd, &writefds))    {
    memset(buffer, 
01024);
    memset(httpheader, 
01024);
    
if((localfp = fopen(NodeCurr->file, "w")) == NULL) {if(DEBUG) fprintf(stderr, "create file '%s' error ", NodeCurr->file); return;}
    
/* receive data from web server */
    
while((nbytes=read(sockfd,buffer,1))==1)
    {
      
if(i < 4)  { /* 获取 HTTP 消息头 */
        
if(buffer[0== ' ' || buffer[0== ' ')  i++;
        
else i = 0;
        memcpy(httpheader 
+ j, buffer, 1); j++;
      }
      
else  { /* 获取 HTTP 消息体 */
        fprintf(localfp, 
"%c", buffer[0]); /* print content on the screen */
        
//fprintf(stdout, "%c", buffer[0]); /* print content on the screen */
        i++;
      }
    }
    fclose(localfp);
  }
}

/**************************************************************
功能:执行一次 HTTP 请求
**************************************************************
*/
void DoOnce() { /* send and receive */
  ConnectWeb(); 
/* connect to the web server */

  
/* send a request */
  SendRequest();

  
/* receive a response message from web server */
  ReceiveResponse();

  close(sockfd); 
/* because HTTP protocol do something one connection, so I can close it after receiving */
}

/**************************************************************
功能:执行 HTTP 请求
**************************************************************
*/
void DoneWithList(int flag) {
  
if(flag) fprintf(stdout, " Request.%d is: %s"++reqn, request);

  DoOnce();

  
if(flag) fprintf(stdout, " The following is the response header: %s", httpheader);
}

/**************************************************************
功能:从字符串 src 中分析出网站地址和端口,并得到文件和目录
**************************************************************
*/
int GetHost(char * src, char ** web, char ** file, int * port, char ** dir)  {
  
char * pA, * pB, * pC;
  
int len;

  
*port = 0;
  
if(!(*src))  return -1;
  pA 
= src;
  
if(!strncmp(pA, "http://", strlen("http://")))  pA = src+strlen("http://");
  
/* else if(!strncmp(pA, "https://", strlen("https://")))  pA = src+strlen("https://"); */
  
else return 1;
  pB 
= strchr(pA, '/');
  
if(pB)  {
    len 
= strlen(pA) - strlen(pB);
    GetMemory(web, len);
    memcpy((
*web), pA, len);
    
if(*(pB+1))  {
      Rstrchr(pB 
+ 1'/'&pC);
      
if(pC) len = strlen(pB + 1- strlen(pC);
      
else len = 0;
      
if(len > 0) {
        GetMemory(dir, len);
        memcpy((
*dir), pB + 1, len);

        
if(pC + 1) {
          len 
= strlen(pC + 1);
          GetMemory(file, len);
          memcpy((
*file), pC + 1, len);
        }
        
else {
          len 
= 1;
          GetMemory(file, len);
          memcpy((
*file), e, len);
        }
      }
      
else {
        len 
= 1;
        GetMemory(dir, len);
        memcpy((
*dir), e + 1, len);

        len 
= strlen(pB + 1);
        GetMemory(file, len);
        memcpy((
*file), pB + 1, len);
      }
    }
    
else {
      len 
= 1;
      GetMemory(dir, len);
      memcpy((
*dir), e + 1, len);

      len 
= 1;
      GetMemory(file, len);
      memcpy((
*file), e, len);
    }
  }
  
else  {
    len 
= strlen(pA);
    GetMemory(web, len);
    memcpy((
*web), pA, strlen(pA));
    len 
= 1;
    GetMemory(dir, len);
    memcpy((
*dir), e + 1, len);
    len 
= 1;
    GetMemory(file, len);
    memcpy((
*file), e, len);
  }

  pA 
= strchr((*web), ':');
  
if(pA)  *port = atoi(pA + 1);
  
else *port = 80;

  
return 0;
}

 

/*********************************************************************
*filename: mailaddrsearch.c
*purpose: 用 C 语言编写一个网络蜘蛛来搜索网上出现的电子邮件地址
*tidied by: zhoulifa(zhoulifa@163.com) 周立发(
http://zhoulifa.bokee.com)
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2006-08-31 21:00:00
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Thanks to: www.gd-linux.org 广东省 Linux 公共服务技术支持中心
********************************************************************
*/

int main(int argc, char ** argv)
{
        
int WebPort;
        
char * WebHost = 0* PageAddress = 0* WebDir = 0;

        
if(argc < 2) {if(DEBUG) fprintf(stdout, "Command error, you should input like this: %s WebPageAddress1 WebPageAddress2 WebPageAddress3 ...", argv[0]); exit(0);}

        NodeHeader 
= NodeTail = NodeCurr = 0;
        
//setlocale(LC_ALL, "zh_CN.gb2312");
        for(i = 1; i < argc; i++)        {
                ret 
= GetHost(argv, &WebHost, &PageAddress, &WebPort, &WebDir); /* Get web page info */
                
if(ret)        {if(DEBUG) fprintf(stdout, "GetHost error from '%s' ", argv); exit(0);}
                AddInitNode(WebHost, PageAddress, WebPort, WebDir); 
/* add this page to chain */
        }
        free(WebHost); free(PageAddress);free(WebDir);
        
if(DEBUG)        {
                fprintf(stdout, 
" Display.%5d:", FileNumber);
                DisplayNode(NodeHeader); 
/* display every node */
        }
        HandleInitNode(NodeHeader); 
/* handle every page */
        
return 0;
}

 

/**************************************************************
功能:分析网页
**************************************************************
*/
void AnalyzePage(WEBNODE * node)
{
        
int fd;
        
int flength = 0;
        fd 
= open(node->file, O_RDONLY);
        
if(fd == -1)        goto __AnalyzeDone;
        flength 
= lseek(fd, 1, SEEK_END);
        write(fd, 
"/0"1);
        lseek(fd, 
0, SEEK_SET);
        mapped_mem 
= mmap(0, flength, PROT_READ, MAP_PRIVATE, fd, 0);
        GetEmail(mapped_mem);
        GetLink(mapped_mem);
        close(fd);
        munmap(mapped_mem, flength);
__AnalyzeDone:
        close(fd);
        node
->IsHandled = 1;
        remove(node
->file);
}

/**************************************************************
功能:为根节点设置兄弟节点
**************************************************************
*/
void AddInitNode(char * Host, char * Page, int Port, char * Dir)
{
        WEBNODE 
* NewNode;
        
char filename[MAXFILENAME + 1= "";

        
if(NodeHeader == NULL) NewNode = NodeHeader = (WEBNODE *)malloc(sizeof(WEBNODE));
        
else NodeTail->brother = NewNode = (WEBNODE *)malloc(sizeof(WEBNODE));
        memset(NewNode, 
0sizeof(WEBNODE));
        NewNode
->host = (char *)malloc(strlen(Host) + 1);
        memset(NewNode
->host, 0, strlen(Host) + 1);
        NewNode
->page = (char *)malloc(strlen(Page) + 1);
        memset(NewNode
->page, 0, strlen(Page) + 1);
        NewNode
->dir = (char *)malloc(strlen(Dir) + 1);
        memset(NewNode
->dir, 0, strlen(Dir) + 1);
        NewNode
->file = (char *)malloc(MAXFILENAME + 1);
        memset(NewNode
->file, 0, MAXFILENAME + 1);
        strcpy(NewNode
->host, Host);
        strcpy(NewNode
->page, Page);
        strcpy(NewNode
->dir, Dir);
        sprintf(filename, 
"file%05d.html", FileNumber++);
        strcpy(NewNode
->file, filename);
        NewNode
->port = Port;
        NewNode
->IsHandled = 0;
        NewNode
->brother = 0;
        NewNode
->child = 0;
        NodeTail 
= NewNode;
}

/**************************************************************
功能:处理根节点信息
**************************************************************
*/
void HandleInitNode(WEBNODE * node)
{
        WEBNODE 
* CurrentNode = 0;
        CurrentNode 
= node;
        
if(CurrentNode)        {
                
while(CurrentNode)        {
                        
if(CurrentNode->IsHandled == 0)        {
                                HandOneNode(CurrentNode);
                                
if(DEBUG)        {
                                        fprintf(stdout, 
" Display.%5d:", FileNumber);
                                        DisplayNode(NodeHeader); 
/* display every node */
                                }
                        }
                        CurrentNode 
= CurrentNode->brother;
                }
                CurrentNode 
= node;
                
while(CurrentNode)        {
                        
if(CurrentNode->child && CurrentNode->child->IsHandled == 0)        {
                                HandleInitNode(CurrentNode
->child);
                        }
                        CurrentNode 
= CurrentNode->brother;
                }
        }
}

/**************************************************************
功能:显示年有节点信息
**************************************************************
*/
void DisplayNode(WEBNODE * NodeHeader)
{
        WEBNODE 
* TempNode;
        TempNode 
= NodeHeader;
        fprintf(stdout, 
" ");
        
while(TempNode) {
                
if(!strcmp(TempNode->dir, "/"))        fprintf(stdout, " %s:%d%s%s => %s %d ", TempNode->host, TempNode->port, TempNode->dir, strcmp(TempNode->page, "@")?TempNode->page:"", TempNode->file, TempNode->IsHandled);
                
else        fprintf(stdout, " %s:%d/%s/%s => %s %d ", TempNode->host, TempNode->port, TempNode->dir, strcmp(TempNode->page, "@")?TempNode->page:"", TempNode->file, TempNode->IsHandled);
                TempNode 
= TempNode->brother;
        }
        TempNode 
= NodeHeader;
        
while(TempNode) {
                
if(TempNode->child)        DisplayNode(TempNode->child);
                TempNode 
= TempNode->brother;
        }
}

/**************************************************************
功能:处理单个节点信息
**************************************************************
*/
void HandOneNode(WEBNODE * node)
{
        
char UserAgent[1024= "", Accept[1024= "", AcceptLanguage[1024= "", AcceptEncoding[1024= "", AcceptCharset[1024= "", KeepAlive[1024= "", Connection[1024= "", ContentType[1024= "";

        NodeCurr 
= node;
        
if((host=gethostbyname(NodeCurr->host))==NULL) /* get ip address by domain */
        {
                
if(DEBUG)  fprintf(stderr," Gethostname '%s' error, %s ", NodeCurr->host, strerror(errno));
                exit(
1);
        }
        GetLocalAgent(UserAgent, Accept, AcceptLanguage, AcceptEncoding, AcceptCharset, KeepAlive, Connection, ContentType); 
/* Get client browser information */

        
if(strcmp(NodeCurr->dir, "/"))        sprintf(request, "GET /%s/%s HTTP/1.0 Host: %s User-Agent: %s Accept: %s Connection: %s ", NodeCurr->dir, strcmp(NodeCurr->page, "@")?NodeCurr->page:"", NodeCurr->host, UserAgent, Accept, Connection);
        
else        sprintf(request, "GET %s%s HTTP/1.0 Host: %s User-Agent: %s Accept: %s Connection: %s ", NodeCurr->dir, strcmp(NodeCurr->page, "@")?NodeCurr->page:"", NodeCurr->host, UserAgent, Accept, Connection);
        DoneWithList(
1);
        AnalyzePage(NodeCurr);
}

/**************************************************************
功能:从字符串 src 中分析出邮件地址保存到文件
**************************************************************
*/
void GetEmail(char * src)
{
        
char * pa, * pb, * pc, *pd;
        
char myemail[1024= "";
        FILE 
* mailfp = NULL;
        
if((mailfp = fopen("email.txt""a+")) == NULL)        return;
        pa 
= src;
        
while((pb = strchr(pa, '@')))        {
                GetBeforePos(pb, 
&pc);
                GetAfterPos(pb, 
&pd);
                
if(pc && pd && (strlen(pc) > (strlen(pd) + 3)))        {
                        memset(myemail, 
01024);
                        memcpy(myemail, pc, strlen(pc) 
- strlen(pd));
                        
if(strcmp(NodeCurr->dir, "/")) fprintf(mailfp, "%s http://%s/%s/%s ", myemail, NodeCurr->host, NodeCurr->dir, strcmp(NodeCurr->page, "@")?NodeCurr->page:"");
                        
else  fprintf(mailfp, "%s http://%s%s%s ", myemail, NodeCurr->host, NodeCurr->dir, strcmp(NodeCurr->page, "@")?NodeCurr->page:"");
                        
if(*(pd + 1))        pa = pd + 1;
                        
else break;
                }
                
else if(*(pb + 1))        pa = pb + 1;
                
else        break;
        }
        fclose(mailfp);
}

/**************************************************************
功能:从 src 中找出前面的字母、数字等内含,即 email 地址中 @ 的前面部分
**************************************************************
*/
void GetBeforePos(char * src, char ** d)
{
        
char * x;
        
if(src - 1)        x = src - 1;
        
else {*= 0return ;}
        
while(x)        {
                
if(*>= 'a' && *<= 'z') {x--continue;}
                
else if(*>= 'A' && *<= 'Z') {x--continue;}
                
else if(*>= '0' && *<= '9') {x--continue;}
                
else if(*== '.' || *== '-' || *== '_') {x--continue;}
                
else {break;}
        }
        x
++;
        
if(x) *= x;
        
else *= 0;
}

/**************************************************************
功能:从 src 中找出后面的字母、数字等内含,即 email 地址中 @ 的后面部分
**************************************************************
*/
void GetAfterPos(char * src, char ** d)
{
        
char * x;
        
if(src + 1)        x = src + 1;
        
else {*= 0return ;}
        
while(x)        {
                
if(*>= 'a' && *<= 'z') {x++continue;}
                
else if(*>= 'A' && *<= 'Z') {x++continue;}
                
else if(*>= '0' && *<= '9') {x++continue;}
                
else if(*== '.' || *== '-' || *== '_') {x++continue;}
                
else {break;}
        }
        
if(x) *= x;
        
else *= 0;

 

/**************************************************************
功能:从 src 中找出前面的字母、数字等内含,即一个网页地址中主机名后面的部分
**************************************************************
*/
void GetAfterPosWithSlash(char * src, char ** d)
{
        
char * x;
        
if(src)        x = src;
        
else {*= 0return ;}
        
while(x)        {
                
if(*>= 'a' && *<= 'z') {x++continue;}
                
else if(*>= 'A' && *<= 'Z') {x++continue;}
                
else if(*>= '0' && *<= '9') {x++continue;}
                
else if(*== '.' || *== '-' || *== '_' || *== '=') {x++continue;}
                
else if(*== ':' || *== '/' || *== '?' || *== '&') {x++continue;}
                
else {break;}
        }
        
if(x) *= x;
        
else *= 0;
}

/**************************************************************
功能:为 myanchor 分配 len 大小的内存
**************************************************************
*/
void GetMemory(char ** myanchor, int len)
{
        
if(!(*myanchor))        (*myanchor) = (char *)malloc(len + 1);
        
else        (*myanchor) = (char *)realloc((void *)(*myanchor), len + 1);
        memset((
*myanchor), 0, len + 1);
}

/**************************************************************
功能:从 src 中分析出网页链接,并加入到当前节点的子节点上
**************************************************************
*/
void GetLink(char * src)
{
        
char * pa, * pb, * pc;
        
char * myanchor = 0;
        
int len = 0;

        pa 
= src;
        
do {
                
if((pb = strstr(pa, "href='")))        {
                        pc 
= strchr(pb + 6''');
                        len 
= strlen(pb + 6- strlen(pc);
                        GetMemory(
&myanchor, len);
                        memcpy(myanchor, pb 
+ 6, len);
                }
                
else if((pb = strstr(pa, "href="")))        {
                        pc 
= strchr(pb + 6'"');
                        len 
= strlen(pb + 6- strlen(pc);
                        GetMemory(
&myanchor, len);
                        memcpy(myanchor, pb 
+ 6, len);
                }
                
else if((pb = strstr(pa, "href=")))        {
                        GetAfterPosWithSlash(pb 
+ 5&pc);
                        len 
= strlen(pb + 5- strlen(pc);
                        GetMemory(
&myanchor, len);
                        memcpy(myanchor, pb 
+ 5, len);
                }
                
else {goto __returnLink ;}
/*
                if(DEBUG)        {
                        if(strcmp(NodeCurr->dir, "/"))        fprintf(stdout, "%s http://%s/%s/%s ", myanchor, NodeCurr->host, NodeCurr->dir, strcmp(NodeCurr->page, "`")?NodeCurr->page:"");
                        else        fprintf(stdout, "%s http://%s%s%s ", myanchor, NodeCurr->host, NodeCurr->dir, strcmp(NodeCurr->page, "`")?NodeCurr->page:"");
                }
*/
                
if(strlen(myanchor) > 0)        AddChildNode(NodeCurr, myanchor);
                
if(pc + 1)        pa = pc + 1;
        }
while(pa);
__returnLink:
        
return;
}

/**************************************************************
功能:为当前节点增加子节点
**************************************************************
*/
void AddChildNode(WEBNODE * node, char * src)
{
        
int WebPort, len;
        
char * WebHost = 0* PageAddress = 0* WebDir = 0* pC = 0;
        WEBNODE 
* NewNode;
        
char filename[MAXFILENAME + 1= "";
        
char IsFromRoot = 0;

        
if(!src)        return;
        
if(!strncasecmp(src, "mailto:", strlen("mailto:")))        return ;
        
if(strstr(src, ".css"))        return;
        
if(strstr(src, ".xml"))        return;
        
if(strstr(src, ".ico"))        return;
        
if(strstr(src, ".jpg"))        return;
        
if(strstr(src, ".gif"))        return;
        
if(strstr(src, "javascript:"))        return;
        
if(strstr(src, "+"))        return;

        ret 
= GetHost(src, &WebHost, &PageAddress, &WebPort, &WebDir);
        
if(ret)        {
                len 
= strlen(node->host);
                GetMemory(
&WebHost, len);
                strcpy(WebHost, node
->host);

                WebPort 
= node->port;

                IsFromRoot 
= !strncmp(src, "/"1);
                
if(IsFromRoot && (src + 1))        Rstrchr(src + 1'/'&pC);
                
else if(!IsFromRoot)        Rstrchr(src, '/'&pC);
                
else        pC = 0;

                
if(pC)        {
                        
if(IsFromRoot)        len = strlen(src + 1- strlen(pC);
                        
else        len = strlen(src) - strlen(pC) + strlen(node->dir) + 1;
                        GetMemory(
&WebDir, len);
                        
if(IsFromRoot)        memcpy(WebDir, src + 1, len);
                        
else        {memcpy(WebDir, node->dir, strlen(node->dir)); strcat(WebDir, "/"); memcpy(WebDir + strlen(node->dir) + 1, src, strlen(src) - strlen(pC));}

                        
if(pC + 1)        {
                                len 
= strlen(pC + 1);
                                GetMemory(
&PageAddress, len);
                                strcpy(PageAddress, pC 
+ 1);
                        }
                        
else        {
                                len 
= 1;
                                GetMemory(
&PageAddress, len);
                                memcpy(PageAddress, e, len);
                        }
                }
                
else        {
                        
if(IsFromRoot)        {
                                len 
= 1;
                                GetMemory(
&WebDir, len);
                                memcpy(WebDir, e 
+ 1, len);

                                len 
= strlen(src + 1);
                                GetMemory(
&PageAddress, len);
                                memcpy(PageAddress, src 
+ 1, len);
                        }
                        
else        {
                                len 
= strlen(node->dir);
                                GetMemory(
&WebDir, len);
                                memcpy(WebDir, node
->dir, len);

                                len 
= strlen(src);
                                GetMemory(
&PageAddress, len);
                                memcpy(PageAddress, src, len);
                        }
                }
        }
        ret 
= IsExistWeb(NodeHeader, WebHost, PageAddress, WebPort, WebDir);
        
if(ret) goto __ReturnAdd;

        
if(node->child == NULL)        NewNode = node->child = (WEBNODE *)malloc(sizeof(WEBNODE));
        
else NodeTail->brother = NewNode = (WEBNODE *)malloc(sizeof(WEBNODE));
        memset(NewNode, 
0sizeof(WEBNODE));
        NewNode
->host = (char *)malloc(strlen(WebHost) + 1);
        memset(NewNode
->host, 0, strlen(WebHost) + 1);
        NewNode
->page = (char *)malloc(strlen(PageAddress) + 1);
        memset(NewNode
->page, 0, strlen(PageAddress) + 1);
        NewNode
->dir = (char *)malloc(strlen(WebDir) + 1);
        memset(NewNode
->dir, 0, strlen(WebDir) + 1);
        NewNode
->file = (char *)malloc(MAXFILENAME + 1);
        memset(NewNode
->file, 0, MAXFILENAME + 1);
        strcpy(NewNode
->host, WebHost);
        strcpy(NewNode
->page, PageAddress);
        strcpy(NewNode
->dir, WebDir);
        sprintf(filename, 
"file%05d.html", FileNumber++);
        strcpy(NewNode
->file, filename);
        NewNode
->port = WebPort;
        NewNode
->IsHandled = 0;
        NewNode
->brother = 0;
        NewNode
->child = 0;
        NodeTail 
= NewNode;
__ReturnAdd:
        free(WebHost); free(PageAddress); free(WebDir);
}

/**************************************************************
功能:检查是否已经处理过的网页
**************************************************************
*/
int IsExistWeb(WEBNODE * node, char * host, char * page, int port, char * dir)
{
        WEBNODE 
* t;
        t 
= node;
        
while(t)        {
                
if(!strcmp(t->host, host) && !strcmp(t->page, page) && t->port == port && !strcmp(t->dir, dir)) return 1;
                t 
= t->brother;
        }
        t 
= node;
        
while(t)        {
                
if(t->child)        {
                        ret 
= IsExistWeb(t->child, host, page, port, dir);
                        
if(ret)        return 2;
                }
                t 
= t->brother;
        }
        
return 0;
}

 

编译这个程序:

gcc mailaddrsearch.c -o mailsearcher

输入一个网址作为参数运行一下试试吧:

./mailsearcher http://zhoulifa.bokee.com/5531748.html


程序首先找出
http://zhoulifa.bokee.com/5531748.html 页面上的邮件地址保存到当前目录下 email.txt 文件里,每行一条记录,格式为邮件地址和出现该邮件地址的网页。然后分析这个页面上出现的网页链接,把各链接作为子节点加入链表,再去处理子节点,重复上述操作。

这只是一个示例程序,并不完善,如果要使其达到实用的目的,还需要让这个程序效率更高点,比如加入 epoll ( 在 2.4 内核中只有 select 了 ) 实现 I/O 多路复用。又比如对每个子节点实现多线程,每个线程处理一个节点。
如果对 I/O 多路复用不熟悉,您可以看一下我这篇文章
http://zhoulifa.bokee.com/5345930.html 里关于 “ Linux 下各类TCP网络服务器的实现源代码

 

 

原创粉丝点击