項目日記(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.pswp.cn/bicheng/19029.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/19029.shtml
英文地址,請注明出處:http://en.pswp.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 算法功…