手把手教你写基于C++ Winsock的图片下载的网络爬虫

来源:互联网 发布:扫地僧 程序员 编辑:程序博客网 时间:2024/05/18 01:32

转载连接:http://blog.csdn.net/nk_test/article/details/48277263

先来说一下主要的技术点:

1. 输入起始网址,使用ssacnf函数解析出主机号和路径(仅处理http协议网址)

2. 使用socket套接字连接服务器,,获取网页html代码(使用http协议的GET请求),然后使用正则表达式解析出图片url和其他的url

3. 下载图片至创建的文件夹中,同时其他的url push进队列。

4. 为了使爬虫能够连续的工作,这里使用了BFS宽度优先搜索,也就是说一开始输入的网址作为起始网址,push进队列,然后把能解析出来的网址在不重复的情况下都push进队列,每次取队列的top来执行下载操作,直到队列为空时终止。

下面附上技术点的学习资料供参考:

ssanf函数的用法:

http://www.cnblogs.com/mycapple/archive/2012/08/03/2621681.html

C++11正则表达式

http://blog.sina.com.cn/s/blog_ac9fdc0b0101oow9.html

http协议:

http://www.ucai.cn/course/show/234

Socket编程:

http://blog.csdn.net/nk_test/article/details/47756381

http://blog.csdn.net/nk_test/article/details/47733307

另外,这个小爬虫结构简陋,还存在很多不足,例如队列中的url太多会爆内存,正则表达式匹配不够准确等,仅仅适合大家学习的时候练手哈。也欢迎大家发现bug,给出好的建议。

 

[cpp] view plain copy
  1. /*下载图片 C++ Winsock 网络编程*/  
  2. #define _CRT_SECURE_NO_WARNINGS   //vs 2013用于忽略c语言安全性警告  
  3. #include <cstdio>  
  4. #include <iostream>  
  5. #include <fstream>  
  6. #include <string>  
  7. #include <cstring>  
  8. #include <regex>  
  9. #include <vector>  
  10. #include <queue>  
  11. #include <algorithm>  
  12. #include <winsock2.h>  
  13. #include <map>  
  14. using namespace std;  
  15. #pragma comment(lib, "ws2_32.lib")  
  16. char  host[500];  
  17. int num = 1;  
  18. char othPath[800];  
  19. string allHtml;  
  20. vector <string> photoUrl;  
  21. vector <string> comUrl;  
  22. map <string, int> mp; //防止相同网址重复遍历  
  23. SOCKET sock;  
  24. bool analyUrl(char *url) //仅支持http协议,解析出主机和IP地址  
  25. {  
  26.     char *pos = strstr(url, "http://");  
  27.     if (pos == NULL)  
  28.         return false;  
  29.     else  
  30.         pos += 7;  
  31.     sscanf(pos, "%[^/]%s", host, othPath);   //http:// 后一直到/之前的是主机名  
  32.     cout << "host: " << host << "   repath:" << othPath << endl;  
  33.     return true;  
  34. }  
  35.   
  36.   
  37. void regexGetimage(string &allHtml)  //C++11 正则表达式提取图片url  
  38. {  
  39.     smatch mat;  
  40.     regex pattern("src=\"(.*?\.jpg)\"");  
  41.     string::const_iterator start = allHtml.begin();  
  42.     string::const_iterator end = allHtml.end();  
  43.     while (regex_search(start, end, mat, pattern))  
  44.     {  
  45.         string msg(mat[1].first, mat[1].second);  
  46.         photoUrl.push_back(msg);  
  47.         start = mat[0].second;  
  48.     }  
  49. }  
  50.   
  51. void regexGetcom(string &allHtml) //提取网页中的http://的url  
  52. {  
  53.     smatch mat;  
  54.     //regex pattern("href=\"(.*?\.html)\"");  
  55.     regex pattern("href=\"(http://[^\s'\"]+)\"");  
  56.     string::const_iterator start = allHtml.begin();  
  57.     string::const_iterator end = allHtml.end();  
  58.     while (regex_search(start, end, mat, pattern))  
  59.     {  
  60.         string msg(mat[1].first, mat[1].second);  
  61.         comUrl.push_back(msg);  
  62.         start = mat[0].second;  
  63.     }  
  64. }  
  65. void preConnect()  //socket进行网络连接  
  66. {  
  67.     WSADATA wd;  
  68.     WSAStartup(MAKEWORD(2, 2), &wd);  
  69.     sock = socket(AF_INET, SOCK_STREAM, 0);  
  70.     if (sock == INVALID_SOCKET)  
  71.     {  
  72.         cout << "建立socket失败! 错误码: " << WSAGetLastError() << endl;  
  73.         return;  
  74.     }  
  75.     sockaddr_in sa = { AF_INET };  
  76.     int n = bind(sock, (sockaddr*)&sa, sizeof(sa));  
  77.     if (n == SOCKET_ERROR)  
  78.     {  
  79.         cout << "bind函数失败! 错误码: " << WSAGetLastError() << endl;  
  80.         return;  
  81.     }  
  82.     struct hostent  *p = gethostbyname(host);  
  83.     if (p == NULL)  
  84.     {  
  85.         cout << "主机无法解析出ip! 错误吗: " << WSAGetLastError() << endl;  
  86.         return;  
  87.     }  
  88.     sa.sin_port = htons(80);  
  89.     memcpy(&sa.sin_addr, p->h_addr, 4);//   with some problems ???  
  90.     //sa.sin_addr.S_un.S_addr = inet_addr(*(p->h_addr_list));  
  91.     //cout << *(p->h_addr_list) << endl;  
  92.     n = connect(sock, (sockaddr*)&sa, sizeof(sa));  
  93.     if (n == SOCKET_ERROR)  
  94.     {  
  95.         cout << "connect函数失败! 错误码: " << WSAGetLastError() << endl;  
  96.         return;  
  97.     }  
  98.     //像服务器发送GET请求,下载图片  
  99.     string  reqInfo = "GET " +(string)othPath+ " HTTP/1.1\r\nHost: " + (string)host + "\r\nConnection:Close\r\n\r\n";  
  100.     if (SOCKET_ERROR == send(sock, reqInfo.c_str(), reqInfo.size(), 0))  
  101.     {  
  102.         cout << "send error! 错误码: " << WSAGetLastError() << endl;  
  103.         closesocket(sock);  
  104.         return;  
  105.     }  
  106.     //PutImagtoSet();  
  107.       
  108. }  
  109.   
  110. void OutIamge(string imageUrl) //将图片命名,保存在目录下  
  111. {  
  112.     int n;  
  113.     char temp[800];  
  114.     strcpy(temp, imageUrl.c_str());  
  115.     analyUrl(temp);  
  116.     preConnect();  
  117.     string photoname;  
  118.     photoname.resize(imageUrl.size());  
  119.     int k = 0;  
  120.     for (int i = 0; i<imageUrl.length(); i++){  
  121.         char ch = imageUrl[i];  
  122.         if (ch != '\\'&&ch != '/'&&ch != ':'&&ch != '*'&&ch != '?'&&ch != '"'&&ch != '<'&&ch != '>'&&ch != '|')  
  123.             photoname[k++] = ch;  
  124.     }  
  125.     photoname = "./img/"+photoname.substr(0, k) + ".jpg";  
  126.   
  127.     fstream file;  
  128.     file.open(photoname, ios::out | ios::binary);  
  129.     char buf[1024];  
  130.     memset(buf, 0, sizeof(buf));  
  131.     n = recv(sock, buf, sizeof(buf)-1, 0);  
  132.     char *cpos = strstr(buf, "\r\n\r\n");  
  133.   
  134.     //allHtml = "";  
  135.     //allHtml += string(cpos);  
  136.     file.write(cpos + strlen("\r\n\r\n"), n - (cpos - buf) - strlen("\r\n\r\n"));  
  137.     while ((n = recv(sock, buf, sizeof(buf)-1, 0)) > 0)  
  138.     {  
  139.         file.write(buf, n);  
  140.         //buf[n] = '\0';  
  141.         //allHtml += string(buf);  
  142.     }  
  143.     //file.write(allHtml.c_str(), allHtml.length());  
  144.     file.close();  
  145.     //closesocket(sock);  
  146. }  
  147. void PutImagtoSet()  //解析整个html代码  
  148. {  
  149.     int n;  
  150.     //preConnect();  
  151.     char buf[1024];  
  152.     while ((n = recv(sock, buf, sizeof(buf)-1, 0)) > 0)  
  153.     {  
  154.         buf[n] = '\0';  
  155.         allHtml += string(buf);  
  156.     }  
  157.     regexGetimage(allHtml);  
  158.     regexGetcom(allHtml);  
  159. }  
  160.   
  161.   
  162. void bfs(string beginUrl)  //宽度优先搜索,像爬虫一样遍历网页  
  163. {  
  164.     queue<string> q;  
  165.     q.push(beginUrl);  
  166.     while (!q.empty())  
  167.     {  
  168.         string cur = q.front();  
  169.         mp[cur]++;  
  170.         q.pop();  
  171.         char tmp[800];  
  172.         strcpy(tmp, cur.c_str());  
  173.         analyUrl(tmp);  
  174.         preConnect();  
  175.         PutImagtoSet();  
  176.         vector<string>::iterator ita = photoUrl.begin();  
  177.         for (ita; ita != photoUrl.end(); ++ita)  
  178.         {  
  179.             OutIamge(*ita);  
  180.         }  
  181.         photoUrl.clear();  
  182.         vector <string>::iterator it = comUrl.begin();  
  183.         for (it; it != comUrl.end(); ++it)  
  184.         {  
  185.             if (mp[*it]==0)  
  186.             q.push(*it);  
  187.         }  
  188.         comUrl.clear();  
  189.     }  
  190. }  
  191. int main()  
  192. {  
  193.     CreateDirectoryA("./img", 0);  //在工程下创建文件夹  
  194.     string beginUrl= "http://news.qq.com/"; //输入起始网址  
  195.     bfs(beginUrl);  
  196.     return 0;  
  197.       

  1. }  

效果图:



阅读全文
0 0
原创粉丝点击