作者: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 *, int, char * ); /**/
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++ < 10) goto __ReCeive;
}
if(ret <= 0) {fprintf(stderr, " Error while receiving! "); exit(0);}

if(FD_ISSET(sockfd, &writefds)) {
memset(buffer, 0, 1024);
memset(httpheader, 0, 1024);
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, 0, sizeof(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, 0, 1024);
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 {*d = 0; return ;}
while(x) {
if(*x >= 'a' && *x <= 'z') {x--; continue;}
else if(*x >= 'A' && *x <= 'Z') {x--;continue;}
else if(*x >= '0' && *x <= '9') {x--;continue;}
else if(*x == '.' || *x == '-' || *x == '_') {x--;continue;}
else {break;}
}
x++;
if(x) *d = x;
else *d = 0;
}

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

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

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

  1. 建立网络链接编程C语言,用C语言编写一个网络蜘蛛来搜索网上出现的电子邮件地址...

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

  2. [转]用 C 语言编写一个网络蜘蛛

    用 C 语言编写一个网络蜘蛛来搜索网上出现的电子邮件地址 作者:zhoulifa 来源:http://bbs.chinaunix.net/viewthread.php?tid=821361 可能大家经 ...

  3. 利用C语言编写一个网络分析器

    一.链路层数据格式 mac报文:14个字节 二.IP数据报文格式 三.TCP数据报文格式 四.UDP数据报文格式 五.demo(网络分析器) recvfrom接收链路层帧数据,不经过网络层.传输层,不 ...

  4. 使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网)

    使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网) 一,前期准备 1,Java IDE(Eclipse)与JDK的安装与配置 jdk-15.0.1-免配置路径版 提取码:earu 免 ...

  5. linux中用c语言编写一个经纬度转换大地坐标

    在Linux中用C语言编写一个经纬度转换大地坐标的程序,需要用到以下步骤: 包含相关的头文件,例如"math.h". 定义必要的常量和变量. 输入经纬度坐标. 将经纬度转换为弧度. ...

  6. python输入一个正整数n求下列算式的值_C语言编写程序:输入一个正整数x和一个正整数n,求下列算式的值。,C语言 编写一个程序,输入一个正整数,求出它是几位数。...

    导航:网站首页 > C语言编写程序:输入一个正整数x和一个正整数n,求下列算式的值.,C语言 编写一个程序,输入一个正整数,求出它是几位数. C语言编写程序:输入一个正整数x和一个正整数n,求下 ...

  7. 用C语言编写一个Linux下的简单shell程序

    这是一个简单的C程序,展示了如何进行系统调用执行logout cd ls pwd pid rm mkdir mv cp等命令,这是一个简单的命令解释程序shell,其源代码如下: #include & ...

  8. C语言编写一个四位数的和,c语言编写一段程序,输入一个四位数,输出各位数字的和...

    用C语言编写程序,输入一个正整数n(1 #include"stdio.h"intmain(){\x09inti,j,n;\x09inta[12];\x09intmin,mx;\x0 ...

  9. c语言用while实现输出加法口诀表,「加法口诀」C语言编写一个加法口诀表 - 金橙教程网...

    加法口诀 C语言编写一个加法口诀表 #include void main(){ int i,j; for(i=1;i<10;i++){ for(j=1;j<=i;j++){ printf( ...

  10. 等腰字母三角形c语言,c语言等腰三角形代码 用C语言编写一个四行*等腰三角形...

    键盘读入3个整数,代表三角形三条边,判断是否是等腰三角形?输入输出示#include int main() { int a,b,c; while(scanf("%d%d%d",&a ...

最新文章

  1. fastq质量值_微生物组16S rRNA数据分析小结:从fastq测序数据到OTU table
  2. 【转】Java里如何实现线程间通信
  3. JQuery 总结(3) jQuery 各种事件
  4. 【SpringBoot集成ElasticSearch 02】Java HTTP Rest client for ElasticSearch Jest 客户端集成(配置+增删改查测试源码)【推荐使用】
  5. 2011年全国软件大赛模拟题及参考答案(Java本科组)
  6. document.getElementById() id是变量
  7. 1.1 一个简单的脚本
  8. 螺钉装弹垫平垫机器人_【经验总结】什么时候用平垫,什么时候用弹垫?
  9. php整合支付宝,Thinkphp5.0整合支付宝在线下单
  10. 清华 | 量化卷积神经网络加速芯片
  11. 在后台中高效工作 – 后台任务
  12. Office 365 Connectors 的使用与自定义开发
  13. 操作系统 第二部分 进程管理(四)
  14. POJ-2031-Building a Space Station
  15. 桌面美化 Python tkinter倒计时工具
  16. 【Dart语言第5篇】运算符
  17. 根据ip地址获取时区
  18. python dict key类型_Python——dict(自定义类作key)
  19. SQL Server 定时自动备份和自动删除方法图文超详细步骤
  20. 禁止所有搜索引擎蜘蛛的爬行收录

热门文章

  1. 文华财经期货买卖点指标源码,期货超短线指标公式源码
  2. 索鸟快传2.0免费局域网文件共享软件,用C++开发的基于HTTP的文件共享软件,文件下载上传、在线预览
  3. 提取html中的音频文件,如何将网页中的音频文件提取出来
  4. css权威指南读书笔记
  5. python 安装包国内源
  6. 耗时两个礼拜,8000字安卓面试长文,重难点整理
  7. Vensim软件中文介绍
  8. FreeFileSync - 最佳免费开源文件夹同步备份软件 (FTP/局域网/移动硬盘)
  9. 65、未授权访问的TIPS
  10. vue仿网易云音乐播放器