C++网络爬虫的实现——WinSock编程

来源:互联网 发布:linux 脚本优先级 编辑:程序博客网 时间:2024/04/20 05:52

写了一个网络爬虫,可以抓取网上的图片。

需要给定初始网站即可。

在vs2010中编译通过。

需要使用多字节字符集进行编译,

vs2010默认的是Unicode字符集。

编译后,运行即可,有惊喜哦!!!


爬虫原理

从最开始的网址开始,在其中找到链接到其他网页的超链接,

放到一个网页队列里面保存起来,找到该网页的所有图片,下载下来。


查看网页队列是否为空,不为空则取出下一个网页,

提取该网页的超链接放入队列的后面,下载该网页所有图片。


如此循环往复。


主框架:
void main()
{
//初始化socket,用于tcp网络连接
    WSADATA wsaData;
    if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0 ){
        return;
    }

// 创建文件夹,保存图片和网页文本文件
CreateDirectory( "./img",0);
CreateDirectory("./html",0);
//string urlStart = "http://hao.360.cn/meinvdaohang.html";

// 遍历的起始地址
string urlStart = "http://www.wmpic.me/tupian";

// 使用广度遍历
// 提取网页中的超链接放入hrefUrl中,提取图片链接,下载图片。
BFS( urlStart );

// 访问过的网址保存起来
visitedUrl.insert( urlStart );

while( hrefUrl.size()!=0 ){
string url = hrefUrl.front();  // 从队列的最开始取出一个网址
cout << url << endl;
BFS( url );  // 遍历提取出来的那个网页,找它里面的超链接网页放入hrefUrl,下载它里面的文本,图片
hrefUrl.pop();   // 遍历完之后,删除这个网址
}
    WSACleanup();
    return;
}

    BFS是最重要的处理:

       先是获取网页响应,保存到文本里面,然后找到其中的图片链接HTMLParse
       下载所有图片DownLoadImg

//广度遍历
void BFS( const string & url ){
char * response;
int bytes;
// 获取网页的响应,放入response中。
if( !GetHttpResponse( url, response, bytes ) ){
cout << "The url is wrong! ignore." << endl;
return;
}
string httpResponse=response;
free( response );
string filename = ToFileName( url );
ofstream ofile( "./html/"+filename );
if( ofile.is_open() ){
// 保存该网页的文本内容
ofile << httpResponse << endl;
ofile.close();
}
vector<string> imgurls;
//解析该网页的所有图片链接,放入imgurls里面
HTMLParse( httpResponse,  imgurls, url );
//下载所有的图片资源
DownLoadImg( imgurls, url );
}



附上所有代码:

代码更新于1014-10-15。


[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //#include <Windows.h>  
  2. #include <string>  
  3. #include <iostream>  
  4. #include <fstream>  
  5. #include <vector>  
  6. #include "winsock2.h"  
  7. #include <time.h>  
  8. #include <queue>  
  9. #include <hash_set>  
  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.     if ( strlen(url.c_str()) > 2000 ) {  
  25.         return false;  
  26.     }  
  27.   
  28.     const char * pos = strstr( url.c_str(), "http://" );  
  29.     if( pos==NULL ) pos = url.c_str();  
  30.     else pos += strlen("http://");  
  31.     if( strstr( pos, "/")==0 )  
  32.         return false;  
  33.     char pHost[100];  
  34.     char pResource[2000];  
  35.     sscanf( pos, "%[^/]%s", pHost, pResource );  
  36.     host = pHost;  
  37.     resource = pResource;  
  38.     return true;  
  39. }  
  40.   
  41. //使用Get请求,得到响应  
  42. bool GetHttpResponse( const string & url, char * &response, int &bytesRead ){  
  43.     string host, resource;  
  44.     if(!ParseURL( url, host, resource )){  
  45.         cout << "Can not parse the url"<<endl;  
  46.         return false;  
  47.     }  
  48.       
  49.     //建立socket  
  50.     struct hostent * hp= gethostbyname( host.c_str() );  
  51.     if( hp==NULL ){  
  52.         cout<< "Can not find host address"<<endl;  
  53.         return false;  
  54.     }  
  55.   
  56.     SOCKET sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);  
  57.     if( sock == -1 || sock == -2 ){  
  58.         cout << "Can not create sock."<<endl;  
  59.         return false;  
  60.     }  
  61.   
  62.     //建立服务器地址  
  63.     SOCKADDR_IN sa;  
  64.     sa.sin_family = AF_INET;  
  65.     sa.sin_port = htons( 80 );  
  66.     //char addr[5];  
  67.     //memcpy( addr, hp->h_addr, 4 );  
  68.     //sa.sin_addr.s_addr = inet_addr(hp->h_addr);  
  69.     memcpy( &sa.sin_addr, hp->h_addr, 4 );  
  70.   
  71.     //建立连接  
  72.     if( 0!= connect( sock, (SOCKADDR*)&sa, sizeof(sa) ) ){  
  73.         cout << "Can not connect: "<< url <<endl;  
  74.         closesocket(sock);  
  75.         return false;  
  76.     };  
  77.   
  78.     //准备发送数据  
  79.     string request = "GET " + resource + " HTTP/1.1\r\nHost:" + host + "\r\nConnection:Close\r\n\r\n";  
  80.   
  81.     //发送数据  
  82.     if( SOCKET_ERROR ==send( sock, request.c_str(), request.size(), 0 ) ){  
  83.         cout << "send error" <<endl;  
  84.         closesocket( sock );  
  85.         return false;  
  86.     }  
  87.   
  88.     //接收数据  
  89.     int m_nContentLength = DEFAULT_PAGE_BUF_SIZE;  
  90.     char *pageBuf = (char *)malloc(m_nContentLength);  
  91.     memset(pageBuf, 0, m_nContentLength);  
  92.   
  93.     bytesRead = 0;  
  94.     int ret = 1;  
  95.     cout <<"Read: ";  
  96.     while(ret > 0){  
  97.         ret = recv(sock, pageBuf + bytesRead, m_nContentLength - bytesRead, 0);  
  98.           
  99.         if(ret > 0)  
  100.         {  
  101.             bytesRead += ret;  
  102.         }  
  103.   
  104.         if( m_nContentLength - bytesRead<100){  
  105.             cout << "\nRealloc memorry"<<endl;  
  106.             m_nContentLength *=2;  
  107.             pageBuf = (char*)realloc( pageBuf, m_nContentLength);       //重新分配内存  
  108.         }  
  109.         cout << ret <<" ";  
  110.     }  
  111.     cout <<endl;  
  112.   
  113.     pageBuf[bytesRead] = '\0';  
  114.     response = pageBuf;  
  115.     closesocket( sock );  
  116.     return true;  
  117.     //cout<< response <<endl;  
  118. }  
  119.   
  120. //提取所有的URL以及图片URL  
  121. void HTMLParse ( string & htmlResponse, vector<string> & imgurls, const string & host ){  
  122.     //找所有连接,加入queue中  
  123.     const char *p= htmlResponse.c_str();  
  124.     char *tag="href=\"";  
  125.     const char *pos = strstr( p, tag );  
  126.     ofstream ofile("url.txt", ios::app);  
  127.     while( pos ){  
  128.         pos +=strlen(tag);  
  129.         const char * nextQ = strstr( pos, "\"" );  
  130.         if( nextQ ){  
  131.             char * url = new char[ nextQ-pos+1 ];  
  132.             //char url[100]; //固定大小的会发生缓冲区溢出的危险  
  133.             sscanf( pos, "%[^\"]", url);  
  134.             string surl = url;  // 转换成string类型,可以自动释放内存  
  135.             if( visitedUrl.find( surl ) == visitedUrl.end() ){  
  136.                 visitedUrl.insert( surl );  
  137.                 ofile << surl<<endl;  
  138.                 hrefUrl.push( surl );  
  139.             }  
  140.             pos = strstr(pos, tag );  
  141.             delete [] url;  // 释放掉申请的内存  
  142.         }  
  143.     }  
  144.     ofile << endl << endl;  
  145.     ofile.close();  
  146.   
  147.     tag ="<img ";  
  148.     const char* att1= "src=\"";  
  149.     const char* att2="lazy-src=\"";  
  150.     const char *pos0 = strstr( p, tag );  
  151.     while( pos0 ){  
  152.         pos0 += strlen( tag );  
  153.         const char* pos2 = strstr( pos0, att2 );  
  154.         if( !pos2 || pos2 > strstr( pos0, ">") ) {  
  155.             pos = strstr( pos0, att1);  
  156.             if(!pos) {  
  157.                 pos0 = strstr(att1, tag );  
  158.             continue;  
  159.             } else {  
  160.                 pos = pos + strlen(att1);  
  161.             }  
  162.         }  
  163.         else {  
  164.             pos = pos2 + strlen(att2);  
  165.         }  
  166.   
  167.         const char * nextQ = strstr( pos, "\"");  
  168.         if( nextQ ){  
  169.             char * url = new char[nextQ-pos+1];  
  170.             sscanf( pos, "%[^\"]", url);  
  171.             cout << url<<endl;  
  172.             string imgUrl = url;  
  173.             if( visitedImg.find( imgUrl ) == visitedImg.end() ){  
  174.                 visitedImg.insert( imgUrl );  
  175.                 imgurls.push_back( imgUrl );  
  176.             }  
  177.             pos0 = strstr(pos0, tag );  
  178.             delete [] url;  
  179.         }  
  180.     }  
  181.     cout << "end of Parse this html"<<endl;  
  182. }  
  183.   
  184. //把URL转化为文件名  
  185. string ToFileName( const string &url ){  
  186.     string fileName;  
  187.     fileName.resize( url.size());  
  188.     int k=0;  
  189.     forint i=0; i<(int)url.size(); i++){  
  190.         char ch = url[i];  
  191.         if( ch!='\\'&&ch!='/'&&ch!=':'&&ch!='*'&&ch!='?'&&ch!='"'&&ch!='<'&&ch!='>'&&ch!='|')  
  192.             fileName[k++]=ch;  
  193.     }  
  194.     return fileName.substr(0,k) + ".txt";  
  195. }  
  196.   
  197. //下载图片到img文件夹  
  198. void DownLoadImg( vector<string> & imgurls, const string &url ){  
  199.   
  200.     //生成保存该url下图片的文件夹  
  201.     string foldname = ToFileName( url );  
  202.     foldname = "./img/"+foldname;  
  203.     if(!CreateDirectory( foldname.c_str(),NULL ))  
  204.         cout << "Can not create directory:"<< foldname<<endl;  
  205.     char *image;  
  206.     int byteRead;  
  207.     forint i=0; i<imgurls.size(); i++){  
  208.         //判断是否为图片,bmp,jgp,jpeg,gif   
  209.         string str = imgurls[i];  
  210.         int pos = str.find_last_of(".");  
  211.         if( pos == string::npos )  
  212.             continue;  
  213.         else{  
  214.             string ext = str.substr( pos+1, str.size()-pos-1 );  
  215.             if( ext!="bmp"&& ext!="jpg" && ext!="jpeg"&& ext!="gif"&&ext!="png")  
  216.                 continue;  
  217.         }  
  218.         //下载其中的内容  
  219.         if( GetHttpResponse(imgurls[i], image, byteRead)){  
  220.             if ( strlen(image) ==0 ) {  
  221.                 continue;  
  222.             }  
  223.             const char *p=image;  
  224.             const char * pos = strstr(p,"\r\n\r\n")+strlen("\r\n\r\n");  
  225.             int index = imgurls[i].find_last_of("/");  
  226.             if( index!=string::npos ){  
  227.                 string imgname = imgurls[i].substr( index , imgurls[i].size() );  
  228.                 ofstream ofile( foldname+imgname, ios::binary );  
  229.                 if( !ofile.is_open() )  
  230.                     continue;  
  231.                 cout <<g_ImgCnt++<< foldname+imgname<<endl;  
  232.                 ofile.write( pos, byteRead- (pos-p) );  
  233.                 ofile.close();  
  234.             }  
  235.             free(image);  
  236.         }  
  237.     }  
  238. }  
  239.   
  240.   
  241.   
  242. //广度遍历  
  243. void BFS( const string & url ){  
  244.     char * response;  
  245.     int bytes;  
  246.     // 获取网页的相应,放入response中。  
  247.     if( !GetHttpResponse( url, response, bytes ) ){  
  248.         cout << "The url is wrong! ignore." << endl;  
  249.         return;  
  250.     }  
  251.     string httpResponse=response;  
  252.     free( response );  
  253.     string filename = ToFileName( url );  
  254.     ofstream ofile( "./html/"+filename );  
  255.     if( ofile.is_open() ){  
  256.         // 保存该网页的文本内容  
  257.         ofile << httpResponse << endl;  
  258.         ofile.close();  
  259.     }  
  260.     vector<string> imgurls;  
  261.     //解析该网页的所有图片链接,放入imgurls里面  
  262.     HTMLParse( httpResponse,  imgurls, url );  
  263.       
  264.     //下载所有的图片资源  
  265.     DownLoadImg( imgurls, url );  
  266. }  
  267.   
  268. void main()  
  269. {  
  270.     //初始化socket,用于tcp网络连接  
  271.     WSADATA wsaData;  
  272.     if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0 ){  
  273.         return;  
  274.     }  
  275.   
  276.     // 创建文件夹,保存图片和网页文本文件  
  277.     CreateDirectory( "./img",0);  
  278.     CreateDirectory("./html",0);  
  279.     //string urlStart = "http://hao.360.cn/meinvdaohang.html";  
  280.   
  281.     // 遍历的起始地址  
  282.     // string urlStart = "http://www.wmpic.me/tupian";  
  283.     string urlStart = "http://item.taobao.com/item.htm?spm=a230r.1.14.19.sBBNbz&id=36366887850&ns=1#detail";  
  284.       
  285.     // 使用广度遍历  
  286.     // 提取网页中的超链接放入hrefUrl中,提取图片链接,下载图片。  
  287.     BFS( urlStart );  
  288.   
  289.     // 访问过的网址保存起来  
  290.     visitedUrl.insert( urlStart );  
  291.   
  292.     while( hrefUrl.size()!=0 ){  
  293.         string url = hrefUrl.front();  // 从队列的最开始取出一个网址  
  294.         cout << url << endl;  
  295.         BFS( url );                   // 遍历提取出来的那个网页,找它里面的超链接网页放入hrefUrl,下载它里面的文本,图片  
  296.         hrefUrl.pop();                 // 遍历完之后,删除这个网址  
  297.     }  
  298.     WSACleanup();  
  299.     return;  
  300. }  
0 0
原创粉丝点击