• Socket网络编程--网络爬虫(4)


      上一小节我们已经实现了获取博客园最近博客的200页里面的用户名,并保存在一个map中。一开始是想通过这个用户名然后构造一个博客地址。然后在这个地址中查找心得用户名,但是后来发现这个的效率不是很高,虽然部分博客会引用别人的博客,也有机率会留有原博客的地址,这样我们可以爬取的到新的用户名。效率是不高。最后我发现博客园的关注和粉丝这个功能用于查找心得用户名很管用。只要该用户在博客园活跃过一段时间就或多或少会有粉丝或关注过某人。(不是有个说法:通过7个人能认识世界上任意一个人)所以这种做法应该是可行的。下面送上一张一开始就画好的框架。有些可能最后的实现跟图中不是很相同。

      理论上这样是可以获取得到,但是在实践的时候才知道,原来没有登录的用户是访问不了别人的粉丝和关注,没想到这个美好的想法就这样没了。这可怎么办呢?(如果有知道的还请告诉我呀。)

      由于种种原因,最后是实现不了这种循环爬取的效果了。都怪写之前没有好好试验一下,也可能是可以完成,只是自己太弱的原因了。只能提供几个可以获取的用户名的地址。因为达不到那种迭代的效果我就不写。真是太不好意思了。(http://www.cnblogs.com/cate/all/1 ~ http://www.cnblogs.com/cate/all/200、http://www.cnblogs.com/comment/1 ~ http://www.cnblogs.com/comment/200)

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <sys/types.h>
      5 #include <sys/socket.h>
      6 #include <unistd.h>
      7 #include <netdb.h>
      8 #include <netinet/in.h>
      9 #include <arpa/inet.h>
     10 #include <regex.h>//正则表达式
     11 #include <map>
     12 #include <queue>
     13 #include <string>
     14 #include <iostream>
     15 
     16 using namespace std;
     17 #define BUF_SIZE 512
     18 
     19 struct URL
     20 {
     21     char host[64];
     22     char url[128];//除去域名后的url
     23 };
     24 int reptile_regex(char * buf,char *pattern,map<string,int> & user);
     25 int createSocket(char *hostname,int port);
     26 int closeSocket(int sockfd);
     27 int sendHttpRequest(int sockfd,struct URL url);
     28 int recvHttpRespond(int sockfd,char *ch);
     29 int reptile_regex_url(char * buf,char *pattern,map<string,int> & user,queue<string> & qstr,int start);
     30 
     31 
     32 int main(int argc,char *argv[])
     33 {
     34     int sockfd;
     35     char ch[100000];//100k
     36     char pattern_user[128]={0};
     37     char pattern_url[128]={0};
     38     struct URL url;
     39     string str;
     40     map<string,int> user;//第一个是用户名,第二个保存被加入的次数
     41     queue<struct URL> qurl;
     42     queue<string> qstr;
     43 
     44     //http://www.cnblogs.com/sitehome/p/1 - 200 //最新博客的200篇
     45     //初始化用户名
     46     for(int i=1;i<=200;++i)
     47     {
     48         strcpy(url.host,"www.cnblogs.com");
     49         strcpy(url.url,"/sitehome/p/");
     50         char pch[8];
     51         sprintf(pch,"%d",i);
     52         strcat(url.url,pch);
     53         strcat(url.url,"/");
     54         cout<<"当前正在判断:"<<url.host<<url.url<<endl;
     55         sockfd=createSocket(url.host,80);
     56         sendHttpRequest(sockfd,url);
     57         recvHttpRespond(sockfd,ch);
     58         strcpy(pattern_user,"http://www.cnblogs.com/[[:alnum:][:cntrl:]\-\_]*");
     59         reptile_regex_url(ch,pattern_user,user,qstr,23);
     60 
     61         closeSocket(sockfd);
     62     }
     63     //一开始以为是只要创建一次socket然后每次都可以进行send&recv的。但是后来测试好像不行,每次都要进行一次socket的创建
     64     while(1)
     65     {
     66         while(!qstr.empty())
     67         {
     68             //构造用户的粉丝地址和关注地址
     69             strcpy(url.host,"home.cnblogs.com");
     70             strcpy(url.url,"/u/");
     71             strcat(url.url,qstr.front().c_str());
     72             qurl.push(url);//加入粉丝/关注地址
     73             cout<<"粉丝/关注地址:"<<url.host<<url.url<<endl;
     74             qstr.pop();
     75         }
     76         while(!qurl.empty())
     77         {
     78             url=qurl.front();
     79             qurl.pop();
     80             cout<<"现在正在判断:";
     81             cout<<url.host<<url.url<<endl;
     82             //将获取到的地址进行再次获取用户名
     83             sockfd=createSocket(url.host,80);
     84             sendHttpRequest(sockfd,url);
     85             recvHttpRespond(sockfd,ch);
     86             //查看源代码发现地址居然不是想象中的http://home.cnblogs.com/u/用户名,而是/u/用户名
     87             strcpy(pattern_user,"/u/[[:alnum:][:cntrl:]\-\_]*");
     88             reptile_regex_url(ch,pattern_user,user,qstr,3);
     89             closeSocket(sockfd);
     90         }
     91     }
     92     return 0;
     93 }
     94 
     95 
     96 //第一个参数是要匹配的字符串,第二个参数是匹配的规则
     97 int reptile_regex_url(char * buf,char *pattern,map<string,int> & user,queue<string> & qstr,int start)
     98 {
     99     size_t nmatch=10;
    100     regmatch_t pm[10];
    101     regex_t reg;//正则表达式指针
    102     char * str;
    103     char ch[32];
    104     int i,j,k;
    105     str=buf;
    106     regcomp(&reg,pattern,REG_EXTENDED);//编译匹配模式
    107     while(regexec(&reg,str,nmatch,pm,0)!=REG_NOMATCH)
    108     {
    109         i=pm[0].rm_so+start;
    110         k=0;
    111         memset(ch,0,sizeof(ch));
    112         for(j=i;j<pm[0].rm_eo;++j)
    113         {
    114             if(str[j]!=0x01) //ctrl-v ctrl-a
    115             {
    116                 ch[k++]=str[j];
    117             }
    118         }
    119         string st(ch);
    120         if(user[st]==0)
    121         {
    122             cout<<"新加入的用户名:"<<st<<endl;
    123             qstr.push(st);
    124         }
    125         user[st]++;
    126         str=str+pm[0].rm_eo;
    127     }
    128     regfree(&reg);
    129     return 0;
    130 }
    131 
    132 int closeSocket(int sockfd)
    133 {
    134     close(sockfd);
    135     return 0;
    136 }
    137 
    138 int createSocket(char *hostname,int port)
    139 {
    140     struct sockaddr_in servAddr;
    141     struct hostent * host;
    142     int sockfd;
    143     host=gethostbyname(hostname);
    144     if(host==NULL)
    145     {
    146         perror("dns 解析失败");
    147     }
    148     servAddr.sin_family=AF_INET;
    149     servAddr.sin_addr=*((struct in_addr *)host->h_addr);
    150     servAddr.sin_port=htons(port);
    151     bzero(&(servAddr.sin_zero),8);
    152 
    153     sockfd=socket(AF_INET,SOCK_STREAM,0);
    154     if(sockfd==-1)
    155     {
    156         perror("socket 创建失败");
    157     }
    158 
    159     if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))==-1)
    160     {
    161         perror("connect 失败");
    162     }
    163     return sockfd;
    164 }
    165 
    166 int sendHttpRequest(int sockfd,struct URL url)
    167 {
    168     char sendBuf[BUF_SIZE];
    169     int sendSize;
    170     //构建一个http请求
    171     sprintf(sendBuf,"GET %s HTTP/1.1 
    Host: %s 
    Connection: Close 
    
    ",url.url,url.host);
    172     printf("%s
    ",sendBuf);
    173     if((sendSize=send(sockfd,sendBuf,BUF_SIZE,0))==-1)
    174     {
    175         perror("send 失败");
    176     }
    177     return 0;
    178 }
    179 
    180 int recvHttpRespond(int sockfd,char *ch)
    181 {
    182     char recvBuf[BUF_SIZE];
    183     int recvSize;
    184     //获取http应答信息
    185     memset(recvBuf,0,sizeof(recvBuf));
    186     memset(ch,0,sizeof(ch));
    187     while(recvSize=recv(sockfd,recvBuf,BUF_SIZE,0)>0)
    188     {
    189         recvBuf[recvSize-2]=0;
    190         strcat(ch,recvBuf);
    191         memset(recvBuf,0,sizeof(recvBuf));
    192     }
    193     return 0;
    194 }
    View Code

      ========2014年9月2日更新===========

      今天找到一个解决的办法了。原来是使用cookie来解决,就是在一个请求头Header中增加一个Cookie端,具体的实现思路可以参考这篇博客: http://www.cnblogs.com/fengfenggirl/p/zhihu_shenhuifu.html 在这里先记录下来,下次如果要实现就可以参照这个思路了。

      本文地址: http://www.cnblogs.com/wunaozai/p/3903545.html

  • 相关阅读:
    STM32F107的DAC配置
    步进电机工作原理
    winform笔记本蓝牙与外部蓝牙设备通信
    C#里三种强制类型转换
    IE6/7BUG之OL有序列表没顺序
    IE6/7BUG之列表UL楼梯
    IE6/7BUG之A超链接无效
    IE6/7BUG之overflow:hidden无效
    linux shell 管道命令(pipe)使用及与shell重定向区别
    UGUI研究院之全面理解图集与使用
  • 原文地址:https://www.cnblogs.com/wunaozai/p/3903545.html
Copyright © 2020-2023  润新知