HTML文本中移除所有HTML标记并提取纯文本是我们经常需要使用的文本内容处理方式,比如搜索引擎、网站爬虫或者本地文档检索系统需要提取网页或HTML文档的实际内容进行索引。通过去除HTML标签,可以专注于实际的文字信息,提高搜索结果的相关性和准确性。在新闻聚合应用或社交媒体平台上展示网页链接的摘要时,通常会提取并显示纯文本内容以提供简洁的预览。对于视觉障碍人士使用的辅助技术如屏幕阅读器,它们无法解析复杂的HTML结构,因此需要提取纯文本以便朗读给用户。所以今天给大家分享一个使用正则表达式移除所有的Html标记的方法,供有需要的朋友们参考:
第一个核心代码是:正则表达式"<.*?>"
// 示例用法:
string inputHtml = "<html><body><h1>Hello, World!</h1>This is a <b>test</b>.</body></html>";
string plainText = RemoveHtmlTags(inputHtml);
Console.WriteLine(plainText); // 输出: "Hello, World!This is a test."
public static string RemoveHtmlTags(string html)
{
// 正则表达式用于匹配HTML标签
Regex regex = new Regex("<.*?>", RegexOptions.Singleline | RegexOptions.Compiled);
// 使用正则表达式的Replace方法移除所有匹配的HTML标签
string result = regex.Replace(html, String.Empty);
return result;
}
这个正则表达式<.*?>是非贪婪匹配任何以 < 开始、以 > 结束的字符串,它会尽可能少地匹配字符以找到每个HTML标签。
请注意,虽然此方法对于简单场景可能有效,但对复杂的HTML文档(特别是含有嵌套标签、注释、CDATA等内容)可能不够健壮,因为它无法处理所有可能的HTML结构。
第二个核心代码是:正则表达式"<[^>]*>"
public static string ExtractPlainTextFromHtml(string html)
{
// 使用正则表达式匹配所有的HTML标签
// 注意:这个简单的正则表达式适用于大多数基础HTML结构,但可能无法处理复杂嵌套或特殊格式的HTML
Regex regex = new Regex("<[^>]*>", RegexOptions.Singleline | RegexOptions.Compiled);
// 使用Replace方法去除所有匹配到的HTML标签,并返回纯文本内容
string plainText = regex.Replace(html, String.Empty);
return plainText.Trim(); // 为了得到更整洁的结果,可以对结果进行trim操作以去除多余的空白字符
}
在这段代码中,我们定义了一个名为ExtractPlainTextFromHtml的方法,该方法利用正则表达式 <[^>]*> 来查找并替换所有HTML标签。这里的正则表达式表示任何以 < 开始、以 > 结束的非空字符串(即HTML标签),Singleline 选项使.能匹配换行符,以便跨多行搜索标签,而 Compiled 选项则是为了优化正则表达式的性能。
第二个核心代码是:正则表达式"<[^>]*>"
public static string RemoveHtmlTags(string html)
{
// 正则表达式,匹配所有HTML标签
string pattern = "<[^>]+>";
// 使用Regex.Replace方法移除所有匹配的HTML标签
return Regex.Replace(html, pattern, String.Empty);
}
请注意,此方法仅移除HTML标记,不会解析或处理嵌入在HTML中的JavaScript代码或其他非标记内容。此外,此方法也无法处理不规范或不符合预期格式的HTML标记。如果需要更复杂的HTML解析或清理,您可能需要使用专门的HTML解析库,如AngleSharp或HtmlAgilityPack等。
尽管上述方法对于许多简单场景已经足够有效,但在面对复杂的HTML文档时,由于HTML本身的嵌套和特殊结构,简单的正则表达式可能无法完美地解析并移除所有标签。在这种情况下,推荐使用专门为处理HTML设计的库,如HtmlAgilityPack,它可以准确地解析HTML并提供丰富的API用于提取纯文本内容。
今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受。这么好的光阴怎么浪费,睡觉、吃饭、打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完。
这篇文章比较基础,在国庆期间的业余时间写的,这几天又完善了下,力求把更多的前端所涉及到的关于文件上传的各种场景和应用都涵盖了,若有疏漏和问题还请留言斧正和补充。
以下是本文所涉及到的知识点,break or continue ?
原理很简单,就是根据 http 协议的规范和定义,完成请求消息体的封装和消息体的解析,然后将二进制内容保存到文件。
我们都知道如果要上传一个文件,需要把 form 标签的enctype设置为multipart/form-data,同时method必须为post方法。
那么multipart/form-data表示什么呢?
multipart互联网上的混合资源,就是资源由多种元素组成,form-data表示可以使用HTML Forms 和 POST 方法上传文件,具体的定义可以参考RFC 7578。
multipart/form-data 结构
看下 http 请求的消息体
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次请求要上传文件,其中boundary表示分隔符,如果要上传多个表单项,就要使用boundary分割,每个表单项由———XXX开始,以———XXX结尾。
每一个表单项又由Content-Type和Content-Disposition组成。
Content-Disposition: form-data 为固定值,表示一个表单元素,name 表示表单元素的 名称,回车换行后面就是name的值,如果是上传文件就是文件的二进制内容。
Content-Type:表示当前的内容的 MIME 类型,是图片还是文本还是二进制数据。
解析
客户端发送请求到服务器后,服务器会收到请求的消息体,然后对消息体进行解析,解析出哪是普通表单哪些是附件。
可能大家马上能想到通过正则或者字符串处理分割出内容,不过这样是行不通的,二进制buffer转化为string,对字符串进行截取后,其索引和字符串是不一致的,所以结果就不会正确,除非上传的就是字符串。
不过一般情况下不需要自行解析,目前已经有很成熟的三方库可以使用。
至于如何解析,这个也会占用很大篇幅,后面的文章在详细说。
使用 form 表单上传文件
在 ie时代,如果实现一个无刷新的文件上传那可是费老劲了,大部分都是用 iframe 来实现局部刷新或者使用 flash 插件来搞定,在那个时代 ie 就是最好用的浏览器(别无选择)。
DEMO
这种方式上传文件,不需要 js ,而且没有兼容问题,所有浏览器都支持,就是体验很差,导致页面刷新,页面其他数据丢失。
HTML
<form method="post" action="http://localhost:8100" enctype="multipart/form-data">
选择文件:
<input type="file" name="f1"/> input 必须设置 name 属性,否则数据无法发送<br/>
<br/>
标题:<input type="text" name="title"/><br/><br/><br/>
<button type="submit" id="btn-0">上 传</button>
</form>
复制代码
服务端文件的保存基于现有的库koa-body结合 koa2实现服务端文件的保存和数据的返回。
在项目开发中,文件上传本身和业务无关,代码基本上都可通用。
在这里我们使用koa-body库来实现解析和文件的保存。
koa-body 会自动保存文件到系统临时目录下,也可以指定保存的文件路径。
然后在后续中间件内得到已保存的文件的信息,再做二次处理。
NODE
/**
* 服务入口
*/
var http = require('http');
var koaStatic = require('koa-static');
var path = require('path');
var koaBody = require('koa-body');//文件保存库
var fs = require('fs');
var Koa = require('koa2');
var app = new Koa();
var port = process.env.PORT || '8100';
var uploadHost= `http://localhost:${port}/uploads/`;
app.use(koaBody({
formidable: {
//设置文件的默认保存目录,不设置则保存在系统临时目录下 os
uploadDir: path.resolve(__dirname, '../static/uploads')
},
multipart: true // 开启文件上传,默认是关闭
}));
//开启静态文件访问
app.use(koaStatic(
path.resolve(__dirname, '../static')
));
//文件二次处理,修改名称
app.use((ctx) => {
var file = ctx.request.files.f1;//得道文件对象
var path = file.path;
var fname = file.name;//原文件名称
var nextPath = path+fname;
if(file.size>0 && path){
//得到扩展名
var extArr = fname.split('.');
var ext = extArr[extArr.length-1];
var nextPath = path+'.'+ext;
//重命名文件
fs.renameSync(path, nextPath);
}
//以 json 形式输出上传文件地址
ctx.body = `{
"fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
}`;
});
/**
* http server
*/
var server = http.createServer(app.callback());
server.listen(port);
console.log('demo1 server start ...... ');
复制代码
CODE
https://github.com/Bigerfe/fe-learn-code/
近在抓取一些比较有价值的网站资源,用于训练AI写作系统,保证AI能在我采集的庞大数据库中学会利用一个命题就可以创作高质量原创文章。对!我说的是原创文章,不是伪原创。至于这个AI写作的系统将会在我成功后与大家展开更为细致的分享,今天我们的主题是,如何通过火车头采集器批量采集网站文章。
软件:火车头采集器/高铁采集器
使用环境:PC端
进入待采集网站,打开需要采集的栏目或者待采集的关键词搜索列表。
待采集网页
确定这个栏目的文章页数,翻到底部发现总页数为15,确定采集页数为15。
网站页码位置
;跳转到下一页,确定网页的起始网址格式,变量基本是.html前面的序号,所以我们先直接复制下来。
进入高铁采集器,点击+按钮跳出任务设置页面。
高铁采集器/火车头采集器
点击网页采集规则页面的起始网页右边的第一个按钮进入向导,填入复制下来的页面地址,并将页面的变量替换成右边的地址参数,直接删掉原页码然后点击按钮插入就可以。
网址采集规则
最终会自动生成一个采集列表文章的链接,但这只是采集页面数据,并没有将需要的内容精确地采集到。
采集起始网址
因为需要让机器知道我们要采集哪些数据,所以我们要在网页代码中找到开头和结尾的标志,以便机器采集。
右击网页空白处查看网页源代码
查看页面源代码
由于源码大多是一行显示,所以我们需要勾选源码顶部的“换行”复选框。
勾选换行复选框
Ctrl+F 搜索源代码中包含列表页的第一条数据的标题,并寻找与该标题临近的一个唯一标签。
查找是否唯一
<h1><span>产品运营</span></h1> </div> <div class="sec-panel-body">
在这段代码中,我选择了 “<divclass="sec-panel-body">” 作为识别开头的代码。
同样的方式,我搜寻列表页的最后一条数据的标题,找到了识别结尾的代码。
是否是唯一且能识别到的代码,我们也可以通过 Ctrl+F 去查找,只要搜索数据是唯一的就是了。
填写起始代码
填入写好的起始和结束代码后,点击右下角的网页测试按钮测试采集数据是否正常。
测试是否能采集到需要的网址
让机器采集一部分列表页数据就可以停止了,然后看到采集的数据是比较多的,有些数据不是我们需要的数据页,所以我们需要将其排除。
查阅到内容页的地址为/n/(*).html,所以我们可以用网页格式去锁定采集地址。
确定地址栏规则
在链接过滤处选择链接包含并填入刚才的格式
过滤不需要的链接
接下来发现内容页地址采集正常。
正确获取需要的地址
接下来我们就需要写内容页的采集规则,这里比较复杂,需要认真看。在最近的测试中,发现对于新手来说也并不是难事,因为逻辑一样的,多去调试就行了。
进入内容采集规则页面,内置有标题和内容,这里我多加两条数据“作者”和“日期”,以便大家更深理解。
内容采集规则
我们在采集过程中可能需要更多的数据,基本上都可以按照我说的操作采集出来。
同样,在文章页面右击调出源代码,我按标题、作者、时间、内容的顺序教大家写采集规则。
首先,我们查找到文章标题的位置,确定位置在<h1>标签内,其实大部分的页面都是<h>标签,只是里面的样式不同而已。
找到标题位置
<h1 class="entry-title">标题</h1>
接着直接看后面的代码,通过一些标志,看到作者和时间,这时候就确定了时间和地址。
找到作者和日期位置
<a class="nickname url fn j-user-card">作者</a> </span> <span class="dot">•</span> <time class="entry-date published" datetime="2022-10-31T08:17:06+08:00" pubdate> 2022年10月31日 08:17:06 </time>
然后再看接下来的内容,去找找内容的代码。
通过文章内容找到旁边的div标签是唯一识别的标签(经验之谈,一般在class中包含content),咱们就可以确定内容的开始标签。
找到内容位置
<div class="entry-content text-indent">
同样的方法,找到结尾词旁边的标签为:
<div class="entry-readmore">
这就确定了标题、作者、时间、内容了,接下来需要去软件内写清楚规则。
我们提取标题优先选择正则提取,并将复制的所有变量在匹配内容中用[参数]代替,在组合结果中直接点击[参数1]。
设置标题提取规则
同样我也选择用正则提取,由于某些数据是变量且不需要,我们直接用(*)代替即可,需要的内容用[参数]替代,并在组合结果中选择[参数1]。
设置作者提取规则
因为我想给大家讲一下为什么有[参数1]、[参数2]、[参数N],所以我使用多个参数进行举例。
在这里,我把标签中的参数作为我的结果,将标签中的内容直接丢掉了,但是获取的结果是一样的。
设置日期提取规则
所以在写规则的时候也不一定要中规中矩按别人教你的来,只要保证数据准确就行。
④内容 这里不需要多说,因为前面我们分析过,前后截取的代码已经知道,直接填进去。
设置内容提取规则
但是要考虑到不同页面中的开头和结尾可能是变量,所以我们要多打开一些文章去查看网页代码,毕竟某些页面开头有引言,有的结尾有版权声明。
现在规则写好了,我们需要找个页面测试下,我们发现数据采集是正确的,现在基本的采集就完成了。
找几个页面测试下
对于我来说,AI写作训练不需要标签,所以我需要在采集的时候直接过滤掉,所以我在内容标签下的数据处理中,选择html标签过滤,直接全选了所有标签。为了阅读方便,我取消了换行和所有标签,当然我们也可以通过对数据的处理输出我们需要的内容。
html标签过滤
html标签过滤
我们不设置内容发布规则的话,会导致文章采集了无法输出。
由于我只需要将数据输出为文档供AI学习,包括web在线发布和导入数据库都包含比较复杂的对应关系,所以输出这里我只讲保存本地文件这一项。
内容发布规则
我们将本地文件保存打开,以txt文件格式输出为例,我们选择txt,并设置保存位置为自定义位置,文件模板我使用的是:
文章格式
把它保存为txt文件,并将文件模板选择为这个文件,软件就会按照这个格式去输出文章了。
所有设置都配置好了之后就直接保存并退出,然后进入主页面,勾选任务右边的“采网址”、“采内容”、“发布”复选框,右击任务并选择开始即可,如果看到运行日志中运行正常就可以让它静默采集了,如果有提示错误,分析错误产生原因,然后对症下药就行了。
直接采集并发布
以下是输出的案例:
采集到的内容
我们在采集中一定不会像我说得这么简单,所以我把我遇到的坑提前告知大家,以免大家走弯路。
采集的数据为空白有一部分原因是原文就是空白的,比如网页上面的问答,如果没有回答,他的内容就是空的。还有就是采集规则不适用于所有页面,重新制定新的规则,保证所有数据能够输出为止。
有时候我们采集的数据是全空,这大概率是因为网速问题或者是网站问题,重新采集即可,因为没有采集到的数据会标注未采和未发。
由于某篇文章在不同的标签或者板块下,软件不会直接帮你过滤,但是我们可以通过设置标签下的内容过滤,勾选“采集内容不得为空重复”的按钮。(勾选“采集内容不得为空”也可以解决问题1)
内容过滤
这里我们在采集后会发现有很多版权词或者一些需要过滤的词,不必重新设置采集规则,而是在本地数据中,选择所有数据,并对特定标签中的特定内容直接进行替换或者过滤即可。
替换内容
以上原创教程仅用于学术交流,请勿搬运或用于不法用途,大佬请直接关闭本文。
*请认真填写需求信息,我们会在24小时内与您取得联系。