我的C语言函数

本文介绍了一个使用Winsock实现的简易网络爬虫程序,该程序能够从指定网站抓取HTML页面并解析其中的数据,同时还能下载网页中包含的图片。文章详细展示了如何构建HTTP请求、接收响应、解析HTML标签及图片URL等关键技术细节。
 
 
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>  
 
 
 
//提示信息
void Help(char * str)
{
    printf("/n%s/t<StartNum>/t[EndNum]/n",str);
    printf("StartNum/t开始ID号;/n");
    printf("EndNum/t/t结束ID号,默认为开始号+100;/n");
}
////////////////////////////////////////////////////////////////////////
//
//    函数名:GetWebImg()
//    说明:从WEB上下载图片,保存到data/中
//    参数:(char *)imgurl    图片地址
//          (char *)imgname    保存到本地的图片名称
//     返回:(int)0        图片成功下载
//
///////////////////////////////////////////////////////////////////////
int GetWebImg( char * imgurl,char * imgname)
{
    WSADATA   wsd;
    SOCKET    sClient;
    char      szBuffer[1024];
    char      szServer[128];
    char     CurrentPath[256];
    char    FilePath[256];
    int       ret,i,iPort;
    struct sockaddr_in server;
    struct hostent     * host=NULL;
    FILE  *fp;
 
    memset(szBuffer,0,sizeof(szBuffer));
    GetCurrentDirectory(sizeof(CurrentPath),CurrentPath);
    strcat(CurrentPath,"//");
    strcpy(FilePath,CurrentPath);
    strcat(FilePath,"//img//");
    strcat(FilePath,imgname);
     
    if((fp=fopen(FilePath,"wb"))==NULL)
    {
        printf("file can not open!/n");
        exit(0);
    }
     
    //发送给远程主机的请求内容串
    sprintf(szBuffer,
            "GET %s HTTP/1.1/r/nHost:%s/r/nConnection:Close/r/n/r/n",imgurl,HOST);
         
    iPort=80;
//    printf("buf:%s/n%d/n",szBuffer,strlen(szBuffer));
    memset(szServer,0,sizeof(szServer));
    sprintf(szServer,"bookcity.dayoo.com");
 
    if(WSAStartup(MAKEWORD(2,2),&wsd)!=0)
    {
        printf("Failed to load Winsock library!/n");
        return -1;
    }
 
    sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(sClient==INVALID_SOCKET)
    {
        printf("socket() failed:%d/n",WSAGetLastError());
        return -1;
    }
 
    server.sin_family=AF_INET;
    server.sin_port=htons(iPort);
    server.sin_addr.s_addr=inet_addr(szServer);
 
    if(server.sin_addr.s_addr==INADDR_NONE)
        {
            host=gethostbyname(szServer);
            if(host==NULL)
            {
                printf("Unable to resolve server: %s/n",
                        szServer);
                return -1;
            }
            CopyMemory(&server.sin_addr,host->h_addr_list[0],
                    host->h_length);
        }
    if(connect(sClient,(struct sockaddr *)&server,
                sizeof(server))==SOCKET_ERROR)
    {
        printf("connect() failed: %d/n",WSAGetLastError());
        return -1;
    }
 
 
    //发送
    ret=send(sClient,szBuffer,strlen(szBuffer),0);
    if(ret==0 || ret==SOCKET_ERROR)
    {
     
        printf("send() failed: %d/n",WSAGetLastError());
        return -1;
    }
//    printf("send %d/n",ret);
 
    int ok=0;
    int it=0;
    int count=1;
    char * tmp;
    //接收
    while(1)
    {
        memset(szBuffer,0,sizeof(szBuffer));
        ret=0;
        ret=recv(sClient,szBuffer,sizeof(szBuffer),0);
        if(ret==0)
        {
            break;
        }
        if(count>0)
        {
        //在第一个接收到的数据中查第一个空格后是响映号码200为正确
            for(tmp=szBuffer;*tmp!='/0'&&!isspace(*tmp);++tmp)
                ;
            for(;isspace(*tmp);++tmp)
                ;
            ok=atoi(tmp);
            for(;strnicmp(tmp,"/r/n/r/n",4);++tmp)
                ;
            tmp=tmp+4;        //去除实体头
            it=(int)(tmp-szBuffer);
            it=(int)(ret-it);
            fwrite(tmp,sizeof(char),it,fp);
            count=0;
        }
        else
        {
        it=it+ret;
        fwrite(szBuffer,sizeof(char),ret,fp);
        }
    //    printf("%s/n",szBuffer);
    }
//    printf("%d/n",it);
    printf("/nget %s file full!/n",imgurl);
    fclose(fp);
    closesocket(sClient);
    WSACleanup();
    return 0;
     
}
 
//////////////////////////////////////////////////////////////////////
//
//  函数名:GetHTMLData()
//  
//  说明:从HTML字符串中取出所需要的数据(如:<span id="ddd">xxxxx</span>
//  
//  参数:
//      (char *)tag        数据所在的HTML标签名
//      (char *)Id        标签ID值
//      (char *)html        HTML字串(文件区),在这里面找出我需要的数据
//      (char *)data        找到数据存放的区域,输出
//      (int)size        data的大小
//       
//  返回:(int)            0找到数据
//  
//  错语:返回-1为没找到数据.
//       
/////////////////////////////////////////////////////////////////////
int GetHTMLData(char * tag,char * Id,char *html,char * data,int size)
{
     
    char ltag[256],tmptag[256],lid[256],tmplid[256],*lhtml,*tmp,*fortmp;
    char* start;//数据开始位置
    int  n,count;//计数器
 
    strcpy(ltag,tag);
    strcpy(lid,Id);
 
 
    ///原理
    //1,找到第一个ID=id的tag标签然后计数器加1,
    //循环下面两步
    //2,检查计数器,如果计数器==0表明操作完成
    //3,从ID=id的tag标签处开始找配对标签出栈和新的(钳套标签)入栈
     
    ////////////////////////////////////////////////////////////////
    //第一步找到第一个ID=id的tag
    for(fortmp=html;fortmp<(html+strlen(html));fortmp++)
    {
            n=100;
            memset(tmptag,0,sizeof(tmptag));
            sprintf(tmptag,"<%s",ltag);
            if(strnicmp(fortmp,tmptag,strlen(tmptag))==0)
            {
                //从第一个tag标签到">"处找ID=id的值是否存在
                for(tmp=fortmp;tmp<(fortmp+strlen(fortmp));tmp++)
                {
                 
                    memset(tmplid,0,sizeof(tmplid));
                    sprintf(tmplid,"id=/"%s/"",lid);
                    if(strnicmp(tmp,tmplid,strlen(tmplid))==0)
                    {
                        //找到ID=id的标签,进入第二步
                        n=0;
                        //break;
                    }
                    if(n==0)
                    {
                        if(strnicmp(tmp,">",strlen(">"))==0)
                        {
                        //继续找下一个tag
                        fortmp=tmp;
                        break;
                        }
                         
                    }
                }
             
            }
            if(n==0)
                break;
             
             
         
    }
 
    //找不到tag和id一样的标签
    if(n!=0)
    {
        memset(data,0,size);
        return -1;
    }
    count=1;
    start=fortmp+1;//保存数据开始位置
    /////////////////////////////////////////////第二步
    //2,检查栈指针是否在栈底,如果在栈底就完成查栈
    //3,从ID=id的tag标签处开始找配对标签出栈和新的(钳套标签)入栈
    tmp=fortmp;
    for(fortmp;fortmp<tmp+strlen(tmp);fortmp++)
    {
            memset(tmptag,0,sizeof(tmptag));
            sprintf(tmptag,"<%s",ltag);
            if(strnicmp(fortmp,tmptag,strlen(tmptag))==0)
            {
            //有钳套标签,count+1
            count++;
            }
            memset(tmptag,0,sizeof(tmptag));
            sprintf(tmptag,"</%s>",ltag);
            if(strnicmp(fortmp,tmptag,strlen(tmptag))==0)
            {
            //找到一个结束的标签,count--
            count--;
            }
            if(count<1)
            {
                break;
            }
    }
    //start[300]='/0';
    //printf("%s/n",start);
    memset(data,0,size);
    n=fortmp-start;
    if(n>size-1)
    {
        n=size-1;
    }
//    strncpy(data,start,n);
    memcpy(data,start,n);
    data[n]='/0';
    return 0;
 
     
     
}
 
 
//////////////////////////////////////////////////////////////////////
//
//  函数名:GetImgUrl()
//  
//  说明:从HTML字符串中取出所需要的图像URL
//  
//  参数:
//      (char *)Id        标签ID值
//      (char *)html        HTML字串(文件区),在这里面找出我需要的数据
//      (char *)data        找到数据存放的区域,输出
//      (int)size        data的大小
//       
//  返回:(int)            0找到数据
//  
//  错语:返回-1为没找到数据.
//       
/////////////////////////////////////////////////////////////////////
int GetImgUrl(char * Id,char *html,char * data,int size)
{
     
    char ltag[256],tmptag[256],lid[256],tmplid[256],*lhtml,*tmp,*fortmp;
    char* start;//数据开始位置
    int  n,count;//计数器
 
    strcpy(ltag,"img");
    strcpy(lid,Id);
 
 
     
    ////////////////////////////////////////////////////////////////
    //第一步找到第一个ID=id的tag
    for(fortmp=html;fortmp<(html+strlen(html));fortmp++)
    {
            n=100;
            memset(tmptag,0,sizeof(tmptag));
            sprintf(tmptag,"<%s",ltag);
            if(strnicmp(fortmp,tmptag,strlen(tmptag))==0)
            {
                //从第一个tag标签到">"处找ID=id的值是否存在
                for(tmp=fortmp;tmp+strlen(fortmp);tmp++)
                {
                 
                    memset(tmplid,0,sizeof(tmplid));
                    sprintf(tmplid,"id=/"%s/"",lid);
                    if(strnicmp(tmp,tmplid,strlen(tmplid))==0)
                    {
                        //找到ID=id的标签,进入第二步
                        start=fortmp;
                        n=0;
                        //break;
                    }
                 
                    if(strnicmp(tmp,">",strlen(">"))==0)
                    {
                        fortmp=tmp;
                        break;
                    }
                         
                 
                         
                }
             
            }
            if(n==0)
                break;
             
             
         
    }
 
    //找不到tag和id一样的标签
    if(n!=0)
    {
        return -1;
    }
    fortmp=start;//保存ID=我们ID的<img的位置
    start=tmp;//保存/>的位置
    /////////////////////////////////////////////第二步
     
    //3,从<img处到/>找 src=
    tmp=fortmp;
//    fortmp[30]='/0';
//    printf("%s/n",fortmp);
    char *tp,*tp2;
    for(fortmp;fortmp<start;fortmp++)
    {
            memset(tmptag,0,sizeof(tmptag));
            sprintf(tmptag,"src=");
            if(strnicmp(fortmp,tmptag,strlen(tmptag))==0)
            {
                tp=fortmp+strlen("str=");//记下数据的开始位置
                tp2=strstr(fortmp," ");
                tp[tp2-tp]='/0';
                //printf("%s/n",tp);
                break;
            }
    }
    memset(data,0,size);
    strcpy(data,tp);
    return 0;
 
     
     
}
 
/* 函数:GetBooks
 * 描述:从网上抓取网页数据存到全局szHtml中
 * 参数:网址 ID
 * 返回:0完成
 */
int GetBooks(char * url,int id)
{
    char lurl[256],szTmp[256],szTemp[256],*pszTmp,*pszMake,*pszBuf;
    sprintf(lurl,"%s%d/0",url,id);
    printf("%s/n",lurl);
    WSADATA   wsd;
    SOCKET    sClient;
    char      szBuffer[1024];
    char      szServer[128];
    int       ret,i,iPort,itmp,pszTmpSize;
    struct sockaddr_in server;
    struct hostent     * host=NULL;
    FILE *fp;
 
    memset(szBuffer,0,sizeof(szBuffer));
 
     
    //发送给远程主机的请求内容串
    sprintf(szBuffer,
            "GET %s HTTP/1.1/r/nAccept-Language:zh-cn/r/nHost:%s/r/nConnection:Close/r/n/r/n",
            lurl,HOST);
         
    iPort=80;
    memset(szServer,0,sizeof(szServer));
    sprintf(szServer,"bookcity.dayoo.com");
 
    if(WSAStartup(MAKEWORD(2,2),&wsd)!=0)
    {
        printf("Failed to load Winsock library!/n");
        return -1;
    }
 
    sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(sClient==INVALID_SOCKET)
    {
        printf("socket() failed:%d/n",WSAGetLastError());
        return -1;
    }
 
    server.sin_family=AF_INET;
    server.sin_port=htons(iPort);
    server.sin_addr.s_addr=inet_addr(szServer);
 
    if(server.sin_addr.s_addr==INADDR_NONE)
        {
            host=gethostbyname(szServer);
            if(host==NULL)
            {
                printf("Unable to resolve server: %s/n",
                        szServer);
                return -1;
            }
            CopyMemory(&server.sin_addr,host->h_addr_list[0],
                    host->h_length);
        }
    if(connect(sClient,(struct sockaddr *)&server,
                sizeof(server))==SOCKET_ERROR)
    {
        printf("connect() failed: %d/n",WSAGetLastError());
        return -1;
    }
 
    sprintf(szBuffer,
            "HEAD %s HTTP/1.1/r/nAccept-Language:zh-cn/r/nHost:%s/r/n/r/n",
            lurl,HOST);
    //发送
    ret=send(sClient,szBuffer,strlen(szBuffer),0);
    if(ret==0 || ret==SOCKET_ERROR)
    {
     
        printf("send() failed: %d/n",WSAGetLastError());
        return -1;
    }
    //接收头文件
    ret=recv(sClient,szBuffer,sizeof(szBuffer)-1,0);
    szBuffer[ret]='/0';
    //输入响映代码头
    for(i=0;szBuffer[i]!='/0'&&strnicmp(&szBuffer[i],"/r/n",2);i++)
        ;
    memset(szTmp,0,sizeof(szTmp));
    strncpy(szTmp,szBuffer,i);
    printf("%s/n",szTmp);
 
    //判别响映代码
    for(i=0;szBuffer[i]!='/0'&&!isspace(szBuffer[i]);i++)
        ;
    for(;isspace(szBuffer[i]);i++)
        ;
    itmp=atoi(&szBuffer[i]);
    //printf("%d/n",itmp);
    if(itmp!=200)
        return -1;
    //获取实体长度
    for(i=0;szBuffer[i]!='/0'&&strnicmp(&szBuffer[i],"Content-Length:",15);i++)
        ;
    i=i+15;
    itmp=atoi(&szBuffer[i]);
    //printf("%d/n",itmp);
    pszTmpSize=itmp+1;
    pszTmp=(char*)malloc(sizeof(char)*pszTmpSize);
    pszMake=(char*)malloc(sizeof(char)*pszTmpSize);
    pszBuf=(char*)malloc(sizeof(char)*pszTmpSize);
    if(pszTmp==NULL||pszMake==NULL||pszBuf==NULL)
    {
        printf("动态内存分配失败!/n");
        return -1;
    }
 
     
     
    memset(szBuffer,0,sizeof(szBuffer));
    sprintf(szBuffer,
            "GET %s HTTP/1.1/r/nAccept-Language:zh-cn/r/nHost:%s/r/nConnection:Close/r/n/r/n",
            lurl,HOST);
 
    //发送
     
    ret=send(sClient,szBuffer,strlen(szBuffer),0);
    if(ret==0 || ret==SOCKET_ERROR)
    {
     
        printf("send() failed: %d/n",WSAGetLastError());
        return -1;
    }
    //printf("%d/n",ret);
 
    memset(szBuffer,0,sizeof(szBuffer));
    ret=recv(sClient,szBuffer,sizeof(szBuffer)-1,0);
    for(i=0;szBuffer[i]!='/0'&&strnicmp(&szBuffer[i],"/r/n/r/n",4);i++)
        ;
    i=i+4;
    itmp=ret-i;
 
    int cn=0;        //计数
    memset(pszTmp,0,pszTmpSize);
    memcpy(&pszTmp[cn],&szBuffer[i],itmp);
    cn=cn+itmp;
    while(1)
    {
        memset(szBuffer,0,sizeof(szBuffer));
        ret=0;
        ret=recv(sClient,szBuffer,sizeof(szBuffer)-1,0);
        if(ret==0)
        {
            break;
        }
        memcpy(&pszTmp[cn],szBuffer,ret);
        cn=ret+cn;
    }
    pszTmp[cn]='/0';
//    printf("%s/n",pszTmp);
    ///////////////////////////////////////////////调用数据分析函数
    /*
    memset(pszBuf,0,sizeof(char)*pszTmpSize);
 
    //编号
    sprintf(pszBuf,"%d",id);
    //图书名称<span id="Labelname"></span>
    memset(pszMake,0,sizeof(char)*pszTmpSize);
    GetHTMLData("span","Labelname",pszTmp,pszMake,sizeof(char)*pszTmpSize);
    //printf("%s/n",pszMake);
    strcat(pszBuf,",/"");
    strcat(pszBuf,pszMake);
    strcat(pszBuf,"/"");
     
    //作者<a id="Bookinfomodule1_HyperLinkWriter">这里是作者名</a>
    memset(pszMake,0,sizeof(char)*pszTmpSize);
    GetHTMLData("a","Bookinfomodule1_HyperLinkWriter",
            pszTmp,pszMake,sizeof(char)*pszTmpSize);
    strcat(pszBuf,",/"");
    strcat(pszBuf,pszMake);
    strcat(pszBuf,"/"");
 
    //取出ISBN:<span id="Bookinfomodule1_LabelIsdn">7500666934</span>
    memset(pszMake,0,sizeof(char)*pszTmpSize);
    GetHTMLData("span","Bookinfomodule1_LabelIsdn",
            pszTmp,pszMake,sizeof(char)*pszTmpSize);
    strcat(pszBuf,",/"");
    strcat(pszBuf,pszMake);
    strcat(pszBuf,"/"");
 
    //出版社<a id="Bookinfomodule1_HyperLinkPublishName"></a>
    memset(pszMake,0,sizeof(char)*pszTmpSize);
    GetHTMLData("a","Bookinfomodule1_HyperLinkPublishName",
            pszTmp,pszMake,sizeof(char)*pszTmpSize);
    strcat(pszBuf,",/"");
    strcat(pszBuf,pszMake);
    strcat(pszBuf,"/"");
 
    //原价<span id="Bookinfomodule1_LabelPrice1"></span>
    memset(pszMake,0,sizeof(char)*pszTmpSize);
    GetHTMLData("span","Bookinfomodule1_LabelPrice1",
            pszTmp,pszMake,sizeof(char)*pszTmpSize);
    strcat(pszBuf,",");
    strcat(pszBuf,"/"");
    strcat(pszBuf,&pszMake[2]);//跳过两个字节,美元的符号
    strcat(pszBuf,"/"");
 
    /////////////////////////////////////////内容<span id="LabelDescription"></span>
    memset(pszMake,0,sizeof(char)*pszTmpSize);
    GetHTMLData("span","LabelDescription",
            pszTmp,pszMake,sizeof(char)*pszTmpSize);
    strcat(pszBuf,",/"");
    //////////////////////////去除tmpBuf中的'/r'回车符
    char *t,*t2;
    t=(char*)malloc(sizeof(char)*pszTmpSize);
    t2=(char*)malloc(sizeof(char)*pszTmpSize);
    memcpy(t,pszMake,sizeof(char)*pszTmpSize);
    memset(pszMake,0,sizeof(char)*pszTmpSize);
    for(;;t=NULL)
    {
        if((t2=strtok(t,"/r"))==NULL) break;
        strcat(pszMake,t2);
    }
    free(t);
    free(t2);
    /////////////////////////////去除"/r"结束
     
    //access规则把所有"变成""
    t=(char*)malloc(sizeof(char)*pszTmpSize);
    t2=(char*)malloc(sizeof(char)*pszTmpSize);
    memcpy(t,pszMake,sizeof(char)*pszTmpSize);
    memset(pszMake,0,sizeof(char)*pszTmpSize);
    for(;;t=NULL)
    {
        if((t2=strtok(t,"/""))==NULL) break;
        strcat(pszMake,t2);
        strcat(pszMake,"/"/"");
    }
    pszMake[strlen(pszMake)-strlen("/"/"")]='/0';
    free(t);
    free(t2);
    /////////////////////
 
    strcat(pszBuf,pszMake);
    strcat(pszBuf,"/"");
    ///////////////////////////////////////////////////////////内容完成
    /*
    //////////////////////////////////////////////////////////图片处理部分
    //<img id="Bookimg" src="xxxxxxxx.jpg" />
    memset(pszMake,0,sizeof(char)*pszTmpSize);
    GetImgUrl("Bookimg",pszTmp,pszMake,sizeof(char)*pszTmpSize);
 
    memset(szTmp,0,sizeof(szTmp));
    strcpy(szTmp,URL);
    for(i=strlen(szTmp)-1;i>0;i--)//去除URL后面的/之后的文件名部份
    {
        if(szTmp[i]=='/')
        {
            szTmp[i]='/0';
            break;
        }
    }
    strcat(szTmp,"/");
    pszMake[strlen(pszMake)-1]='/0';//去除双引号
    strcat(szTmp,&pszMake[1]);
    strcpy(pszMake,szTmp);
     
    strcpy(szTmp,&pszMake[strlen(pszMake)-3]);//获取图片的扩展名
    //重新生成图片的名称
    time_t tt;
    struct tm * now;
    tt=time(NULL);
    now=localtime(&tt);
    strftime(szTemp,sizeof(szTemp),"%Y%m%d%H%M%s",now);
    strcat(szTemp,".");
    strcat(szTemp,szTmp);
    strcat(pszBuf,",/"");
    strcat(pszBuf,szTemp);
    strcat(pszBuf,"/"");
 
     
    //从网上下载图片
    //如果图片名是nocover.gif就不下载,这个是没有图片的意思
    if((strstr(pszMake,"nocover.gif"))==NULL)
    {
    if(GetWebImg(pszMake,szTemp)!=0) return -1;
    }
    //printf("%s/n",pszBuf);*/
    ///////////////////////////////////////////////////////////////写到文本文件
     
    if((fp=fopen("data.txt","a"))==NULL)
    {
        printf("打开文件失败!/n");
        return -1;
    }
    fprintf(fp,"%s/n",pszBuf);
    fclose(fp);
    /////////////////////////////////////////////////////////////写文件完成     
    ///////////////////////////////////////////////////获取数据完成
    free(pszMake);
    free(pszTmp);
    closesocket(sClient);
    WSACleanup();
 
    return 0;
}
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值