最简单的爬虫是分析网页,如果要爬取图片,就要将图片在网页中的格式进行分析,取到图片的连接,接着下载图片;
由于网页中还会链接到其他的网页,所以需要将其中的所有网页取出,一般有两种算法:BFS广度优先遍历:和DFS深度优先遍历。
对于一个简单的爬虫程序,需要以下几部分组成
1.解析网页URL得到对应的主机名和资源值
2.需要向服务端发送http请求,得到相应的相应
3.提取所有的url及图片地址
4.文件的下载和存储
5.一个BFS或者DFS算法
用类CrawlerC来实现:
主要的成员函数有:
bool analyUrl(const string&url,string&host,string&resource);//通过对URL的解析得到对应的主机地址和资源
bool getHttpRes(const string&url,char*&response,int &bytesRead);//向对应的主机发送http请求
void getHtmlRes(string &htmlResponse,vector
string getFileName(const string&url);//依据URL建立文件名,便于区分哪个网站的图片
void downLoadImg(vector
void BFS(const string &url);//广度优先遍历
bool CrawlerC::analyUrl(const string &url, string &host, string &resource)
{
//url中http是协议,之后的www什么的是域名,之后的/后面是资源
if (strlen(url.c_str()) > 2000){
cout << "url长度过长,可能是错误的url" << endl;
return false;
}
//判断字符串2是不是字符串1的子串,如果是,返回首次出现的地址
const char*pos = strstr(url.c_str(), "http://");//在URL中找到http出现的位置
if (pos == NULL)
pos = url.c_str();//没有找到http,则默认是http
else
pos += strlen("http://");//有http需要将其跳过
if (strstr(pos, "/") == 0)//需要取到第一个/之前的值,这部分值是主机的地址
return false;
char pHost[100];
char pResource[2000];
sscanf(pos, "%[^/]%s", pHost, pResource);//格式化字符串,取到以/为结束的字符串
host = pHost;//得到主机名
resource = pResource;//得到资源
return true;
}
bool CrawlerC::getHttpRes(const string &url, char*&response, int &bytesRead)
{
string host, resource;
if (!analyUrl(url, host, resource)){//解析URL得到对应的主机名和资源
cout <h_addr,4);
//建立连接
if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) != 0){
cout << "无法连接" << endl;
return false;
}
//准备发送HTTP请求
string request = "GET " + resource + " HTTP/1.1\r\nHost:" + host + "\r\nConnection:Close\r\n\r\n";
//发送数据
if (SOCKET_ERROR == send(sock, request.c_str(), request.size(), 0)){
cout << "发送失败" << endl;
closesocket(sock);
return false;
}
//接收数据
int nContentLeng = 1048576;
char *pageBuf = (char*)malloc(nContentLeng);
//char *pageBuf = new char[nContentLeng];
memset(pageBuf, 0, nContentLeng);
bytesRead = 0;//已经读取的长度
int ret = 1;//拷贝完成的长度
cout << "read:" << endl;
while (ret > 0){
//指定接收的缓存及其长度,返回拷贝完成的字节数
ret = recv(sock, pageBuf + bytesRead, nContentLeng - bytesRead, 0);
if (ret > 0)
bytesRead += ret;
if (nContentLeng - bytesRead < 100){//缓冲区的剩余长度过小
cout << "重新分配" << endl;
nContentLeng *= 2;
pageBuf = (char*)realloc(pageBuf, nContentLeng);
}
cout << ret << endl;
}
pageBuf[bytesRead] = '\0';//添加结束标志
response = pageBuf;
closesocket(sock);
return true;
}
void CrawlerC::getHtmlRes(string &htmlResponse, vector&imgUrls, const string &host)
{
//找到所有的连接加入到队列中
const char* p = htmlResponse.c_str();//需要解析的返回串
char* tag = "href=\"";//这个匹配href=",找到链接
const char *pos = strstr(p,tag);
ofstream ofile("url.txt", ios::app);
while (pos){//循环取出所有的超链接
pos += strlen(tag);//pos现在指向了网址的开始
const char*nextQ = strstr(pos, "\"");//匹配引号
if (nextQ){//取到网址的结束位
char *url = new char[nextQ - pos + 1];
sscanf(pos, "%[^\"]", url);//取到以引号结束的子串
string surl = url;
if (visitedUrl.find(surl) == visitedUrl.end()){
visitedUrl.insert(surl);//不在url中
ofile << surl << endl;
hrefUrl.push(surl);
}
pos = strstr(pos, tag);
delete[]url;
}
}
ofile << endl << endl;
ofile.close();
tag = " strstr(pos0, ">")){
pos = strstr(pos0, att1);
if (!pos){
continue;
}
else
pos = pos + strlen(att1);
}
else{
pos = pos2 + strlen(att2);
}
const char*nextQ = strstr(pos, "\"");//找后引号
if (nextQ){
char*url = new char[nextQ - pos + 1];
sscanf(pos, "%[^\"]", url);
cout << url << endl;
string imgUrl = url;
if (visitedImg.find(imgUrl) == visitedImg.end()){
visitedImg.insert(imgUrl);
imgUrls.push_back(imgUrl);
}
pos0 = strstr(pos0, tag);
delete[]url;
}
}
}
std::string CrawlerC::getFileName(const string&url)
{
string fileName;
fileName.resize(url.size());
int k = 0;
for (int i = 0; i < (int)url.size(); i++){
char ch = url[i];
//去除特殊符号
if (ch != '\\'&&ch != '/'&&ch != ':'&&ch != '*'&&ch != '?'&&ch != '"'&&ch != '<'&&ch != '>'&&ch != '|')
fileName[k++] = ch;
}
return fileName.substr(0, k);
}
void CrawlerC::downLoadImg(vector&imgUrl, const string&url)
{
//生成保存图片的文件夹
string foldname = getFileName(url);
foldname = "./img/" + foldname;
if (!CreateDirectory(foldname.c_str(), NULL))
cout << "不能创建文件夹" << endl;
char*image=NULL;
int byteRead;
for (int i = 0; i < imgUrl.size(); i++){
string str = imgUrl[i];
int pos = str.find_last_of(".");
if (pos==string::npos)
continue;
else{
string ext = str.substr(pos + 1, str.size() - pos - 1);
if (ext != "bmp"&& ext != "jpg" && ext != "jpeg"&& ext != "gif"&&ext != "png")
continue;
}
if (getHttpRes(imgUrl[i], image, byteRead)){
if (strlen(image)==0)
continue;
const char*p = image;
const char * pos = strstr(p, "\r\n\r\n") + strlen("\r\n\r\n");//图片文件的开始位置
int index = imgUrl[i].find_last_of("/");
if (index != string::npos){
string imgname = imgUrl[i].substr(index, imgUrl[i].size());//截取文件名
ofstream ofile(foldname + imgname, ios::binary);
if (!ofile.is_open())
continue;
cout << g_ImgCnt++ << foldname + imgname << endl;
ofile.write(pos, byteRead - (pos - p));
ofile.close();
}
free(image);
}
}
}
void CrawlerC::BFS(const string &url)
{
char*response=0;
int bytes;
if (!getHttpRes(url, response, bytes)){
cout << "错误的url" << endl;
return;
}
string httpResponse = response;
free(response);
string fileName = getFileName(url);
ofstream ofile("./html/" + fileName);
if (ofile.is_open()){
ofile << httpResponse << endl;
ofile.close();
}
vectorimageUrl;
getHtmlRes(httpResponse, imageUrl,url);
downLoadImg(imageUrl, url);
}
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2, ), &wsaData) != 0)//这个是初始化socket
return 1;
CreateDirectory("./img", 0);
CreateDirectory("./html", 0);
CrawlerC test;
string url = "http://www.nipic.com/index.html";
test.BFS(url);
test.visitedUrl.insert(url);
while (test.hrefUrl.size() > 0){
string url1 = test.hrefUrl.front();
//cout << url1 << endl;
test.BFS(url1);//对于每一个url都要进行搜索
test.hrefUrl.pop();
}
WSACleanup();
return 0;
}
参考链接:http://blog.csdn.net/huangxy10/article/details/8120106