LinuxC/C++网络爬虫(1)
网络爬虫(Web Crawler),是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本,有时候又称网络蚂蚁,是搜索引擎(例如:Baidu、Google……)的重要组成部分。随着Internet的快速发展,网站数量剧增意味着后台数据量的剧增,在这样的情况下,用户能不能通过搜索引擎来及时地得到包含他要查找内容的网页,能不能实现定向搜索……,这些对传统的搜索引擎必然是个巨大的考验。以上这些都是网络爬虫所关心的问题,通过改变网络爬虫的搜索策略,分析策略等,就能在很大程度上解决以上问题。
传统的网络爬虫一般从一个或若干初始网页的URL开始,抓取初始网页,然后通过URL分析策略,提取已抓取页面上的URL,然后继续重复以上过程,不断从当前页面上抽取新的URL放入队列,直到满足一定的停止条件。
目前已经发布的网络爬虫有:
RBSE (Eichmann,1994)是第一个发布的爬虫。
WebCrawler(Pinkerton,1994)是第一个公开可用的用来建立全文索引的一个子程序,他使用库www来下载页面。
World Wide Web Worm (McBryan, 1994)是一个用来为文件建立包括标题和URL简单索引的爬虫。索引可以通过grep式的Unix命令来搜索。
GNU Wget是一个在GPL许可下,使用C语言编写的命令行式的爬虫。它主要用于网络服务器和FTP服务器的镜像。
Heritrix是一个互联网档案馆级的爬虫,设计的目标为对大型网络的大部分内容的定期存档快照,是使用java编写的。
大家常用的搜索引擎,例如Baidu,Google也都有自己的网络爬虫来帮他们抓取Internet海洋中的网页。这里稍微插一段题外话,其实网络爬虫和网站维护经常都是对立的,因为有些爬虫刷新时间短,有些爬虫比较“笨”,会在网站里迷失了路等情况,引起给网站服务器发送大量请求,造成服务器压力过大而崩溃。但话又说回来,一个设计良好的网络爬虫,再加上使用者良好的素质,是完全可以避免以上情况的。总得来说,网络爬虫带来的好处远远大于它自身和使用者带来的坏处。
因为刚开始接触这个网络爬虫的缘故,本人对爬虫了解并不是太深,这两天写了一个小程序,实现了通过URL来获取网页源代码。这两天找了很多资料,但是绝大部分的爬虫资料都是Python编写的,少数是JAVA和c#写的,C/C++的版本少之又少,还是需要我继续去学习啊。
#include <iostream>
#include <string>
#include <string.h>
#include <netdb.h>
#include <stdlib.h>
using namespace std;
#define ERROR -1
#define OK 0
#define PORT 80
void GetUrlAndPath(const string url, string &HostUrl, string &PagePath)
{
HostUrl = url;
PagePath = "/";
//去除 http:// 字符串
int pos = HostUrl.find("http://");
if(pos != -1)
{
HostUrl = HostUrl.replace(pos, 7, "");
}
//去除 https:// 字符串
pos = HostUrl.find("https://");
if(pos != -1)
{
HostUrl = HostUrl.replace(pos, 8, "");
}
//提取主机端口和路径
pos = HostUrl.find("/");
if(pos != -1)
{
PagePath = HostUrl.substr(pos);
HostUrl = HostUrl.substr(0, pos);
}
}
string getpagecontent(const string url)
{
//记录主机的信息,包括主机名、别名、地址类型、地址长度和地址列表
struct hostent *host;
string HostUrl, PagePath;
//从url获取主机url和路径
GetUrlAndPath(url, HostUrl, PagePath);
//通过主机名连接主机
host = gethostbyname(HostUrl.c_str());
if(host == 0)
{
cout<<"gethostbyname error";
exit(1);
}
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = ((struct in_addr*) (host->h_addr))->s_addr;
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd == -1)
{
cout<<"create sfd error"<<endl;
exit(1);
}
string requestHeader;
requestHeader = "GET " + PagePath + " HTTP/1.1\r\n";
requestHeader += "Host: " + HostUrl + "\r\n";
requestHeader += "Accept: */*\r\n";
requestHeader += "User-Agent: Mozilla/4.0(compatible)\r\n";
requestHeader += "connection:Keep-Alive\r\n";
requestHeader += "\r\n";
int ret = connect(sfd, (const sockaddr*)&addr, sizeof(addr));
if(ret == -1)
{
cout<<"connect error"<<endl;
exit(1);
}
ret = send(sfd, requestHeader.c_str(), requestHeader.size(), 0);
if(ret == -1)
{
cout<<"send error"<<endl;
exit(1);
}
struct timeval timeout = {1, 0};
setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, sizeof(struct timeval));
char c;
bool flag = true;
while(recv(sfd, &c, 1, 0))
{
if(c == '\r')
{
continue;
}
else if(c == '\n')
{
if(flag == false)
break;
flag = false;
}
else
{
flag = true;
}
}
int len, BUFFERSIZE = 512;
char buffer[BUFFERSIZE];
string pagecontent = "";
while((len = recv(sfd, buffer, BUFFERSIZE-1, 0)) > 0)
{
buffer[len] = '\0';
pagecontent += buffer;
}
return pagecontent;
}
int main()
{
cout<<getpagecontent("http://www.baidu.com")<<endl;
return 0;
}
还没有评论,来说两句吧...