开发MFC爬取图片工具二(实现爬取图片功能)

在CHttp的类的基础上添加函数实现爬取图片功能

引言

前面的文章中将解析url,连接服务器,获取HTML界面的功能实现了并封装在一个类中。接下来需要实现功能是,如何解析获得的html界面,并将其中我们需要的图片连接地址保存下载下来,并且能接着爬取另外的网址的功能。
接下来我将这三个功能按照三个函数来实现。
根据爬取的网站不同和想爬取的内容不同。这里可以根据自己的要求来制定相应函数,但总流程是相同的。

各个爬取模块简单介绍

  1. 简单爬取模块(此处的RegexIamage中匹配、下载、保存功能都有,但结构有点复杂,我在后面的模块中进行的了分解)
    bool RegexIamage(string & html, string savepathM, int num);
    void StartCatch(string startUrl, string savepathM, int num);
  2. 爬取任意网页模块(使用广域优先法爬取,爬取的内容不太受控制,但会不停的爬取任意图片)
    bool RegexIamage(string & html, vector& vecImage, queue& q);
    bool downLoadImage(vector& vecImage, string savepathM, int numImg);
    void StartCatch2(string startUrl, string savepathM,int numPage, int numImg);
  3. 爬取百度图片模块(此处专门用来爬取百度图片,可以根据内容爬取相应的图片,在后面的界面爬取图片工具就是在此基础上进行的,注意此模块中用到了上面模块的一个下载函数)
    bool RegexIamageBaiDu(string & html, vector& vecImage, queue& q);
    void StartCatchBaiDu(string name, string savepathM, int numPage, int numImg);

所有代码

  1. CHttp.h
#include <iostream>
#include <Windows.h>		//#include<WinSock2.h>在windows里边
#include <string>
#include <queue>
#include <regex>
#include <urlmon.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#pragma comment(lib, "urlmon.lib")

#pragma comment(lib, "WS2_32")  // 链接到WS2_32.lib
using namespace std;

class CHttp
{
public:
	char g_Host[MAX_PATH];				//获取主机路径
	char g_Object[MAX_PATH];			//获取资源路径

	SOCKET g_sock;
	SSL *sslHandle;
	SSL_CTX *sslContext;
	BIO * bio;

	int numImagesR=0;			//定义一个下载的总数量,所有网页中的图片相加的数量
	string cururl;			//用来暂存p队列中的链接

	//UTF转GBK(在获取的页面为utf-8的可以使用此转换)
	std::string UtfToGbk(const char* utf8);
	//将string类型转换为LPCWSTR类型(在下载模块的图片路径,保存路径需要转换格式会用到)
	LPCWSTR stringToLPCWSTR(std::string orig);

	//下方的两个解析模块和下载模块无需改变,主要是根据自己需求改变开始抓取模块和匹配模块
	//解析URL(https)
	bool Analyse(string url);
	//连接https服务器
	bool Connect();
	//建立SSl连接(https)
	bool SSL_Connect();
	//得到html(https)
	bool Gethtml(string url, string& html);
	//将解析https的url,连接服务器,建立SSL连接得到html封装在一起得到(解析https连接得到html)
	bool GetHtmlHttps(string url, string& html);

	//解析URL(http)
	bool Analyse2(string url);
	//连接http服务器
	bool Connect2();
	//得到html(http)
	bool Gethtml2(string url, string& html);
	//将解析http的url,连接服务器,得到html封装在一起得到(解析http连接得到html)
	bool GetHtmlHttp(string url, string& html);

	//上方的关于如何连接http网址或https网址并获取网页html已经封装好了,下面的匹配图片、下载图片操作需自行定义

	//爬取任意网页模块
	//匹配图片模块,可根据自己的需要更改
	//使用正则表达式匹配图片连接(此模块使用了广度优先法,此处匹配的http和https的图片连接)
	bool RegexIamage(string & html, vector<string>& vecImage, queue<string>& q);//参数1为要解析的html页面,参数2为解析出来的图片网络路径(多条路径),q为爬取的深度
	//下载图片使用URLDownloadToFile函数(此处可以下载任意网络文件,http或https)
	bool downLoadImage(vector<string>& vecImage, string savepathM, int numImg);//参数1为要下载的图片网络路径,参数2为保存路径,参数3为需要下载的图片数量
	//开始抓取(自定义,此处可以获取多个页面的图片,但多个页面链接不能控制(若想控制需要更改队列中地址的获取条件针对性的获取同网站下的其它页面资源))
	void StartCatch2(string startUrl, string savepathM,int numPage, int numImg);//参数1为要下载的图片网络路径,参数2为保存路径,参数3为需要下载的页数,参数4为需要下载的图片数量

	//爬取百度图片模块(也调用了上方的下载函数downLoadImage)
	//使用正则表达式来匹配百度图片
	bool RegexIamageBaiDu(string & html, vector<string>& vecImage, queue<string>& q);//参数1为要解析的html页面,参数2为解析出来的图片网络路径(多条路径),q为翻页页数
	//开始抓取百度图片
	void StartCatchBaiDu(string name, string savepathM, int numPage, int numImg);//参数1为要搜索的图片名称,参数2为保存路径,参数3为需要下载的页数,参数4为需要下载的图片数量

	//简单爬取模块
	//正则表达式匹配图片连接,并保存(此处匹配图片,保存模块都有,但结构有的复杂,我在上方的模块中进行的了分解)
	bool RegexIamage(string & html, string savepathM, int num);	//参数1需要解析的HTML页面,参数2所要保存的路径,参数3所要保存的图片数量
	//开始抓取(此处开始抓取不够模块化,只针对针对起始网址的单个页面进行图片的获取)
	void StartCatch(string startUrl, string savepathM, int num);		//参数1需要输入的开始地址,参数2需要输入的保存路径,参数3需要下载的图片数量

};

  1. CHttp.cpp
#include "CHttp.h"

//开始抓取
void CHttp::StartCatch(string startUrl, string savepathM, int num)
{
	queue<string> q;		//声明一个url队列,#include <queue>
	q.push(startUrl);

	while (!q.empty())
	{
		string cururl = q.front();
		q.pop();

		//解析URL
		if (false == Analyse(cururl))
		{
			cout << "解析URL失败,错误码:" << GetLastError() << endl;
			continue;
		}

		//连接服务器
		if (false == Connect())
		{
			cout << "连接服务器失败,错误代码:" << GetLastError() << endl;
			continue;
		}

		//建立ssl连接
		if (false == SSL_Connect())
		{
			cout << "建立SSL连接失败,错误代码:" << GetLastError() << endl;
			continue;
		}

		//获取网页
		string html;
		if (false == Gethtml(cururl,html))
		{
			cout << "获取网页数据失败,错误代码:" << GetLastError() << endl;
			continue;
		}

		//获取图片并保存
		if (false == RegexIamage(html, savepathM, num))
		{
			cout << "获取网页数据失败,错误代码:" << GetLastError() << endl;
			continue;
		}
		//cout << html << endl;
	}
	//释放
	SSL_shutdown(sslHandle);
	SSL_free(sslHandle);
	SSL_CTX_free(sslContext);
	closesocket(g_sock);
	WSACleanup();
}


//解析url(https)
bool CHttp::Analyse(string url)
{
	char *pUrl = new char[url.length() + 1];
	strcpy(pUrl, url.c_str());

	char *pos = strstr(pUrl, "https://");//找到https://开头的字符串
	if (pos == NULL) return false;
	else pos += 8;//将https://开头省略

	sscanf(pos, "%[^/]%s", g_Host, g_Object);
	//cout << "g_Host:" << g_Host << ",g_Object:" << g_Object << endl;	//用来测试

	delete[] pUrl;
	return true;
}

//解析url(http)
bool CHttp::Analyse2(string url){

	char *pUrl = new char[url.length() + 1];
	strcpy(pUrl, url.c_str());

	char *pos = strstr(pUrl, "http://");//找到http://开头的字符串
	if (pos == NULL) return false;
	else pos += 7;//将http://开头省略

	sscanf(pos, "%[^/]%s", g_Host, g_Object);
	//cout << "g_Host:" << g_Host << ",g_Object:" << g_Object << endl;	//用来测试

	delete[] pUrl;
	return true;
}


//建立TCP连接
bool CHttp::Connect()
{
	//初始化套接字
	WSADATA wsadata;
	if (0 != WSAStartup(MAKEWORD(2, 2), &wsadata)) return false;

	//创建套接字
	g_sock = socket(AF_INET, SOCK_STREAM, 0);//此处注意与http有所不同
	if (g_sock == INVALID_SOCKET) return false;

	//将域名转换为IP地址
	hostent *p = gethostbyname(g_Host);
	if (p == NULL) return false;

	sockaddr_in sa;		//定义服务器地址信息
	memcpy(&sa.sin_addr, p->h_addr, 4);		//将p指针中的ip地址拷贝4个字节到sa.sin_addr中
	sa.sin_family = AF_INET;		//地址符使用此
	sa.sin_port = htons(443);		//将主机字节顺序转换成网络字节顺序(此为https的端口)

	if (SOCKET_ERROR == connect(g_sock, (sockaddr*)&sa, sizeof(sockaddr))) return false;
	return true;
}

//连接http服务器
bool CHttp::Connect2(){
	//初始化套接字
	WSADATA wsadata;
	if (0 != WSAStartup(MAKEWORD(2, 2), &wsadata)) return false;

	//创建套接字
	g_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (g_sock == INVALID_SOCKET) return false;

	//将域名转换为IP地址
	hostent *p = gethostbyname(g_Host);
	if (p == NULL) return false;

	sockaddr_in sa;		//定义服务器地址信息
	memcpy(&sa.sin_addr, p->h_addr, 4);		//将p指针中的ip地址拷贝4个字节到sa.sin_addr中
	sa.sin_family = AF_INET;		//地址符使用此
	sa.sin_port = htons(80);		//将主机字节顺序转换成网络字节顺序(此为http的端口)

	if (SOCKET_ERROR == connect(g_sock, (sockaddr*)&sa, sizeof(sockaddr))) return false;
	return true;
}

//建立SSl连接
bool CHttp::SSL_Connect()
{
	// Register the error strings for libcrypto & libssl

	ERR_load_BIO_strings();
	// SSl库的初始化,载入SSL的所有算法,载入所有的SSL错误信息
	SSL_library_init();
	OpenSSL_add_all_algorithms();
	//加载SSL错误信息
	SSL_load_error_strings();

	// New context saying we are a client, and using SSL 2 or 3
	//建立新的SSL上下文
	sslContext = SSL_CTX_new(SSLv23_client_method());
	if (sslContext == NULL)
	{
		ERR_print_errors_fp(stderr);
		return false;
	}
	// Create an SSL struct for the connection
	sslHandle = SSL_new(sslContext);
	if (sslHandle == NULL)
	{
		ERR_print_errors_fp(stderr);
		return false;
	}
	// Connect the SSL struct to our connection
	if (!SSL_set_fd(sslHandle, g_sock))
	{
		ERR_print_errors_fp(stderr);
		return false;
	}
	// Initiate SSL handshake
	if (SSL_connect(sslHandle) != 1)
	{
		ERR_print_errors_fp(stderr);
		return false;
	}

	return true;
}

//得到html(https)
bool CHttp::Gethtml(string url, string & html)
{
	char temp1[100];
	sprintf(temp1, "%d", 166);
	string c_get;
	c_get = c_get
		//+ "GET " + g_Object + " HTTP/1.1\r\n"
		+ "GET " + url + " HTTP/1.1\r\n"
		+ "Host: " + g_Host + "\r\n"
		+ "Content-Type: text/html; charset=UTF-8\r\n"
		//+ "Content-Length:" + temp1 + "\r\n"
		+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299\r\n"
		+ "Connection:Close\r\n\r\n";
	//+ temp;

	SSL_write(sslHandle, c_get.c_str(), c_get.length());

	char buff[101];
	int nreal = 0;

	while ((nreal = SSL_read(sslHandle, buff, 100)) > 0)
	{
		buff[nreal] = '\0';
		//html += UtfToGbk(buff);		//此处将所得页面转换为gbk格式的
		html += buff;
		//printf("%s\n", buff);
		memset(buff, 0, sizeof(buff));
	}

	return true;
}

//得到html(http)
bool CHttp::Gethtml2(string url, string& html){
	char temp1[100];
	sprintf(temp1, "%d", 166);
	string c_get;
	c_get = c_get
		//+ "GET " + g_Object + " HTTP/1.1\r\n"
		+ "GET " + url + " HTTP/1.1\r\n"
		+ "Host: " + g_Host + "\r\n"
		+ "Content-Type: text/html; charset=UTF-8\r\n"
		//+ "Content-Length:" + temp1 + "\r\n"
		+ "Connection:Close\r\n\r\n";
	//+ temp;

	//发送get请求,并判断是否失败
	if (SOCKET_ERROR == send(g_sock, c_get.c_str(), c_get.length(), 0)){
		cout << "发送get请求失败" << endl;
		return false;
	}

	//接收数据并保存到HTML中
	char ch = 0;
	while (recv(g_sock, &ch, 1, 0)){
		html = html + ch;				//此处未进行编码转换
	}
	//printf("%s\n", html);
	//cout << html << endl;
	return true;
}

//将解析url,连接服务器,建立SSL连接得到html封装在一起得到(解析https连接得到html)
bool CHttp::GetHtmlHttps(string url, string& html){
	//解析https的URL
	if (false == Analyse(url))
	{
		cout << "解析URL失败,错误码:" << GetLastError() << endl;
	}

	//连接https服务器
	if (false == Connect())
	{
		cout << "连接服务器失败,错误代码:" << GetLastError() << endl;
	}

	//建立ssl连接
	if (false == SSL_Connect())
	{
		cout << "建立SSL连接失败,错误代码:" << GetLastError() << endl;
	}

	//获取https网页
	if (false == Gethtml(url, html))
	{
		cout << "获取网页数据失败,错误代码:" << GetLastError() << endl;
	}
	return true;
}

//将解析http的url,连接服务器,得到html封装在一起得到(解析http连接得到html)
bool CHttp::GetHtmlHttp(string url, string& html){
	//解析http的URL
	if (false == Analyse2(url))
	{
		cout << "解析URL失败,错误码:" << GetLastError() << endl;
	}

	//连接http服务器
	if (false == Connect2())
	{
		cout << "连接服务器失败,错误代码:" << GetLastError() << endl;
	}

	//获取http网页
	if (false == Gethtml2(url, html))
	{
		cout << "获取网页数据失败,错误代码:" << GetLastError() << endl;
	}
	return true;
}

//UTF转GBK
string CHttp::UtfToGbk(const char* utf8)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len + 1];
	memset(wstr, 0, len + 1);
	MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
	len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* str = new char[len + 1];
	memset(str, 0, len + 1);
	WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
	if (wstr) delete[] wstr;
	return str;
}

//正则表达式匹配图片连接,并保存
bool CHttp::RegexIamage(string & html, string savepathM, int num)
{
	smatch mat;
	regex rgx("src=\"(.*(png|svg|jpg))\"");
	string::const_iterator start = html.begin();
	string::const_iterator end = html.end();
	string per;
	int i = 1;
	//int num = 10;	
	while (regex_search(start, end, mat, rgx))
	{
		//URL生成
		per = mat[1].str();
		size_t len = per.length();//获取字符串长度
		int nmlen = MultiByteToWideChar(CP_ACP, 0, per.c_str(), len + 1, NULL, 0);//如果函数运行成功,并且cchWideChar为零 //返回值是接收到待转换字符串的缓冲区所需求的宽字符数大小。
		wchar_t* buffer = new wchar_t[nmlen];
		MultiByteToWideChar(CP_ACP, 0, per.c_str(), len + 1, buffer, nmlen);
		//保存路径(此处不能使用相对路径只能用绝对路径,否则下载的图片扩展名会有错误)
		//savepath = "G:/OpenCV/个人项目练习/爬取图片/loadhttps/loadhttps/img/";
		string savepath = savepathM + to_string(i) + ".jpg";
		size_t len1 = savepath.length();
		wchar_t* imgsavepath = new wchar_t[len1];
		int nmlen1 = MultiByteToWideChar(CP_ACP, 0, savepath.c_str(), len1 + 1, imgsavepath, len1);
		cout << mat.str() << endl;
		cout << savepath << endl;
		//下载文件
		HRESULT hr = URLDownloadToFile(NULL, buffer, imgsavepath, 0, NULL);//buffer
		if (hr == S_OK)
		{
			cout << "-------ok" << endl;
			if (i == num)//爬num张就结束了,也可以去掉这句话
			{
				exit(0);
			}
		}
		start = mat[0].second;
		i++;
	}
	return true;
}

//将string类型转换成LPCWSTR类型的
LPCWSTR CHttp::stringToLPCWSTR(string orig)
{
	size_t origsize = orig.length() + 1;
	const size_t newsize = 100;
	size_t convertedChars = 0;
	wchar_t *wcstring = (wchar_t *)malloc(sizeof(wchar_t)*(orig.length() - 1));
	mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);


	return wcstring;
}

//使用正则表达式匹配图片连接(自定义,一定要注意引用&)
bool CHttp::RegexIamage(string & html, vector<string>& vecImage, queue<string>& q){

	//vector<string> vecImage;//用来专门放图片连接
	//解析网页内容(使用正则表达式)
	//定义一个正则表达式
	smatch mat;
	//下方用既可以匹配到http的,又可以https的连接
	regex rex("http[^\\s'\"<>()]+");//我们先将所有的url匹配出来,从http开始,不能包含单引号、双引号、空格、尖括号等,将这些除掉使用中括号【】里面^表示除,空格\s需加\转义,'无需转义,"需要转义,除掉这些不能有的字符至少要出现1次使用加号+,重复0次以上n多次用*
	string::const_iterator start = html.begin();
	string::const_iterator end = html.end();
	//从html的开始一直匹配到最后,将匹配的结果放到mat中
	while (regex_search(start, end, mat, rex)){
		string per(mat[0].first, mat[0].second);//匹配出的每一条,构造一下per
		//cout << per << endl;		//输出匹配到的url连接
		//判断里面url是否有图片jpg、png等等
		//匹配到了图片连接
		if (per.find(".jpg") != string::npos 
			 || per.find(".png") != string::npos 
			 || per.find(".jpeg") != string::npos
			 || per.find(".svg") != string::npos	
			)
		{
			vecImage.push_back(per);
			//cout << per << endl;		//输出匹配到的url连接
			//cout << vecImage[i] << endl;
		}
		else{
			//去除w3c连接(w3c是个组织,万维网)
			if (per.find("https://www.w3.org") == string::npos){
				q.push(per);
			}
		}
		start = mat[0].second;		//不断叠加
	}
	return true;
}

//参数1为要解析的html页面,参数2为解析出来的图片网络路径(多条路径),q为翻页页数
bool CHttp::RegexIamageBaiDu(string & html, vector<string>& vecImage, queue<string>& q){
	smatch mat;
	regex rgx("http://[^\\s'\"<>()]+");			//用来匹配所有的http://图片连接,此处可以匹配百度中的所需要的正式图片
	string::const_iterator start = html.begin();
	string::const_iterator end = html.end();
	string per;
	int i = 1;
	//int num = 10;	
	while (regex_search(start, end, mat, rgx))
	{
		string per(mat[0].first, mat[0].second);//匹配出的每一条,构造一下per
		//cout << per << endl;		//输出匹配到的url连接
		//判断里面url是否有图片jpg、png等等
		//匹配到了图片连接
		if (per.find(".jpg") != string::npos)
		{
			vecImage.push_back(per);
			//cout << per << endl;		//输出匹配到的url连接
			//cout << vecImage[i] << endl;
		}

		start = mat[0].second;
		i++;
	}
	return true;
}

//下载图片(自定义)
bool CHttp::downLoadImage(vector<string>& vecImage, string savepathM, int numImg){
	string per;		//用来暂时储存图片
	//下载图片
	int i;
	for (i = 0; i < vecImage.size(); i++){
		//将vecImage的url连接由string变为符合下面下载函数的格式
		per = vecImage[i];
		//cout << per << endl;		//输出匹配到的url连接
		size_t len = per.length();//获取字符串长度
		int nmlen = MultiByteToWideChar(CP_ACP, 0, per.c_str(), len + 1, NULL, 0);//如果函数运行成功,并且cchWideChar为零 //返回值是接收到待转换字符串的缓冲区所需求的宽字符数大小。
		wchar_t* buffer = new wchar_t[nmlen];
		MultiByteToWideChar(CP_ACP, 0, per.c_str(), len + 1, buffer, nmlen);

		//转变savepath的格式
		//string savepath = savepathM + vecImage[i].substr(vecImage[i].find_last_of('/') + 1);	//此处使用的是其原来的图片名称

		numImagesR++;				//此处使用全局变量numImagesR,防止后面的数字把前面的数字覆盖
		string savepath = savepathM + to_string(numImagesR) + ".jpg";									//此处使用数字对其重命名
		size_t len1 = savepath.length();
		wchar_t* imgsavepath = new wchar_t[len1];
		int nmlen1 = MultiByteToWideChar(CP_ACP, 0, savepath.c_str(), len1 + 1, imgsavepath, len1);
		
		//下载文件stringToLPCWSTR
		HRESULT hr = URLDownloadToFile(NULL, buffer, imgsavepath, 0, NULL);//buffer
		if (hr == S_OK)
		{
			cout << per << endl;		//输出成功下载到的url连接
			cout << "-------ok" << endl;

			if (numImagesR == numImg)//爬numImg张就结束了,也可以去掉这句话
			{
				cout << "总共下载图片数量" << numImagesR << endl;
				exit(0);
			}
		}	
	}

	cout << "当前页面共下载图片数量" << (i+1) << endl;
	return true;
}

void CHttp::StartCatch2(string startUrl, string savepathM, int numPage, int numImg){
	queue<string> q;		//声明一个url队列,#include <queue>
	q.push(startUrl);			//将起始url放入队列

	int y = 1;//此处是进行多少页
	while (!q.empty())			//队列不为空,就一直执行此循环(一直爬取连接不止一个网站上的,在这网站上其他的也可以)
	{
		cururl = q.front();
		q.pop();

		string html;
		//判断此链接是否为http链接,不同的连接使用不同的获取页面方式
		//如果不是http就执行https的操作
		if (string::npos == cururl.find("http://"))
		{	
			GetHtmlHttps(cururl, html);
		}
		//如果不是https就执行http的操作
		if (string::npos == cururl.find("https://"))
		{
			GetHtmlHttp(cururl, html);
		}		
		//cout << html << endl;

		//获取https图片
		vector<string> vecImage;
		if (false == RegexIamage(html, vecImage,q))		//此处匹配图片地址,也将队列q压入一个新的地址(此地址为下一个所需下载的地址)
		{
			cout << "获取图片失败,错误代码:" << GetLastError() << endl;
			continue;
		}
		else{
			
			cout << "获取图片成功" << endl;
			cout <<"第"<<y<< "页图片总数量:" << vecImage.size() << endl;
		}

		//下载图片
		if (false == downLoadImage(vecImage, savepathM, numImg))
		{
			cout << "下载图片失败,错误代码:" << GetLastError() << endl;
			continue;
		}
		else{
			cout << "下载图片成功" << endl;
			cout << "图片数量" << vecImage.size() << endl;
			cout << "当前网址为:" << cururl << "页" << endl;
		}

		if (y == numPage)//爬num张就结束了,也可以去掉这句话
		{
			cout << "当前为第"<<y<<"页" << endl;
			break;
			//exit(0);
		}
		y++;

	}
	//释放
	//如果不是http就执行https的操作
	if (string::npos == cururl.find("http://"))
	{
		SSL_shutdown(sslHandle);
		SSL_free(sslHandle);
		SSL_CTX_free(sslContext);
	}
	closesocket(g_sock);
	WSACleanup();
}

//开始抓取百度图片
void CHttp::StartCatchBaiDu(string name, string savepathM, int numPage, int numImg){

	int y = 1;//此处是进行多少页
	string startUrl = "https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word={" + name + "}&pn={" + to_string(y-1) + "}";
	queue<string> q;		//声明一个url队列,#include <queue>
	q.push(startUrl);			//将起始url放入队列

	while (!q.empty())			//队列不为空,就一直执行此循环(一直爬取连接不止一个网站上的,在这网站上其他的也可以)
	{
		cururl = q.front();
		q.pop();

		string html;
		//判断此链接是否为http链接,不同的连接使用不同的获取页面方式
		//如果不是http就执行https的操作
		if (string::npos == cururl.find("http://"))
		{
			GetHtmlHttps(cururl, html);
		}
		//如果不是https就执行http的操作
		if (string::npos == cururl.find("https://"))
		{
			GetHtmlHttp(cururl, html);
		}
		//cout << html << endl;

		//获取https图片
		vector<string> vecImage;
		if (false == RegexIamageBaiDu(html, vecImage, q))		//此处匹配图片地址,也将队列q压入一个新的地址(此地址为下一个所需下载的地址)
		{
			cout << "获取图片失败,错误代码:" << GetLastError() << endl;
			continue;
		}
		else{
			cout << "获取图片成功" << endl;
			cout << "第" << y << "页图片总数量:" << vecImage.size() << endl;
		}

		//下载图片
		if (false == downLoadImage(vecImage, savepathM, numImg))
		{
			cout << "下载图片失败,错误代码:" << GetLastError() << endl;
			continue;
		}
		else{
			cout << "下载图片成功" << endl;
			cout << "图片数量" << vecImage.size() << endl;
			cout << "当前网址为:" << cururl << "页" << endl;
		}

		if (y == numPage)//爬numPage页就结束了,也可以去掉这句话
		{
			cout << "当前为第" << y << "页" << endl;
			break;
			//exit(0);
		}
		y++;
		int page = (y - 1) * 20;
		cururl = "https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word={" + name + "}&pn={" + to_string(page) + "}";	//重新给当前url赋值
		q.push(cururl);			//将当前url放入队列
	}
	//释放
	//如果不是http就执行https的操作
	if (string::npos == cururl.find("http://"))
	{
		SSL_shutdown(sslHandle);
		SSL_free(sslHandle);
		SSL_CTX_free(sslContext);
	}
	closesocket(g_sock);
	WSACleanup();
}
  1. main.cpp
#include "CHttp.h"

int main()
{
	cout << "*********************************************************" << endl;
	cout << "***********************爬取图片系统***********************" << endl;
	cout << "*********************************************************" << endl;


	//开始抓取下方采用了广域优先法爬取界面相关链接图片
	string savepathM = "G:/OpenCV/个人项目练习/爬取图片/loadhttps/loadhttps/img/";
	int numPage =2;
	int numImg = 10;
	CHttp http;
	//string starturl = "https://www.tupianzj.com/meinv/mm/";	
	//string starturl = "http://www.ivsky.com/Photo/42/42_Index.html";
	//string starturl = "https://image.baidu.com/search/index?ct=201326592&cl=2&st=-1&lm=-1&nc=1&ie=utf-8&tn=baiduimage&ipn=r&rps=1&pv=&fm=rs2&word=%E8%89%BE%E4%B8%BD%C2%B7%E6%8B%89%E7%89%B9%E5%B9%B4%E8%BD%BB&oriquery=%E8%89%BE%E4%B8%BD%C2%B7%E6%8B%89%E7%89%B9&ofr=%E8%89%BE%E4%B8%BD%C2%B7%E6%8B%89%E7%89%B9&hs=2&sensitive=0";
	//http.StartCatch(starturl, savepathM, num);	//简单爬取
	//http.StartCatch2(starturl, savepathM, numPage, numImg);		//任意爬取模块,可爬取任意网址无论http或https


	//下方模块是针对百度图片搜索模块可以搜索特定内容,进行翻页
	//string savepathM = "G:/OpenCV/个人项目练习/爬取图片/loadhttps/loadhttps/img/";
	//CHttp http;
	//此链接为百度任意翻页链接https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word={%E7%BE%8E%E5%A5%B3}&pn={}	
	http.StartCatchBaiDu("艾丽拉特", savepathM, numPage, numImg);

	//while (1);
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吾名招财

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值