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,用空格隔开,只能抓取一条,另一条没有抓取。(未解决问题)
本人是大学生,能力有限,会虚心学习,大家可以互相交流。