项目日记(1): boost搜索引擎

目录

1. 项目相关背景

2. 搜索引擎的相关宏原理

3. 搜索引擎的技术栈和项目环境

4. 正排索引, 倒排索引, 搜索引擎具体原理

5. 编写数据去标签化和数据清洗的模块parser(解析器).


1.项目相关背景

百度, 搜狗, 360等都有搜索引擎, 但是都是全网的搜索;

 boost是进行站内搜索, 数据更少并且垂直.

观察通过不同的搜索引擎进行查找的时候会出现不同的关键字, 一般包括title, content, 网址, 时间等.

2. 搜索引擎的相关宏原理

        实现用户通过客户端的浏览器输入关键字, 通过get方式, 然后http发送请求给服务端内存中的searcher, searcher再通过已经抓取好网页并且存放在data/*html目录下进行数据清理去标签建立索引的步骤, 将查找到的多个网页的title, content, url进行拼接, 最后返回给用户一个新的网页.

        在后面实现的部分主要是完成对客户端和服务端的流程, 爬虫网页数据就不做了.

3. 搜索引擎的技术栈和项目环境

技术栈:

        c/c++, c++11, STL, 标准库boost, Jesoncpp, cppjieba, cpp-httplib, html5, css, js, jQuery, Ajax.

项目环境:

        Centos 7云服务器, vim/g++/Makefile, vscode.

4. 正排索引, 倒排索引, 搜索引擎具体原理

正排索引:  由文档ID找到文档内容;

倒排索引: 根据文档的内容, 分词, 整理不重复的各个关键字, 对应到相应的文档ID.

举个栗子:

        妈妈买了四斤蔬菜; 妈妈买了一斤肉; 妈妈买了三两饺子皮.

正排索引: 

倒排索引:

5. 编写数据去标签化和数据清洗的模块parser(解析器)

5.1 官网下载标准库

首先到boost官网去下载好标准库; 网址: https://www.boost.org/

然后使用Xshell将下载好的标准库rz, 然后解包, 将标准库留下.

这里我是创建了一个boost_searcher目录来存放所有需要的文件数据.

其中boost_1_85_0就是boost下载好的标准库.

data目录下的input(从boost_1_85_0里面的doc目录下的html目录的全部数据拿出来的)存放原始html的数据, raw_html是处理过的文件数据.

parser.cc就是用来实现去标签化和数据清洗的函数.

5.2 去标签

一般html文件里面都是出现大量成对的标签, 我们只需要内容, 所以标签对我们没有作用要去除.

去除标签之后的每个文档如何区分捏?

使用\3进行标记区分文档. 读取的时候使用getline(ifstream, line); line就是\3.

5.3 编写parser代码

1. 在boost_searcher里创建一个parser.cc的文件; 

2. 先实现大体的框架; 首先EnumFile递归原html的所有文档, 将它们放到file_list数组里面;

3. ParserHtml从file_list里面将文件读取出来并且解析出来title, content, url;

4. SaveHtml 是将解析好的数据文件写入到output里面.

#include <iostream>
#include <vector>
#include <string>
#include <boost/filesystem.hpp>
#include <utility>
#include <fstream>
#include "util.hpp"
using namespace std;// 原来没处理过的html数据的文件目录.
const string src_path = "data/input";
// 将数据清洗以及去标签过的数据放到这个目录文件中
const string output = "data/raw_html/raw.txt";typedef struct DocInfo
{string title;string content;string url;
}DocInfo_t;//这里规定一下:
//const &: 输入;
//*: 输出;
//&: 输入输出;bool EnumFile(const string& src_file, vector<string>* file_list);bool ParserHtml(const vector<string>& file_list, vector<DocInfo>* results);bool SaveHtml(const vector<DocInfo_t>& result,const string& output);int main()
{//1. 递归将所有的html文件带路径的保存到file_list, 方便对文件进行一个个查询.vector<string> file_list;if(!EnumFile(src_path, &file_list)){cerr << "Enum File error!" << endl;return 1;}//2.按照file_list读取每个文件的内容.并且进行解析;vector<DocInfo_t> results;if(!ParserHtml(file_list, &results)){cerr << "Parser Html error!" << endl;return 2;}//3.将各个文件进行解析好的文件内容, 写入到output, \3为每个文档的分割符;if(!SaveHtml(results, output)){cerr << "Save Html error!" << endl;return 3;}return 0;
}

EnumFile模块: 

1.首先使用到标准库里面的接口boost::filesystem以及path来查看是否src_file的资源路径是否存在.

2. 使用ecursive_directory_iterator对src_file资源进行遍历, 再进一步筛选是否为普通文件以及.html后缀的文件. 如果是的话就将其放到数组file_list里面.

bool EnumFile(const string& src_path, vector<string>* file_list)
{// 这里是标准库<boost/filesystem.hpp>提供的接口和结构体;namespace fs = boost::filesystem;fs::path root_path(src_path);// 实现判断原资源数据路径是否存在.if(!fs::exists(root_path)){cerr << src_path << "no exists" << endl;return false;}//进行html文档的遍历, 如果为空就是遍历完成了.fs::recursive_directory_iterator end;for(fs::recursive_directory_iterator iter(root_path); iter != end; iter++){//判断是否为普通文件, 因为html都是普通文件.if(!fs::is_regular_file(*iter)){continue;}//判断是否为html后缀的文件.if(iter->path().extension() != ".html"){continue;}cout << "debug: " << iter->path().string() << endl;//当前路径一定是合法的html为后缀的文件file_list->push_back(iter->path().string());}return true;
}

1. ParserHtml: 将处理好的源html数据存放在file里的, 对其进行遍历, 然后对文件中的title, content, url进行解析, 最后存放到result数组里面.

2. 然后使用ParserTitle进行将title解析; 因为title的内容都是放在<title> </title>里面; 

我们只要找到<title> 和 </title> 然后将中间的内容切分即可.

3. ParserContent进行去标签获取内容, 采用状态机的方法, 枚举LABLE和CONTENT, 这里需要注意一般html里面开头也是标签, 所以初始化status是LABLE, 对file进行遍历, 如果遇到>那么就代表是标签的结束, status就是CONTENT, 如果遇到<那么就代表是标签的开始, status就是LABLE. 如果遇到\n, 我们需要使用\n做分隔符, 所以要把原来的变成空串, 最后将拼接好的字符串放到content.

4. ParserUrl进行url的解析, 那么我们boost官网查询和我们存放在自己的路径是不同的.

上面是url_head, 下面的url_tail只shangchu需要将data/input删除即可.

static bool ParserTitle(const string& file, string* title)
{size_t begin = file.find("<title>");if(begin == string::npos)return false;size_t end = file.find("</title");if(end == string::npos)return false;begin += string("<title>").size();if(begin > end)return false;*title = file.substr(begin, end - begin);return true;
}static bool ParserContent(const string& file, string* content)
{//去除html里面的标签;状态机enum status{LABLE,CONTENT};//默认一般html的开头都是标签.enum status s = LABLE;for(char c : file){switch(s){case LABLE:if(c == '>')s = CONTENT;case CONTENT:if(c == '<')s = LABLE;else{//原本文件的\n去除, 因为要用\n来做文本分割符;if(c == '\n')c = ' ';content->push_back(c);}break;default:break;}}return true;
}static bool ParserUrl(const string& file_path, string* url)
{//这个是网址拼接.string url_head = "https://www.boost.org/doc/libs/1_85_0/doc/html/accumulators.html";string url_tail = file_path.substr(src_path.size());*url = url_head + url_tail;return true;
}static void ShowDoc(const DocInfo& doc)
{cout << "title: " << doc.title << endl;cout << "content: " << doc.content << endl;cout << "url: " << doc.url << endl;}//将获取的html资源file_list解析处理后放到result;
bool ParserHtml(const vector<string>& file_list, vector<DocInfo_t>* results)
{for(const string& file : file_list){string result;//读取每个文件的内容;if(!ns_util::FileUtil::ReadFile(file, &result)){continue;}DocInfo_t doc;//解析文件, 读取title;if(!ParserTitle(result, &doc.title)){continue;}//解析文件, 读取content;if(!ParserContent(result, &doc.content)){continue;}//解析文件, 读取url;if(!ParserUrl(result, &doc.url)){continue;}results->push_back(move(doc)); //提高效率减少拷贝.//for testShowDoc(doc);break;}return true;
}

util.hpp: FileUtil是将每条源html的资源进行输出;

#pragma once#include <iostream>
#include <vector>
#include <string>
#include <fstream>using namespace std;namespace ns_util
{class FileUtil{public://读取文件file_path里面的内容并且放到out;static bool ReadFile(const string& file_path, string* out){ifstream in(file_path, ios::in);//如果没有打开文件成功if(!in.is_open()){cerr << "open file" << file_path << "error" << endl;return false;}string line;while(!getline(in, line)){*out += line;}in.close();return true;}};
};

SaveHtml:将解析好的数据进行文档分割和内容分割. 将解析好的数据以这种方式写入到output.

//将解析的数据读写到output每个文档\n分割, 每个文档的title, content, url以\3分割.
bool SaveHtml(const vector<DocInfo_t>& result,const string& output)
{
#define SEP '\3'//采用二进制方式写入;ofstream out(output, ios::out | ios::binary);if(!out.is_open()){cerr << "open " << output << "failed!" << endl;return false;}for(auto& item : result){string out_string;out_string = item.title;out_string += SEP;out_string += item.content;out_string += SEP;out_string += item.url;out_string += '\n';out.write(out_string.c_str(), out_string.size());}out.close();return true;
}

后言: 好久没更新博客了, xdm求个三联, 多多更新超多计算机网络, Linux, c++, c, 算法内容.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/19029.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java SE】 String、StringBuff和StringBuilder

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 字符串不可变性1.1 设计不可变1.2 修改字符串创建新对象1.3 为什么字符串不可变1.4 String类设计不可变的…

在Docker中使用GPU

一、安装nvidia-container-toolkit 总之一句话&#xff1a;nvidia-docker和nvidia-docker2&#xff0c;nvidia-container-runtime 已经被英伟达迭代了&#xff0c;可以认为nvidia-container-toolkit是nvidia-docker和nvidia-docker2&#xff0c; nvidia-container-runtime 的替…

Vue3项目练习详细步骤(第三部分:文章分类页面模块)

文章分类列表 主体结构 接口文档 文章分类列表查询接口数据绑定 Pinia状态管理库 axios请求拦截器 Pinia持久化插件-persist 未登录统一处理 添加文章分类 主体结构 接口文档 绑定请求数据 编辑文章分类 弹框结构 数据回显 接口文档 绑定请求数据 删除分类 …

前端中var、let 或 const区别

前端中var、let 或 const区别 一、前言1.var2.let3.const4.总结 一、前言 当涉及 JavaScript 中的变量声明时&#xff0c;开发人员通常会面临选择使用 var、let 或 const。虽然它们都可以用来声明变量&#xff0c;但在实际应用中&#xff0c;它们之间有一些重要的区别。接下来…

在window中使用HTTP服务器获取kali的文件

文章目录 一、在window中使用HTTP服务器获取kali的文件1、疑问2、执行条件3、成功读取 一、在window中使用HTTP服务器获取kali的文件 1、疑问 有时候kali上面有的文件想传入window但是发现不允许这样操作那怎么办呢&#xff1f;特别是在一些限制工具的比赛中想把kali的文件传…

数字化学校渠道的建造内容

数字化学校渠道的建造内容可以用阶段来区分&#xff1a; 1.网络硬件为主的建造 这一阶段首要重视的是学校网络的硬件基础建造&#xff0c;一起供给部分网络根本服务&#xff0c;与此一起&#xff0c;也进行部分信息使用内容的建造&#xff0c;如电子阅览室、归纳管理信息体系等…

Android 图片加载glide库 一次通关

前言 Glide是一个由Bumptech开发的开源图片加载库&#xff0c;专门用于Android平台。它被广泛应用于Android应用中&#xff0c;以简化图片加载过程&#xff0c;并提高性能和效率。 Glide能够快速加载图片&#xff0c;同时减少页面加载时间和内存消耗。Glide具有强大的缓存机制…

国产操作系统上apt命令详解 _ 统信 _ 麒麟 _ 中科方德

原文链接&#xff1a;国产操作系统上apt命令详解 | 统信 | 麒麟 | 中科方德 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在国产操作系统上使用apt命令的详解文章。apt&#xff08;Advanced Package Tool&#xff09;是Debian及其衍生发行版&#xff08;如统信UOS…

网络流量监控:解读网络性能的关键

目录 什么是网络流量监控&#xff1f; 网络流量监控的原理 网络流量监控的应用 AnaTraf网络流量分析仪简介 结语 在当今数字化时代&#xff0c;网络已成为人们日常生活和商业运营的核心。随着企业和个人对网络的依赖程度不断增加&#xff0c;确保网络稳定性和性能已成为至…

如何在JavaScript中检查字符串是否包含子字符串?

在JavaScript中检查一个字符串是否包含某个子字符串是一个常见任务。本文将介绍几种实现该功能的方法&#xff0c;包括传统方法和高级算法。 使用 indexOf() 方法 最基础和常见的方法是使用 indexOf() 方法。该方法返回字符串在另一个字符串中的起始位置&#xff0c;如果未找…

TPshop商城的保姆教程(windows)

提前准备 phpStudy下载&#xff1a;https://www.xp.cn/download.html 选择适合自己的版本下载 TPshop商城源文件下载链接&#xff1a; https://pan.baidu.com/s/143fLrxbwe9CTMCbyx7mXJQ?pwd6666 开始安装 安装完phpstudy后 以管理员的身份启动phpstudy.exe 选择合适自己…

2024年03月 Python(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,共50分) 第1题 以下选项中,创建类正确的是?() A: class test1: def prt(self): …… B: class Mg(): def__init__(na,ag): self.na=na C: class A(): def print(self): print(“Yes”) a=A() a.print() D…

【好书推荐,持续更新~~】

书籍推荐&#xff0c;持续更新~~ 1.《只是为了好玩: Linux之父林纳斯自传》-- Linus Torvalds, David Diamond Linux之父Linus Torvalds的自传&#xff0c;也是Linus唯一一本书。Linus以调侃的语气讲述了自己的成长经历&#xff0c;在他看来&#xff0c;一切都是为了好玩儿&am…

【Vue】v-bind属性绑定指令

作用&#xff1a;动态设置html的标签属性 比如&#xff1a;src、url、title 默认情况下是单向的 语法&#xff1a; v-bind:属性名"表达式"v-bind:可以简写成 > : 比如&#xff0c;有一个图片&#xff0c;它的 src 属性值&#xff0c;是一个图片地址。这个地址…

Android SDK下载安装(_指定版本)

安装完sdk&#xff0c;就可以直接使用adb命令了&#xff0c;如果想做app相关自动化测试&#xff0c;也是需要sdk环境依赖的 一、SDK下载 A&#xff1a;官网下载&#xff1a; 管内镜像网站(推荐)&#xff1a;https://www.androiddevtools.cn/index.html 官网&#xff1a;htt…

2024-5-9——给植物浇水 II

2024-5-9 题目来源我的题解方法一 双指针 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2105 我的题解 方法一 双指针 使用两个指针t1和t2记录Alice和Bob当前还未浇水的植物&#xff0c;使用变个变量cap1和cap2表示Alice和Bob当前剩余的水量。 两端同时浇水&#xff0…

渗透测试一些知识点

1、如果提示缺少参数&#xff0c;如{msg&#xff1a;params error}&#xff0c;可尝使用字典模糊测试构造参数&#xff0c;进一步攻击。 2、程序溢出&#xff0c;int最大值为2147483647&#xff0c;可尝试使用该值进行整数溢出&#xff0c;观察现象。 3、403&#xff0c;404响…

如何使用MATLAB写测试(2)Negative Test

如何使用MATLAB写测试&#xff08;2&#xff09;Negative Test 原文&#xff1a;如何使用MATLAB写测试&#xff08;2&#xff09;Negative Test - 知乎 (zhihu.com) 上一篇请参见 如何使用MATLAB写测试&#xff08;1&#xff09; - 知乎专栏 上一篇中&#xff0c;我们的实习…

【YashanDB知识库】ODBC驱动类问题定位方法

【标题】ODBC驱动类问题定位方法 【需求分类】故障分析 【关键字】ODBC 【需求描述】由于我们的ODBC接口目前尚不完善&#xff0c;经常会遇见ODBC接口能力不足导致应用功能无法运行的问题&#xff0c;需要定位手段确定底层是哪个接口报错 【需求原因分析】方便一线数据库管…

【python】修改目标检测的txt标签(yolo)的类别ID映射

脚本功能&#xff1a; 针对目录下的所有yolo格式的txt标签文件&#xff0c;将class类别的id修改为指定id。 实际应用常见不多 代码 # -*- coding: utf-8 -*- # Time : 2023/9/11 10:58 # Author : CLW # FileName: change_txt_label.py # Software: PyCharmimport os 算法功…