C/C++爬虫--http协议

C/C++爬虫--http协议


    在bilibili上扒了个爬虫视频,自己看了几遍,跟着老师学习了这个项目。

项目名称:C/C++爬虫--http协议

项目简介:编写用C++语言爬虫http协议的网址,然后将网页的源码下载下来。

开发环境:Visual Studio 2012      和        FiddleSetup.exe

项目实现:将URL放入队列,然后取出一条URL,进行解析这条URL,分为协议,域名,资源路径三部分,接下来要连接网络,获取网页数据,解析网页,获取有价值的内容,比如:jpg,avi,png,mp4,torrent,在网页中还有超链接,然后将那些URL继续放入队列,循环解析。

项目难点:在用SOCKET联网时,HTTP协议底层是通过TCP协议实现的,端口号为80,联网过程较难,在获取网页时,将网页中URL循环放入队列的过程,以及将img文件下载到img文件中的过程较难。(此项目还未解决获取网页中的这两个问题,只能下载源码)

项目实现示意图:

1.Spider.h的代码如下:

#include <iostream>
#include <Windows.h>
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <queue>
using namespace std;
//开始抓取URL
bool StartCatch(string url);

2.Spider.cpp的代码如下:

#include "Spider.h"
#include "HTTP.h"
//http获取
int main()
{
	cout<<"********************************************"<<endl;
	cout<<"         欢迎使用人工智能网络爬虫系统       "<<endl;
	cout<<"********************************************"<<endl;
	cout<<"请输入要抓取的URL链接:"<<endl;

	//下载图片时,照片下载到此文件夹
	//创建文件夹 L告诉编译器:字符串要使用Unicode编码
	CreateDirectory(L"image",NULL);

	std::string starturl;
	cin >> starturl;

	//开始抓取
	StartCatch(starturl);

}

//开始抓取
bool StartCatch(std::string url)
{
	queue<string> q;
	//插入一条url
	q.push(url);

	//循环不停的从队列中取出url
    while(!q.empty())
	{
		string currentUrl = q.front();
		q.pop();

		cout<< "取出" <<currentUrl << endl;
		CHttp http;
		http.AnalyseURL(currentUrl);
		if(FALSE == http.Connect())
		{
			cout << "链接失败!"<<endl;
		}
		else
		{
			cout << "链接成功!"<<endl;
		}
        //获取网页
	    string html;
	    http.GetHtml(html);
	    cout << html << endl;
	}
	

	return true;

}

3.HTTP.h的代码如下:

#include <iostream>
#include <string>

using namespace std;
//http获取
class CHttp
{
public:
	bool AnalyseURL(std::string url);//解析URL
	CHttp();                        //构造函数
	bool Connect();                 //连接网络
	bool GetHtml(std::string& html);//获取网页
private:
	std::string m_host;    //域名
	std::string m_object;  //资源名
	SOCKET m_socket;       //客户端套接字 
};

4.HTTP.cpp的代码如下:

#include <WinSock2.h>

#include "HTTP.h"
#pragma comment(lib,"ws2_32.lib")
//构造函数
CHttp::CHttp()
{
	WSADATA wd;
	//初始化网络
	WSAStartup(MAKEWORD(2,2),&wd);

	//HTTP协议底层是通过TCP协议实现的
	m_socket = socket(AF_INET,SOCK_STREAM,0);
};

//链接网络
bool CHttp::Connect()
{
	hostent* p = gethostbyname(m_host.c_str());
	if(p == NULL)
	{
		return false;
	}
	sockaddr_in sa;
	memcpy(&sa.sin_addr,p->h_addr,4);
	sa.sin_family = AF_INET;
	sa.sin_port = htons(80); //将主机字节顺序转换为网络字节顺序

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

//解析URL
bool CHttp::AnalyseURL(string url)
{
	//https://    baike.baidu.com  /item/王北车/22747470?fr=aladdin
	if(string::npos == url.find("http://"))//npos代表枚举常量,为-1
	{
		return false;
	}
	if(url.length() <= 7)
	{
		return false;
	}

	int pos = url.find('/',7);
	//https://    baike.baidu.com
	if(string::npos == pos)
	{
		m_host = url.substr(7);
		m_object = "/";
	}
	//https://    baike.baidu.com  /
	//https://    baike.baidu.com  /item/王北车/22747470?fr=aladdin
	else
	{
		m_host = url.substr(7,pos-7);
		m_object = url.substr(pos);
	}
	if(m_host.empty() )
		return false;

	cout<<"域名:" << m_host <<endl;
	cout<<"资源名:" << m_object <<endl;
	return true;

}

//获取网页
bool CHttp::GetHtml(std::string& html)
{
	//先请求和服务器要需要哪个网页
	//下载软件FiddleSetup.exe,监控网页,打开浏览器给服务器发的头信息,在Raw的按钮栏中
	std::string info;
	info += "GET " + m_object + " HTTP/1.1\r\n";
	info += "Host: " + m_host + "\r\n";
	info += "Connection: Close\r\n";
	info += "User-Agent: Mozilla/5.0(Windows NT 10.0; WOW64) AppleWebKit/537.36(KHTML,like Gecko) Chrome/69.0.3497.100 Safari/537.36\r\n";
	info += "\r\n";

	if(SOCKET_ERROR == send(m_socket,info.c_str(),info.length(),0))
		return false;

	//接受
	char ch = 0;
	while(recv(m_socket,&ch,sizeof(ch),0))
	{
		html += ch;
	}

	return true;
}

编译结果:联网成功,并且将源码下载下来,对比图如下所示(问题:没有全部下载下来)

编译结果:输入两条一样的URL,用空格隔开,只能抓取一条,另一条没有抓取。(未解决问题)

  本人是大学生,能力有限,会虚心学习,大家可以互相交流。

猜你喜欢

转载自blog.csdn.net/qq_41103495/article/details/108414822