网络爬虫实现

来源http://blog.csdn.net/huangxy10/article/details/8120106

  1. #include <string>  
  2. #include <iostream>  
  3. #include <fstream>  
  4. #include <vector>  
  5. #include "winsock2.h"  
  6. #include <time.h>  
  7. #include <queue>  
  8. #include <hash_set>  
  9.   
  10.   
  11. #pragma comment(lib, "ws2_32.lib")   
  12. using namespace std;  
  13.   
  14. #define DEFAULT_PAGE_BUF_SIZE 1048576  
  15.   
  16. queue<string> hrefUrl;  
  17. hash_set<string> visitedUrl;  
  18. hash_set<string> visitedImg;  
  19. int depth=0;  
  20. int g_ImgCnt=1;  
  21.   
  22. //解析URL,解析出主机名,资源名  
  23. bool ParseURL( const string & url, string & host, string & resource){  
  24.     const char * pos = strstr( url.c_str(), "http://" );  
  25.     if( pos==NULL ) pos = url.c_str();  
  26.     else pos += strlen("http://");  
  27.     if( strstr( pos, "/")==0 )  
  28.         return false;  
  29.     char pHost[100];  
  30.     char pResource[200];  
  31.     sscanf( pos, "%[^/]%s", pHost, pResource );  
  32.     host = pHost;  
  33.     resource = pResource;  
  34.     return true;  
  35. }  
  36.   
  37. //使用Get请求,得到响应  
  38. bool GetHttpResponse( const string & url, char * &response, int &bytesRead ){  
  39.     string host, resource;  
  40.     if(!ParseURL( url, host, resource )){  
  41.         cout << "Can not parse the url"<<endl;  
  42.         return false;  
  43.     }  
  44.       
  45.     //建立socket  
  46.     struct hostent * hp= gethostbyname( host.c_str() );  
  47.     if( hp==NULL ){  
  48.         cout<< "Can not find host address"<<endl;  
  49.         return false;  
  50.     }  
  51.   
  52.     SOCKET sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);  
  53.     if( sock == -1 || sock == -2 ){  
  54.         cout << "Can not create sock."<<endl;  
  55.         return false;  
  56.     }  
  57.   
  58.     //建立服务器地址  
  59.     SOCKADDR_IN sa;  
  60.     sa.sin_family = AF_INET;  
  61.     sa.sin_port = htons( 80 );  
  62.     //char addr[5];  
  63.     //memcpy( addr, hp->h_addr, 4 );  
  64.     //sa.sin_addr.s_addr = inet_addr(hp->h_addr);  
  65.     memcpy( &sa.sin_addr, hp->h_addr, 4 );  
  66.   
  67.     //建立连接  
  68.     if( 0!= connect( sock, (SOCKADDR*)&sa, sizeof(sa) ) ){  
  69.         cout << "Can not connect: "<< url <<endl;  
  70.         closesocket(sock);  
  71.         return false;  
  72.     };  
  73.   
  74.     //准备发送数据  
  75.     string request = "GET " + resource + " HTTP/1.1\r\nHost:" + host + "\r\nConnection:Close\r\n\r\n";  
  76.   
  77.     //发送数据  
  78.     if( SOCKET_ERROR ==send( sock, request.c_str(), request.size(), 0 ) ){  
  79.         cout << "send error" <<endl;  
  80.         closesocket( sock );  
  81.         return false;  
  82.     }  
  83.   
  84.     //接收数据  
  85.     int m_nContentLength = DEFAULT_PAGE_BUF_SIZE;  
  86.     char *pageBuf = (char *)malloc(m_nContentLength);  
  87.     memset(pageBuf, 0, m_nContentLength);  
  88.   
  89.     bytesRead = 0;  
  90.     int ret = 1;  
  91.     cout <<"Read: ";  
  92.     while(ret > 0){  
  93.         ret = recv(sock, pageBuf + bytesRead, m_nContentLength - bytesRead, 0);  
  94.           
  95.         if(ret > 0)  
  96.         {  
  97.             bytesRead += ret;  
  98.         }  
  99.   
  100.         if( m_nContentLength - bytesRead<100){  
  101.             cout << "\nRealloc memorry"<<endl;  
  102.             m_nContentLength *=2;  
  103.             pageBuf = (char*)realloc( pageBuf, m_nContentLength);       //重新分配内存  
  104.         }  
  105.         cout << ret <<" ";  
  106.     }  
  107.     cout <<endl;  
  108.   
  109.     pageBuf[bytesRead] = '\0';  
  110.     response = pageBuf;  
  111.     closesocket( sock );  
  112.     return true;  
  113.     //cout<< response <<endl;  
  114. }  
  115. //提取所有的URL以及图片URL  
  116. void HTMLParse ( string & htmlResponse, vector<string> & imgurls, const string & host ){  
  117.     //找所有连接,加入queue中  
  118.     const char *p= htmlResponse.c_str();  
  119.     char *tag="href=\"";  
  120.     const char *pos = strstr( p, tag );  
  121.     ofstream ofile("url.txt", ios::app);  
  122.     while( pos ){  
  123.         pos +=strlen(tag);  
  124.         const char * nextQ = strstr( pos, "\"" );  
  125.         if( nextQ ){  
  126.             char * url = new char[ nextQ-pos+1 ];  
  127.             //char url[100]; //固定大小的会发生缓冲区溢出的危险  
  128.             sscanf( pos, "%[^\"]", url);  
  129.             string surl = url;  
  130.             if( visitedUrl.find( surl ) == visitedUrl.end() ){  
  131.                 visitedUrl.insert( surl );  
  132.                 ofile << surl<<endl;  
  133.                 hrefUrl.push( surl );  
  134.             }  
  135.             pos = strstr(pos, tag );  
  136.             delete [] url;  
  137.         }  
  138.     }  
  139.     ofile << endl << endl;  
  140.     ofile.close();  
  141.   
  142.     tag ="<img ";  
  143.     const char* att1= "src=\"";  
  144.     const char* att2="lazy-src=\"";  
  145.     const char *pos0 = strstr( p, tag );  
  146.     while( pos0 ){  
  147.         pos0 += strlen( tag );  
  148.         const char* pos2 = strstr( pos0, att2 );  
  149.         if( !pos2 || pos2 > strstr( pos0, ">") )  
  150.             pos = strstr( pos0, att1)+strlen(att1);  
  151.         else  
  152.             pos = pos2 + strlen(att2);  
  153.         const char * nextQ = strstr( pos, "\"");  
  154.         if( nextQ ){  
  155.             char * url = new char[nextQ-pos+1];  
  156.             sscanf( pos, "%[^\"]", url);  
  157.             cout << url<<endl;  
  158.             string imgUrl = url;  
  159.             if( visitedImg.find( imgUrl ) == visitedImg.end() ){  
  160.                 visitedImg.insert( imgUrl );  
  161.                 imgurls.push_back( imgUrl );  
  162.             }  
  163.             pos0 = strstr(pos0, tag );  
  164.             delete [] url;  
  165.         }  
  166.     }  
  167.     cout << "end of Parse this html"<<endl;  
  168. }  
  169.   
  170. //把URL转化为文件名  
  171. string ToFileName( const string &url ){  
  172.     string fileName;  
  173.     fileName.resize( url.size());  
  174.     int k=0;  
  175.     forint i=0; i<(int)url.size(); i++){  
  176.         char ch = url[i];  
  177.         if( ch!='\\'&&ch!='/'&&ch!=':'&&ch!='*'&&ch!='?'&&ch!='"'&&ch!='<'&&ch!='>'&&ch!='|')  
  178.             fileName[k++]=ch;  
  179.     }  
  180.     return fileName.substr(0,k) + ".txt";  
  181. }  
  182.   
  183. //下载图片到img文件夹  
  184. void DownLoadImg( vector<string> & imgurls, const string &url ){  
  185.   
  186.     //生成保存该url下图片的文件夹  
  187.     string foldname = ToFileName( url );  
  188.     foldname = "./img/"+foldname;  
  189.     if(!CreateDirectory( foldname.c_str(),NULL ))  
  190.         cout << "Can not create directory:"<< foldname<<endl;  
  191.     char *image;  
  192.     int byteRead;  
  193.     forint i=0; i<imgurls.size(); i++){  
  194.         //判断是否为图片,bmp,jgp,jpeg,gif   
  195.         string str = imgurls[i];  
  196.         int pos = str.find_last_of(".");  
  197.         if( pos == string::npos )  
  198.             continue;  
  199.         else{  
  200.             string ext = str.substr( pos+1, str.size()-pos-1 );  
  201.             if( ext!="bmp"&& ext!="jpg" && ext!="jpeg"&& ext!="gif"&&ext!="png")  
  202.                 continue;  
  203.         }  
  204.         //下载其中的内容  
  205.         if( GetHttpResponse(imgurls[i], image, byteRead)){  
  206.             const char *p=image;  
  207.             const char * pos = strstr(p,"\r\n\r\n")+strlen("\r\n\r\n");  
  208.             int index = imgurls[i].find_last_of("/");  
  209.             if( index!=string::npos ){  
  210.                 string imgname = imgurls[i].substr( index , imgurls[i].size() );  
  211.                 ofstream ofile( foldname+imgname, ios::binary );  
  212.                 if( !ofile.is_open() )  
  213.                     continue;  
  214.                 cout <<g_ImgCnt++<< foldname+imgname<<endl;  
  215.                 ofile.write( pos, byteRead- (pos-p) );  
  216.                 ofile.close();  
  217.             }  
  218.             free(image);  
  219.         }  
  220.     }  
  221. }  
  222.   
  223.   
  224.   
  225. //广度遍历  
  226. void BFS( const string & url ){  
  227.     char * response;  
  228.     int bytes;  
  229.     if( !GetHttpResponse( url, response, bytes ) ){  
  230.         cout << "The url is wrong! ignore." << endl;  
  231.         return;  
  232.     }  
  233.     string httpResponse=response;  
  234.     free( response );  
  235.     string filename = ToFileName( url );  
  236.     ofstream ofile( "./html/"+filename );  
  237.     if( ofile.is_open() ){  
  238.         ofile << httpResponse << endl;  
  239.         ofile.close();  
  240.     }  
  241.     vector<string> imgurls;  
  242.     HTMLParse( httpResponse,  imgurls, url );  
  243.       
  244.     //下载图片资源  
  245.     DownLoadImg( imgurls, url );  
  246. }  
  247. void main()  
  248. {  
  249.     WSADATA wsaData;  
  250.     if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0 ){  
  251.         return;  
  252.     }  
  253.     CreateDirectory( "./img",0);  
  254.     CreateDirectory("./html",0);  
  255.     //string urlStart = "http://hao.360.cn/meinvdaohang.html";  
  256.     string urlStart = "http://hao.360.cn/meinvdaohang.html";  
  257.     BFS( urlStart );  
  258.     visitedUrl.insert( urlStart );  
  259.     while( hrefUrl.size()!=0 ){  
  260.         string url = hrefUrl.front();  
  261.         cout << url << endl;  
  262.         BFS( url );  
  263.         hrefUrl.pop();  
  264.     }  
  265.     WSACleanup();  
  266.     return;  
  267. }  

你可能感兴趣的:(网络爬虫)