使用xpath实现document.querySelector样式选择器进行html解析(四):将选择结果封装进行输出

本文主要是介绍使用xpath实现document.querySelector样式选择器进行html解析(四):将选择结果封装进行输出,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

使用xpath实现document.querySelector样式选择器进行html解析(一):将html转成xml

使用xpath实现document.querySelector样式选择器进行html解析(二):扩展一下xpath以便支持正则

使用xpath实现document.querySelector样式选择器进行html解析(三):实现样式选择器

使用xpath实现document.querySelector样式选择器进行html解析(四):将选择结果封装进行输出

-----------------------------------------------------------------

恩,其实到目前为止,关于xpath解析html的样式选择器其实已经完工了,而且,应该说比预期的目的还多出了一丢丢的效果

例如:QuerySelector("*[style*='(?<!\w)font-weight\s*:\s*bold(?!\w)']"),可以选中所有style属性中包含粗体定义的节点

例如:QuerySelector("*:contains(abc.*?xyz)"),可以选中所有正文中包含abc和xyz,且abc在xyz之前的节点

注意到没有,我们可以直接使用正则,当然了,第三章我贴的伪类contains处理之前的那个正则不支持圆括号输入,关于指定属性的正则不支持方括号输入,自己魔改一下就可以完整的支持正则了,或者比较麻烦,需要层深计算,但还是可以实现的,可以参考文盲老顾之前关于正则的博文,但是个人感觉没什么必要了

本章为选择器的最后一章,关于结果输出方式的,有自己代码风格的可以不看,毕竟文盲老顾也是半路出家的c#工作者,没有考虑到的,没有学习到的东西都还很多,有更好的结果输出方案的也请告知文盲,让文盲继续进步哦

-----------------------------------------------------------------

为了方便得到结果之后直接可以用.连接属性,用来直接输出结果,所以QuerySelector方法我们修改一下
        public HtmlObjectResult QuerySelector(string selection){string xpath = CssParser.ParseCSS(selection);try{return new HtmlObjectResult(_xml.SelectNodes(xpath, XMLExpand.XPathExpand));}catch (Exception ex){throw ex;}}

直接将返回的XmlNodeList封装到一个类里,作为结果实现

    public class HtmlObjectResult{private List<HtmlObjectNode> _result = new List<HtmlObjectNode>();private int _curr = 0;public int Count{get{return _result == null ? 0 : _result.Count;}}public HtmlObjectNode[] NodeCollection{get{return _result.ToArray();}}public HtmlObjectNode Node{get{return _result == null ? null : _result[_curr];}}public HtmlObjectResult(XmlNodeList xnl){for (int i = 0; i < xnl.Count; i++){_result.Add(new HtmlObjectNode(xnl[i]));}}public HtmlObjectResult Next{get{_curr += _curr < _result.Count - 1 ? 1 : 0;return this;}}public HtmlObjectResult Previous{get{_curr -= _curr > 0 ? 1 : 0;return this;}}public HtmlObjectResult First{get{_curr = 0;return this;}}}

对于结果来说,它其实是一个节点集合,所以,提供一个Count,来表示到底有多少节点被选中

一般情况下,我们都是直接使用的第一个节点作为我们的结果,所以定义一个First,如果需要其他结果,可以用Next、Previous来选择不同的结果,恩,反正都是返回这个结果集本身,只是下标定位改变了而已

然后可以返回当前选中的结果作为输出内容,也就是Node属性,Node也是一个封装后的xml节点,稍后再讲

当然,如果不喜欢这些,可以直接输出所有的结果,NodeCollection可以满足你的需要,当然其中的元素也是被封装好的结果节点

再然后是正式输出我们期望的结果值了

    public class HtmlObjectNode{private XmlNode _node = null;public HtmlObjectNode(XmlNode node){_node = node;}public HtmlObjectNode Next{get{return _node == null ? null : _node.NextSibling != null ? new HtmlObjectNode(_node.NextSibling) : this;}}public HtmlObjectNode Previous{get{return _node == null ? null : _node.PreviousSibling != null ? new HtmlObjectNode(_node.PreviousSibling) : this;}}public HtmlObjectNode Parent{get{return _node == null ? null : _node.ParentNode != null ? new HtmlObjectNode(_node.ParentNode) : this;}}public string InnerHtml{get{return _node == null ? null : Regex.Replace(_node.InnerXml, @"<!\[CDATA\[|\]\]>", "", RegexOptions.IgnoreCase).Trim();}}public string OuterHtml{get{return _node == null ? null : Regex.Replace(_node.OuterXml, @"<!\[CDATA\[|\]\]>", "", RegexOptions.IgnoreCase).Trim();}}public string InnerText{get{return _node == null ? null : _node.InnerText;}}public XmlNode Node{get{return _node;}}}

作为被选中的节点,有时候我们需要纯文本内容,有时候需要html内容,html内容有时候需要包含节点本身,有时候不包含

所以,我们的结果输出就直接定义成三个,分别是InnerText、InnerHtml、OuterHtml,这个也符合html本身的习惯

由于我在第一章的时候,将html转成xml的时候还追加了不少的CDataSetion节点,这些节点在作为结果输出的时候应该被删除节点声明,所以我在这里用正则删除了一些信息

当然,有时候某些节点定位非常麻烦,可他相邻的部分节点非常好定位,那么我们通常会定位到我们希望选中的节点之前,例如有一个表格,很多行很多列,没有样式啦、ID啦,甚至数据的位置也可能改变,但表格的格式不变,比如每一个td声明数据名称后,下一个紧跟着的td必定是它对应的值的时候,我们就可以直接定位到这个数据名称的位置,例如 QuerySelector("td:contains(姓名)"),然后使用Next向后移动一个节点,再输出就是对应的值了:QuerySelector("td:contains(姓名)").First.Node.Next.InnerText

需要注意的是,Node之前的Next是在结果集中选择下一个对应的结果,Node之后的Next是在Html中对应的元素的下一个元素

好了,HtmlParser部分基本上讲完了,之后文盲老顾会尝试做一些数据提取方面新的尝试,在尽量减少指正的情况下,如何从页面内获取到我们想要的数据,例如自动解析表格之类的

这篇关于使用xpath实现document.querySelector样式选择器进行html解析(四):将选择结果封装进行输出的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/746664

相关文章

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令

Redis实现分布式锁全过程

《Redis实现分布式锁全过程》文章介绍Redis实现分布式锁的方法,包括使用SETNX和EXPIRE命令确保互斥性与防死锁,Redisson客户端提供的便捷接口,以及Redlock算法通过多节点共识... 目录Redis实现分布式锁1. 分布式锁的基本原理2. 使用 Redis 实现分布式锁2.1 获取锁

Python WebSockets 库从基础到实战使用举例

《PythonWebSockets库从基础到实战使用举例》WebSocket是一种全双工、持久化的网络通信协议,适用于需要低延迟的应用,如实时聊天、股票行情推送、在线协作、多人游戏等,本文给大家介... 目录1. 引言2. 为什么使用 WebSocket?3. 安装 WebSockets 库4. 使用 We

Linux实现查看某一端口是否开放

《Linux实现查看某一端口是否开放》文章介绍了三种检查端口6379是否开放的方法:通过lsof查看进程占用,用netstat区分TCP/UDP监听状态,以及用telnet测试远程连接可达性... 目录1、使用lsof 命令来查看端口是否开放2、使用netstat 命令来查看端口是否开放3、使用telnet

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

基于Java和FFmpeg实现视频压缩和剪辑功能

《基于Java和FFmpeg实现视频压缩和剪辑功能》在视频处理开发中,压缩和剪辑是常见的需求,本文将介绍如何使用Java结合FFmpeg实现视频压缩和剪辑功能,同时去除数据库操作,仅专注于视频处理,需... 目录引言1. 环境准备1.1 项目依赖1.2 安装 FFmpeg2. 视频压缩功能实现2.1 主要功

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php