BoostCompass(数据准备预处理模块)

在这里插入图片描述

阅读导航

  • 一、网页数据下载
  • 二、编写数据去标签与数据清洗的模块 Parser
    • ✅boost 开发库的安装
    • 1. 基本思路
    • 2. 详细讲解
      • (1)程序递归遍历目录,收集所有HTML文件的路径
      • (2)对每个HTML文件进行解析,提取出文档标题、内容和URL
      • (3)将这些信息保存到一个文本文件中,每个文档信息之间用特定分隔符隔开
  • 三、结果验证
    • 1. 编辑makefile文件
    • 2. 生成可执行程序

一、网页数据下载

🔴下载网页界面链接

在这里插入图片描述

  1. 打开了上面的网页以后下载boost_1_84_0.tar.gz压缩包就可以了。

  2. 下载以后,打开Linux建立相关目录,在这个目录下输入rz -E命令选中刚才我们下载的压缩包,把压缩包传输进Linux机器中。

  3. 在控制台输入tar xzf boost_1_84_0.tar.gz进行解压
    在这里插入图片描述

  4. 解压出来上面的这些文件,我们需要的数据是在文件夹doc/html里面,我们把它复制到我们创建的data/input文件夹里面使用cp -rf boost_1_84_0/doc/html/* data/input

  5. 把刚才解压过的文件删除了就可以了。

我们已经收集到了网页的初始信息,但是在这些信息中存在着一些无用的网页标签和其他数据,需要进行清理处理,以便我们能够更好地分析和利用这些数据。

二、编写数据去标签与数据清洗的模块 Parser

✅boost 开发库的安装

PS:我们要先在Linux机器上安装Boost库:sudo yum install -y boost-devel

1. 基本思路

  1. 程序递归遍历目录,收集所有HTML文件的路径;
  2. 对每个HTML文件进行解析,提取出文档标题、内容和URL;
  3. 将这些信息保存到一个文本文件中,每个文档信息之间用特定分隔符隔开。

✅整个处理流程由main函数协调,涉及文件操作、字符串解析和错误处理等技术,旨在高效地从HTML文件中提取结构化数据,为后续的数据使用或分析提供便利。

2. 详细讲解

(1)程序递归遍历目录,收集所有HTML文件的路径

  • 程序代码
// 遍历目录,获取所有HTML文件的路径
bool EnumFile(const std::string &src_path, std::vector<std::string> *files_list) {namespace fs = boost::filesystem;fs::path root_path(src_path);// 检查路径是否存在if (!fs::exists(root_path)) {std::cerr << src_path << " not exists" << std::endl;return false;}// 使用递归目录迭代器遍历目录fs::recursive_directory_iterator end;for (fs::recursive_directory_iterator iter(root_path); iter != end; iter++) {// 跳过非普通文件if (!fs::is_regular_file(*iter)) {continue;}// 跳过非HTML文件if (iter->path().extension() != ".html") {continue;}// 将HTML文件路径添加到列表中files_list->push_back(iter->path().string());}return true;
}
  • 代码解释

函数接受一个字符串参数src_path,这个参数表示需要遍历的目录路径。函数的返回类型是bool,表示操作的成功与否。函数还接受一个指向std::vector<std::string>的指针作为参数,这个向量用于存储找到的HTML文件路径。

在函数内部,首先创建了一个boost::filesystempath对象,用于表示传入的源路径。接着,使用fs::exists函数检查这个路径是否存在。如果路径不存在,函数输出错误信息并返回false

如果路径存在,函数使用fs::recursive_directory_iterator来创建一个迭代器,这个迭代器可以遍历目录及其所有子目录。迭代器的结束状态由end变量表示。在迭代过程中,函数检查每个文件是否是普通文件(fs::is_regular_file),如果不是,则跳过。然后,检查文件扩展名是否为.html,如果不是HTML文件,也跳过。

对于每个符合条件的HTML文件,使用iter->path().string()获取其完整的路径字符串,并将其添加到传入的files_list向量中。

(2)对每个HTML文件进行解析,提取出文档标题、内容和URL

  • 程序代码
// 辅助函数,用于解析HTML文件中的标题
static bool ParseTitle(const std::string &file, std::string *title)
{// 查找标题起始位置std::size_t begin = file.find("<title>");if(begin == std::string::npos){   // 如果未找到标题起始标记return false;    // 返回失败}// 查找标题结束位置std::size_t end = file.find("</title>");if(end == std::string::npos){   // 如果未找到标题结束标记return false;   // 返回失败}begin += std::string("<title>").size(); // 调整起始位置,跳过"<title>"if(begin > end){ // 如果起始位置在结束位置之后return false; // 返回失败}// 提取标题内容*title = file.substr(begin, end - begin);return true; // 返回成功
}// 辅助函数,用于解析HTML文件中的内容(去除HTML标签)
static bool ParseContent(const std::string &file, std::string *content)
{//去标签,基于一个简易的状态机enum status{LABLE,   // 标签状态CONTENT  // 内容状态};enum status s = LABLE; // 初始化状态为标签状态for( char c : file){   // 遍历文件中的每个字符switch(s){         // 根据当前状态进行处理case LABLE:    // 当前状态为标签状态if(c == '>') s = CONTENT; // 如果遇到'>',切换到内容状态break;case CONTENT:  // 当前状态为内容状态if(c == '<') s = LABLE; // 如果遇到'<',切换到标签状态else {//这里不需要保留原始文件中的\n,因为后面要用\n作为html解析之后文本的分隔符if(c == '\n') c = ' '; // 将换行符替换为空格content->push_back(c); // 将字符添加到内容中}break;default:break;}}return true; // 返回成功
}// 辅助函数,用于构建文档的URL
static bool ParseUrl(const std::string &file_path, std::string *url)
{// 构造URL头部std::string url_head = "https://www.boost.org/doc/libs/1_78_0/doc/html";  // 提取URL尾部std::string url_tail = file_path.substr(src_path.size());// 拼接URL*url = url_head + url_tail;return true; // 返回成功
}// 解析HTML文件,提取标题、内容和URL
bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfo_t> *results) {for (const std::string &file : files_list) {// 读取文件内容std::string file_content;if (!ns_util::FileUtil::ReadFile(file, &file_content)) {continue;}// 解析标题DocInfo_t doc;if (!ParseTitle(file_content, &doc.title)) {continue;}// 解析内容(去除HTML标签)if (!ParseContent(file_content, &doc.content)) {continue;}// 解析URLif (!ParseUrl(file, &doc.url)) {continue;}// 将解析结果添加到结果集中results->push_back(std::move(doc));}return true;
}
  • 代码解释
  1. ParseTitle 函数

    • 这个函数的目的是从一个HTML文件字符串中提取标题(<title>标签内的内容)。
    • 它首先查找<title>标签的开始位置,如果没有找到,返回false
    • 然后,它查找</title>标签的结束位置,如果没有找到,同样返回false
    • 如果找到了开始和结束位置,函数会计算标题的实际长度,并使用substr方法提取标题内容。
    • 最后,将提取的标题内容通过指针参数title返回,并返回true表示成功。
  2. ParseContent 函数

    • 此函数用于去除HTML文件内容中的所有标签,只保留纯文本。
    • 它使用一个简单的状态机来区分标签和内容状态。
    • 遍历文件中的每个字符,如果是标签状态(LABLE),遇到>字符则切换到内容状态(CONTENT)。
    • 在内容状态下,遇到<字符则切换回标签状态,其他字符(除了换行符\n,将其替换为空格)则添加到内容字符串中。
    • 最终,通过指针参数content返回处理后的纯文本内容,并返回true表示成功。
  3. ParseUrl 函数

    • 这个函数用于构建一个文档的完整URL。
    • 它首先定义了一个URL的基础部分,然后从文件路径中提取特定部分作为URL的尾部。
    • 通过拼接基础URL和尾部路径,构建完整的URL字符串。
    • 通过指针参数url返回构建的URL,并返回true表示成功。
  4. ParseHtml 函数

    • 这是一个整合函数,它接收一个包含HTML文件路径的向量,并返回一个包含解析结果的DocInfo_t类型的向量。
    • 对于每个文件路径,它首先读取文件内容,然后依次调用ParseTitleParseContentParseUrl函数来提取标题、内容和URL。
    • 如果任何一个步骤失败,它会跳过当前文件并继续处理下一个文件。
    • 最后,将所有解析成功的文档信息添加到结果集中,并返回true表示解析过程完成。

🍁这些函数共同工作,提供了一个从HTML文件中提取有用信息的解决方案。它们可以用于构建搜索引擎索引、内容摘要或其他需要从HTML中提取数据的场景。代码结构清晰,通过模块化的设计提高了可读性和可维护性。

(3)将这些信息保存到一个文本文件中,每个文档信息之间用特定分隔符隔开

  • 程序代码
// 保存解析结果到文件
#define SEP '\3' // 定义分隔符
bool SaveHtml(const std::vector<DocInfo_t> &results, const std::string &output) {std::ofstream out(output, std::ios::out | std::ios::binary); // 以二进制方式进行写入if (!out.is_open()) {std::cerr << "open " << output << " failed!" << std::endl;return false;}// 遍历结果集,将每个文档的信息写入文件for (auto &item : results) {std::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;
}
  • 代码解释
  1. 定义分隔符

    • 使用预处理器指令#define定义了一个名为SEP的宏,其值为\3。这个宏用于在保存到文件的文档信息之间创建一个分隔符,以便在后续读取文件时能够区分不同的文档记录。
  2. 打开文件

    • 使用std::ofstream创建一个输出文件流out,尝试以二进制模式打开指定的输出文件。这种模式可以确保写入的数据不会被转换或解释为文本文件中的字符,而是以原始字节形式保存。
  3. 检查文件是否成功打开

    • 通过调用out.is_open()检查文件是否成功打开。如果文件没有成功打开,则输出错误信息到标准错误流std::cerr,并返回false
  4. 写入文档信息

    • 如果文件成功打开,函数遍历results向量中的每个DocInfo_t结构体。
    • 对于每个结构体,创建一个字符串out_string,并将结构体中的titlecontenturl字段依次拼接,每个字段后跟一个定义好的分隔符SEP,并在每条记录的末尾添加换行符\n
    • 使用out.write()函数将out_string的内容写入到文件中。out.write()接受两个参数:指向要写入数据的指针和要写入的字节数。
  5. 关闭文件

    • 在所有文档信息都写入文件后,调用out.close()关闭文件。这是一个好的编程实践,可以确保所有的数据都已经被刷新到磁盘,并且释放与文件相关的资源。

整体而言,SaveHtml函数负责将解析后的文档信息以一种结构化的方式保存到文件中,以便后续的处理或分析。通过使用二进制模式和特定的分隔符,该函数确保了数据的完整性和可读性。

三、结果验证

完成了上述代码后,我们的基本架构已经基本完成。接下来,我们需要编写一个名为makefile的文件,以便进行编译和验证结果。

1. 编辑makefile文件

Parser=parser.PHONY:all
all:$(Parser)$(Parser):parser.cpp$(cpp) -o $@ $^ -lboost_system -lboost_filesystem -std=c++11.PHONY:clean
clean:rm -f $(Parser) 

2. 生成可执行程序

  1. 在控制台输入:make指令,会生成一个名字为parser的可执行程序
    在这里插入图片描述
  2. 输入:./parser命令,执行可执行程序
  3. 打开文件data/raw_html/raw.txt就可以看到数据处理后的结果了,如下图(PS:/3在ASCII码表中表示^c

在这里插入图片描述

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

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

相关文章

【资源分享】书籍:现代统计学:使用Python的计算方法

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…

【微服务】------微服务架构技术栈

目前微服务早已火遍大江南北&#xff0c;对于开发来说&#xff0c;我们时刻关注着技术的迭代更新&#xff0c;而项目采用什么技术栈选型落地是开发、产品都需要关注的事情&#xff0c;该篇博客主要分享一些目前普遍公司都在用的技术栈&#xff0c;快来分享一下你当前所在用的技…

Java每日一题(三道同一类型的题)

前言 本文一共有三道题:1.两数之和 2.三数之和 3. 四数之和 为什么把这三道题放一起呢&#xff0c;因为三数之和是可以根据两数之和进行推导&#xff0c;四数之和可以根据三数之和进行推导。 两数之和 思路分析: 我的思路: 1.排序 2.使用左右指针 3.处理细节问题 先让数组…

生活中的数学 --- 等额本息贷款和等额本金贷款的月供应该怎么算?

等额本息贷款和等额本金贷款的月供应该怎么算&#xff1f; 从一个例子开始&#xff0c;假设我要从银行贷款36万(即&#xff0c;本金)&#xff0c;银行给出的贷款年利率是12%(月利率为年利率除以12)&#xff0c;贷款半年(6个月)&#xff0c;按月还款&#xff0c;分6期还完。 问分…

电池二次利用走向可持续大循环周期的潜力和挑战(第二篇)

一、二次利用风险 电动汽车的当前电池信息&#xff0c;如年份、容量和制造商&#xff0c;通常是相互关联和不完整的。再加上电池内部的电化学变化&#xff0c;SLB在包括安全和环境在内的一些领域存在很大的风险&#xff0c;这表明短期内梯次利用仍然是一个不成熟的方案。 1.1 安…

在mysql中如何更新数据呢?

如何更新一条数据&#xff1f; 在 MySQL 中&#xff0c;更新一条数据可以使用 UPDATE 语句。以下是更新一条数据的基本语法&#xff1a; UPDATE table_name SET column1 value1, column2 value2,... WHERE condition;其中&#xff1a; table_name&#xff1a;要更新的表的…

Linux 系统下对于 MySQL 的初级操作

由于公司老板想把早已封存的服务器陈年老码捣鼓一下&#xff0c;所以找了一个外援&#xff0c;我则是配合提供支持。但是过程并不顺利。至少 5 年以上的间隔&#xff0c;导致外援查看的时候发现很多代码和配置是缺失的&#xff0c;目前卡在数据库部分&#xff0c;而我这边就帮忙…

libVLC 提取视频帧使用QGraphicsView渲染

在前面章节中&#xff0c;我们讲解了如何使用QWidget渲染每一帧视频数据&#xff0c;这种方法对 CPU 负荷较高。 libVLC 提取视频帧使用QWidget渲染-CSDN博客 后面又讲解了使用OpenGL渲染每一帧视频数据&#xff0c;使用 OpenGL去绘制&#xff0c;利用 GPU 减轻 CPU 计算负荷…

亚马逊AWS永久免费数据库

Amazon DynamoDB 是一项无服务器的 NoSQL 数据库服务&#xff0c;您可以通过它来开发任何规模的现代应用程序。作为无服务器数据库&#xff0c;您只需按使用量为其付费&#xff0c;DynamoDB 可以扩展到零&#xff0c;没有冷启动&#xff0c;没有版本升级&#xff0c;没有维护窗…

交换机与队列的介绍

1.流程 首先先介绍一个简单的一个消息推送到接收的流程&#xff0c;提供一个简单的图 黄色的圈圈就是我们的消息推送服务&#xff0c;将消息推送到 中间方框里面也就是 rabbitMq的服务器&#xff0c;然后经过服务器里面的交换机、队列等各种关系&#xff08;后面会详细讲&…

RabbitMQ如何保证消息的幂等性???

在RabbitMQ中&#xff0c;保证消费者的幂等性主要依赖于业务设计和实现&#xff0c;而非RabbitMQ本身提供的一种直接功能。 在基于Spring Boot整合RabbitMQ的场景下&#xff0c;要保证消费者的幂等性&#xff0c;通常需要结合业务逻辑设计以及额外的技术手段来实现。以下是一个…

Elasticsearch 悬挂索引分析和自己的一点见解

在 Elasticsearch 的实战中&#xff0c;悬挂索引是一个既常见又容易引起困扰的概念。 今天&#xff0c;我将分享一次处理集群状态为RED&#xff0c;原因为DANGLING_INDEX_IMPORTED 的实战经验&#xff0c;深入探讨悬挂索引的定义、产生原因、管理方法&#xff0c;以及如何有效…

[Linux - C语言] 自主Shell

[Linux - C语言] 自主Shell [Linux - C语言] 自主Shell逻辑策划 main()打印命令行 void MakeCommandLineAndPrint()用户名 USER主机名 HOSTNAME当前目录 PWDSkipPath 切割目录打印命令行 获取用户字符串 int GetUserCommand()检查重定向 void CheckRedir()切割字符 void SplitC…

JVM字节码与类的加载——类的加载过程详解

文章目录 1、概述2、加载(Loading)阶段2.1、加载完成的操作2.2、二进制流的获取方式2.3、类模型与Class实例的位置2.4、数组类的加载 3、链接(Linking)阶段3.1、链接阶段之验证(Verification)3.1.1、格式检查3.1.2、字节码的语义检查3.1.3、字节码验证3.1.4、符号引用验证 3.2、…

Harmony鸿蒙南向驱动开发-I3C

I3C&#xff08;Improved Inter Integrated Circuit&#xff09;总线是由MIPI Alliance开发的一种简单、低成本的双向二线制同步串行总线。 I3C是两线双向串行总线&#xff0c;针对多个传感器从设备进行了优化&#xff0c;并且一次只能由一个I3C主设备控制。相比于I2C&#xf…

langchain LCEL,prompt模块,outputparse输出模块

目录 基本代码 prompt模块 prompt模版控制长度 outputparse格式化输出 LangChain表达式语言&#xff0c;或者LCEL&#xff0c;是一种声明式的方式&#xff0c;可以轻松地将链条组合在一起 langchian 可以使用 通义千问&#xff0c;我们用通义千问&#xff0c;用法也要申请…

基于ros的相机内参标定过程

基于ros的相机内参标定过程 1. 安装还对应相机的驱动2. 启动相机节点发布主题3. 下载camera_calibartion4. 将红框的文件夹复制在自己的工作空间里边&#xff0c;编译5. 标定完成以后&#xff0c;生成内参参数文件camera.yaml。将文件放在对应的路径下&#xff0c;修改config文…

ArcGIS Server 10发布要素服务时遇到的数据库注册问题总结(一)

工作环境&#xff1a; Windows 7 64 位旗舰版 ArcGIS Server 10.1 ArcGIS Desktop 10.1 IIS 7.0 开始的时候以为10.1发布要素服务和10.0一样&#xff0c;需要安装ArcSDE&#xff0c;后来查阅资料发现不需要&#xff0c;数据库直连方式就可以了。 首先我来说一下发布要素服…

stm32开发之threadx+netxduo(tcp 服务端使用记录)

前言 本篇需要用到threadx之动态内存的实现记录 里面的动态内存分配管理代码.开发环境使用的stm32cubemxclion组合芯片使用的是stm32f407zgt6,网口使用的是lan8720&#xff0c;使用cubemx提供的lan8742也可以驱动&#xff0c;注意实际的网口与芯片的引脚 示例代码 tcp 服务端…