写搜索引擎对我来说是一件有趣的事情,做的多好谈不上,但是至少可以一步一步做出来。当然做的怎么样,还得大家来判断了。在开始今天的话题之前,我们可以扯一些别的东西。什么东西呢,其实就是搜索引擎的一些衍生产品,很有意思。
现在的网页中有很多的信息,这里包括的内容很多。除了一般我们大家知道的字符数据之外,还有很多的其他文件内容,比如说pdf文件、视频文件、图形文件、音频文件等等,所以我们可以根据这些内容开发出对应的搜索产品。可以是图片搜索、视频搜索、博客搜索、mp3搜索等等。曾经在我上大学的时候,那个阶段mp3开始流行,大家基本上都习惯于用百度来搜索mp3,使用起来非常简洁方便。当然后来出了迅雷之后,大家又开始习惯使用狗狗来搜索一些视频文件,那个时候资源真的丰富得不行,基本上说只有你不想要的,没有你找不到的。当然后来由于关键字的引入、IP的保护和一些其他的原因,狗狗的资源越来越少,基本上处于弃用的边缘了,这中间已经不是技术的问题了。
习惯上网的朋友都知道,在网页上如果某一段文字有详细的说明,那么鼠标滑到该文字上的时候就会变成手的形状,提示我们此处可以单击。其实,这就是我们常说的超链接。有了超链接,我们就可以进一步访问更多的网页,熟悉更多的内容。网页与网页之间有了超链接这个利器之后,我们就可以顺着这条线慢慢爬行,遍历所有的网页,这在理论上完全是可以行得通的。但是在现实中是否必要就是另外一回事了。
在网页内容中寻找超链接的方法很多,大家完全可以采用正则表达式的方法把这些地址全部找到。但是我在这方面不是很了解,采用的方法就比较笨,就是根据http://的方法,逐步查找到对应url地址的。当然如果长度超过一定的范围,我就丢弃了。当然,现在很多网页中的url地址使用脚本生成的,这给我们的工作造成了一定的困难。不过没有关系,后续我们可以慢慢改进、逐步进行解决。
#include <stdio.h>
#include <windows.h>
#include <wininet.h>
#ifdef ERROR
#undef ERROR
#endif
#define U8 unsigned char
#define U32 unsigned int
#define STATUS unsigned int
#define OK 0
#define ERROR (~0L)
#define MAX_BLOCK_SIZE 1024
#define MAX_DOMAIN_NAME_LENGTH 64
#define SAVE_DIR "E:/download/"
#pragma comment(lib, "wininet.lib")
static STATUS download_web_page(const char* url, const char* path);
static int total_number = 0;
static char* domain_name[] = {
"http://www.baidu.com",
"http://www.sogou.com",
"http://www.163.com",
"http://www.sina.com",
"http://www.sohu.com",
"http://www.qq.com",
"http://www.ifeng.com",
"http://www.z.cn",
"http://www.360buy.com",
"http://www.dangdang.com",
"http://www.zaobao.com",
};
/* get length of html file */
static int get_file_size(const char* path)
{
HANDLE hFile;
int size = 0;
hFile = CreateFile(path, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
size = GetFileSize(hFile, NULL);
CloseHandle(hFile);
}
return size;
}
/* get all data from html file */
static STATUS get_file_content(const char* path, void** pp_buffer, int* size)
{
int length;
char* buffer;
HANDLE hFile;
if(NULL == path)
{
return ERROR;
}
if(NULL == pp_buffer)
{
return ERROR;
}
if(NULL == size)
{
return ERROR;
}
length = get_file_size(path);
if(0 == length)
{
return ERROR;
}
buffer = (char*) malloc(length +1);
if(NULL == buffer)
{
return ERROR;
}
buffer[length] = '\0';
hFile = fopen(path, "r+b");
if(NULL == hFile)
{
free(buffer);
return ERROR;
}
fread(buffer, 1, length, hFile);
fclose(hFile);
*pp_buffer = buffer;
*size = length;
return OK;
}
/* show all http name, sometimes just for debug use */
static void print_http_name(const char* buffer, int size)
{
while(size --)
{
printf("%c", *buffer ++);
}
printf("\n");
}
static void download_linked_page(const char* buffer, int size)
{
char* data;
char name[64];
print_http_name(buffer, size);
data = (char*)malloc(size + 1);
if(NULL == data)
{
return;
}
data[size] = '\0';
memmove(data, buffer, size);
memset(name, 0, 64);
sprintf(name, SAVE_DIR"%d.html", total_number);
if(OK == download_web_page(data, name))
{
total_number ++;
}
/* free data memroy, which contained http domain name */
free(data);
}
/* get http form html file, then download it by its name*/
static void get_http_and_download(const char* buffer)
{
const char* prev;
const char* next;
char letter;
int count;
if(NULL == buffer)
{
return;
}
next = buffer;
while(1)
{
next = strstr(next, "http://");
if(NULL == next)
{
break;
}
count = MAX_DOMAIN_NAME_LENGTH;
prev = next;
next += strlen("http://");
while(1)
{
if(!count)
{
break;
}
count --;
letter = *next;
if('"' == letter || '\'' == letter || ')' == letter || '>' == letter)
{
break;
}
next ++;
}
if(count)
{
download_linked_page(prev, next - prev);
}
}
}
/* implement page download */
static STATUS download_web_page(const char* url, const char* path)
{
U8 buffer[MAX_BLOCK_SIZE];
U32 iNumber;
FILE* hFile;
HINTERNET hSession;
HINTERNET hUrl;
STATUS result;
hSession = InternetOpen("RookIE/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if(NULL == hSession)
{
return ERROR;
}
hUrl = InternetOpenUrl(hSession, url, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);
if(NULL == hUrl)
{
result = ERROR;
goto error1;
}
hFile = fopen(path, "wb");
if(NULL == hFile)
{
result = ERROR;
goto error2;
}
iNumber = 1;
while(iNumber > 0)
{
InternetReadFile(hUrl, buffer, MAX_BLOCK_SIZE -1, &iNumber);
fwrite(buffer, sizeof(char), iNumber, hFile);
}
fclose(hFile);
result = OK;
error2:
InternetCloseHandle(hUrl);
error1:
InternetCloseHandle(hSession);
return result;
}
/* download page and its linked pages */
void download_page_entry(const char* url)
{
char* buffer;
int size;
char name[64];
memset(name, 0, 64);
sprintf(name, SAVE_DIR"/%d.html", total_number ++);
download_web_page(url, name);
if(OK == get_file_content(name, &buffer, &size))
{
get_http_and_download(buffer);
free(buffer);
}
}
int main(int argc, char* argv[])
{
int index;
for(index = 0; index < (sizeof(domain_name) / sizeof(char*)); index ++)
{
download_page_entry(domain_name[index]);
}
return 1;
}
上面的代码稍显复杂,关键内容在于判断get_http_and_download函数中是如何获取url地址的。为了验证效果,我们下载了11个网站的网页和其链接网页,大约有1万多个,花费了有两个多小时。当然因为中间没有做重复性url地址判断,所以很多网页极有可能重复下载了。不过没关系,朋友们可以看看代码的基本逻辑结构就行了,重点掌握网页是怎么遍历和查找的就可以了。最后,如果大家要运行这段代码,首先需要在E盘创建一个download的目录,也就是我们保存网页的地方,再就是保证E盘剩余空间有1G以上即可。
标签:web,遍历,http,name,buffer,搜索引擎,char,download,size From: https://blog.51cto.com/feixiaoxing/5881001