HtmlAgilityPack中通过sibling才能得到对应的InnerText和form,option等tag的子节点

面试题-手撕NMS(非极大值抑制) 非极大值抑制(Non-Maximum Suppression,NMS)是一种常用于目标检测和计算机视觉中的算法,用于去除重叠的边界框,保留最可能是真实目标的边界框。其核心就是对一组检测框,找出其中属于同一个类别且分数最高的那个框,然后把和这个框的IOU值大于阈值的那些框都删掉。 阅读详情

转自:http://www.crifan.com/htmlagilitypack_html_tag_form_option_no_child_via_sibling_get_innertext/


最近在用HtmlAgilityPack解析HTML文件,用到的很奇怪的问题,这篇文章给了很详细解释和标准答案,收藏一下!



【背景】

之前使用HtmlAgilityPack期间,遇到了2个bug:

1. InnerText没有包含对应字符串(但是用NextSibling.InnerText却可以得到)

对于html:

?
1
<option value="search-alias=instant-video">Amazon Instant Video</option>

用如下的代码:

?
1
2
3
4
//<option value="search-alias=instant-video">Amazon Instant Video</option>
string searchValue = singleOptionNode.Attributes["value"].Value; //search-alias=instant-video
//instant-video
string generalCategory = singleOptionNode.InnerText; //CAN NOT get: Amazon Instant Video

是不工作的。

后来经过调试,改为:

?
1
2
3
4
//<option value="search-alias=instant-video">Amazon Instant Video</option>
string searchValue = singleOptionNode.Attributes["value"].Value; //search-alias=instant-video
//instant-video
string generalCategory = singleOptionNode.NextSibling.InnerText; //can get: Amazon Instant Video

却是可以的。

很是尼玛的诡异。

很明显是一个bug。

 

和:

2.丢失了form节点的input子节点

访问:

http://www.amazon.com/gp/offer-listing/B0083PWAPW/ref=dp_olp_all_mbc?ie=UTF8&condition=all

得到的html中,对应的部分是:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
<form method= "POST"  action= "/gp/item-dispatch/ref=olp_atc_fm_1"  >
     <input type= "hidden"  name= "session-id"  value= "182-0726239-4848949" >
     <input type= "hidden"  name= "qid"  value= "" >
     <input type= "hidden"  name= "sr"  value= "" >
     <input id= "signInToHUC"  type= "hidden"  value= "0"  name= "signInToHUC" >
     <input type= "hidden"  name= "metric-asin.B0083PWAPW"  value= "1" >
     <input type= "hidden"  name= "registryItemID.1"  value= "" >
     <input type= "hidden"  name= "registryID.1"  value= "" >
     <input type= "hidden"  name= "itemCount"  value= "1" >
     <input type= "hidden"  name= "offeringID.1" value= "%2F%2FeHHmpktM3oPoQj%2FOWhDI%2FpHyvwwFCwEfNIBEgFcfAHzKHAzVK%2BZfhkmBFO%2BPbow9JfdOmrE6eKME4ydhLTTK1Dgaf8O3N7SyOR%2F136TvVh0lfJypEt4Q%3D%3D" >
     <input type= "hidden"  name= "isAddon"  value= "0" >
     <input type= "image"  src= "http://g-ecx.images-amazon.com/images/G/01/x-locale/nav2/images/add-to-cart-md-p._V192250398_.gif"  align= "absmiddle" alt= "Add to cart"  border= "0"  height= "21"  name= "submit.addToCart"  width= "112" />
</form>

可以通过:

?
1
2
htmlDoc = crl.htmlToHtmlDoc(respHtml);
HtmlNodeCollection postItemNodeList = htmlDoc.DocumentNode.SelectNodes( "//form[starts-with(@action, '/gp/item-dispatch/ref=') and @method='POST']" );

搜索到form节点,但是结果其下,再去搜input节点:

?
1
HtmlNodeCollection inputTypeNodeList = postItemNode.SelectNodes( ".//input[@type='hidden' and @name and @value]" );

竟然得到的inputTypeNodeList是null:

inputTypeNodeList is null

即form下面,没有找到任何的child,即,所有的input节点,都丢失了!

再回去查看postItemNode,结果其下就是没有child的:

first child is null and no child

 

所以,应该是对应的HtmlAgilityPack的bug。

 

【折腾过程】

1. 后来看到:

No child nodes for FORM object

中提到了,说是:

In Html specification form tag can overlap, so Htmlagilitypack handle this node a little different.  
。。。

After adding this call all form elements are added as children.

然后就去看看,结果果然是从child变成了sibling了,而且此处还是很变态的,NextSibling的NextSibling才是我们要的input节点:

nextsibling then nextsibling can get input

所以,此处,看来只能是说动的,类似于上面那个问题一样的,写成NextSibling的NextSibling

不过,真是这样写的话,那也够变态的。。。。

2.然后也看到别人也遇到同样问题:

Problem parsing children of a node with HtmlAgilityPack

而且某人也是放弃了HtmlAgilityPack而转到了SGMLReader了。

不过,另外有人说,不是bug,而是可以配置的。

其相关的讨论见:

http://htmlagilitypack.codeplex.com/workitem/21782

再参考:

HtmlAgilityPack — Does <form> close itself for some reason?

去,在将html转为htmlDoc之前,添加:

?
1
HtmlNode.ElementsFlags.Remove( "form" );

变为:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
HtmlNode.ElementsFlags.Remove( "form" );
 
htmlDoc = crl.htmlToHtmlDoc(respHtml);
HtmlNodeCollection postItemNodeList = htmlDoc.DocumentNode.SelectNodes( "//form[starts-with(@action, '/gp/item-dispatch/ref=') and @method='POST']" );
if  (postItemNodeList ==  null )
{
     //something error
}
else
{
     foreach  (HtmlNode postItemNode  in  postItemNodeList)
     {
         string  itemDispatchUrl = postItemNode.Attributes[ "action" ].Value;  ///gp/item-dispatch/ref=olp_atc_used_1
         itemDispatchUrl = constAmazonDomainUrl + itemDispatchUrl; //http://www.amazon.com/gp/item-dispatch/ref=olp_atc_used_1
 
         Dictionary< string ,  string > postDict =  new  Dictionary< string ,  string >();
 
         HtmlNodeCollection inputTypeNodeList = postItemNode.SelectNodes( ".//input[@type='hidden' and @name and @value]" );

然后得到的inputTypeNodeList,的确不是null了,也有了child了:

indeed has the input node as child for form

 

【总结】

之前还夸奖HtmlAgilityPack好用呢,结果还没用多久,就出现这么多的bug。看来真的没法继续使用了。

每次都要很小心,不知道啥时候就会出错,真郁闷。。。

即使不是bug,其本身把form下面的节点,都弄成其sibling这个策略,还是很变态的。至少让更多人的,都容易误解。


【后记】

后来的后来,经过参考别人的解释:

<option> have no child, why?

发现,

其实上述两个,所谓的bug,就是同一个问题:

对于HtmlAgilityPack,实际上,对于option,form等tag,其默认的处理的结果是:其下的子节点,会变成sibling

所以,上面的:

对于option需要通过NextSibling才能获得对应的InnerText;

对于form子节点为空,也是需要通过NextSibling(的NextSibling)才能获得对应的input子节点;

其本质都是:

HtmlAgilityPack是针对HTML 3.2的规范去实现的,而HTML 3.2就是这样规定的。

其不是bug,而是feature

但是很明显,是属于让人蛋疼的feature。

解决办法有两种:

1.改源码

把HtmlNode.cs中的下面这行注释掉:

?
1
ElementsFlags.Add( "form" , HtmlElementFlag.CanOverlap | HtmlElementFlag.Empty);

2.不改源码

在HtmlDocument类型的变量执行LoadHtml之前,加上:

?
1
HtmlNode.ElementsFlags.Remove( "tagName" );

即,对于我之前的crifanlib.cs中的:

?
1
2
3
4
5
6
7
8
public  HtmlAgilityPack.HtmlDocument htmlToHtmlDoc( string  html)
{
     HtmlAgilityPack.HtmlDocument htmlDoc =  new HtmlAgilityPack.HtmlDocument();
 
     htmlDoc.LoadHtml(html);
 
     return  htmlDoc;
}

换成:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public  HtmlAgilityPack.HtmlDocument htmlToHtmlDoc( string  html)
{
     HtmlAgilityPack.HtmlDocument htmlDoc =  new  HtmlAgilityPack.HtmlDocument();
 
     //make some html tag: form/option, has child
     HtmlNode.ElementsFlags.Remove( "form" );
     HtmlNode.ElementsFlags.Remove( "option" );
 
     htmlDoc.LoadHtml(html);
 
     return  htmlDoc;
}

即可。

如此,后续解析html得到的form,option等tag,其child就是我们所希望的内容了。


YOLO26改进策略【YOLO和Mamba】| CVPR 2025:EfficientViM 压缩隐藏状态空间进行通道混合、单头设计减少内存操作,提升目标检测效率与精度 本文记录的是利用模块优化的目标检测网络模型。EfficientViM Block(基于隐藏状态混合器的状态空间对偶性模块) 的设计旨在,提升特征提取效率,同时兼顾全局依赖捕捉与局部细节保留。本文将深入研究的原理,并将其应用到中,通过重构特征提取流程、减少内存绑定操作、融合多阶段特征,增强模型在资源受限环境下的检测性能与速度。EfficientViM: Efficient Vision Mamba with Hidden State Mixer based State Space DualityEfficie 阅读详情

相关推荐

【小白指南】如何将deepseek引入WPS\Word\Excel中去?

如何将deepseek引入WPS\Word\Excel中去?纯小白都能看的懂,一步步操作就能行

2503_90498422的博客 1万+

HtmlAgilityPack 获取节点的子节点

这个问题真的是好无语 var table = doc.DocumentNode.SelectSingleNode("//table[@class='ddd']"); var a = table.SelectNodes("//a"); 无论怎么尝试 a对象拿到的</a>标签都是全局的 拿不到table节点下的</a>标签 你...

weixin_33701294的博客 518

Intel Realsense windows安装与入门

realsense400系列介绍: https://www.intelrealsense.com/stereo-depth/?utm_source=intelcom_website&utm_medium=button&utm_campaign=day-to-day&utm_content=D400_learn-more_button realsense 435i介绍: ...

hanshuning的专栏 1万+

c# html agility pack,【已解决】C#用HtmlAgilityPack执行Html解析时,发现InnerText中包含javascript,要去除Javascript...

【问题】C#中,中HtmlAgilityPack,去解析:的html中的:World’s first tablet with dual-band, dual-antenna Wi-Fi for over 35% faster downloads and streaming (compared to the iPad mini)时,发现对应的源码是:World’s first tablet with...

weixin_31847579的博客 545

巨量千川M-API实战:异步报表与批量操作自动化指南

API(应用程序编程接口)是现代软件系统间通信和数据交换的核心技术,它定义了服务间交互的协议和规范。在数字营销领域,营销API(Marketing API)通过程序化接口实现了广告账户管理、数据获取和操作自动化的能力,其技术价值在于将重复性人工操作转化为高效、准确的自动化流程,显著提升运营效率并降低人为错误。在广告投放精细化运营场景中,面对海量数据报表的获取与批量广告状态管理的需求,异步任务处理和批量操作接口成为关键技术解决方案。本文聚焦巨量千川M-API,深入解析其异步报表获取机制与批量操作实现,涵盖从任

weixin_32932149的博客 429

Lumerical官方案例、FDTD时域有限差分法仿真学习(十四)——超透镜(Metalens)

这个例子的目的是设计一个由圆柱形纳米棒组成的衍射超透镜。 纳米棒的半径和排列经过调整以在超透镜表面上产生所需的相位分布。 该设计通过近场和远场分析在 Ansys FDTD、RCWA(严格耦合波分析)和 OpticStudio 中得到验证。...

weixin_45719141的博客 3万+

HtmlAgilityPack类说明---一些属性介绍

常用属性介绍 名称 描述 InnerHtml 获取某节点内部的html InnerText 获取某节点内部的纯文本 OuterHtml 获取本节点与内容的html ParentNode 获取本节点的父节点 InnerHtml var htmlDoc = new HtmlDocument(); htmlDoc.LoadHtml...

『程序员·小李』的博客 756

Coze HTTP请求节点实战:5分钟搞定天气API对接(含动态参数技巧)

本文通过一个天气预报API对接的实战案例,详细讲解了如何在Coze平台使用HTTP请求节点实现外部数据交互。文章重点演示了动态参数传递、JSON响应解析与错误处理等核心技巧,帮助开发者在5分钟内快速构建稳定可靠的智能体外部服务调用能力。

weixin_29233333的博客 675

2012-09-10 23:30 如何解决HtmlAgilityPack得到的InnerText中有残留的script、样式的问题...

那么如何解决HtmlAgilityPack得到的InnerText中有残留的script、样式的问题呢,在google上搜索“HtmlAgilityPackscriptinnerText”找到了stackoverflow上的这篇文章《C#:HtmlAgilityPackextractinnertext》 代码如下: foreach(varscriptind...

andy76123的博客 208

华为OD干了两个月,还是跑了

​本人工作了快13年,base南京。2024年2月份由于公司业务变动第一次拿到了公司发的大礼包,同时也面临着失业的问题,我对自己的技术还是很有信心的,但是,找了大概有一个多月时间,发现心意的工作的确不太好找,当然收到挺多家offer,就是薪资不太满意,外包也一直不想去,不过说实话外包给的薪资普遍要比自研的单位要高一些,最后为了钱还是进华为(既然选择外包那就选择好一些的吧),毕竟中年老男人工作不能断太久。

啊渊的专栏 1万+

Python 领域 vllm 知识蒸馏的实践经验

知识蒸馏(Knowledge Distillation)是一种将大型、复杂模型(教师模型)的知识转移到小型、高效模型(学生模型)的技术。在大型语言模型(LLM)时代,这项技术变得尤为重要,因为它可以在保持模型性能的同时显著降低计算资源需求。本文专注于在Python生态中使用vLLM(Very Large Language Model)框架实现知识蒸馏的实践经验。vLLM是一个专为大型语言模型设计的高效推理和服务框架,它通过创新的注意力机制和内存管理技术,显著提高了LLM的推理速度。

AI Python 编程之道的博客 777

ARM多核平台LDREX/STREX独占访问全栈核对指南

独占访问(Exclusive Access)是ARM架构实现原子操作与自旋锁的硬件基础,其核心依赖LDREX/STREX指令对及CPU内部exclusive monitor状态机。该机制并非简单‘支持即可用’,而受编译器优化、内存类型约束、缓存一致性协议、SoC总线实现等多层因素影响,极易出现‘单核正常、多核失效’或‘高负载下STREX失败率陡增’等隐蔽问题。技术价值在于保障并发原语的确定性与实时性,广泛应用于Linux内核同步、RTOS关键区保护、安全可信计算及高可靠性嵌入式固件开发。本文聚焦ARMv7/

weixin_30613727的博客 97

MATLAB 基于深度学习的步态识别算法仿真

步态识别是一种通过分析人体行走方式来识别身份的技术。基于深度学习的步态识别算法利用卷积神经网络 (CNN) 提取步态特征,并通过分类器进行身份识别。基于深度学习的步态识别算法是实现身份识别的重要手段,具有广泛的应用前景。MATLAB 提供了丰富的工具和函数,可以方便地进行算法仿真和性能评估。

走向CTO的路上... 518

清除HtmlAgilityPack得到的InnerText中残留的script

清除脚本可以这样: foreach(var script in doc.DocumentNode.Descendants("script").ToArray()) script.Remove(); 清除样式可以这样: foreach(var style in doc.DocumentNode.Descendants("style").ToArray()) style.Remo

yw1688的专栏 1056

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

HtmlAgilityPack官方文档(四)【Traversing】

Traversing允许您遍历HTML节点。属性 名称 描述 ChildNodes Gets all the children of the node. FirstChild Gets the first child of the node. LastChild Gets the last child of the node. NextSibling Gets

极客神殿 1462

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

使用HtmlAgilityPack抓取html标签属性内容

使用HtmlAgilityPack抓取hml标签属性内容,C# 爬出,网页内容抓取

HilaryHe 1万+

HtmlAgilityPack 之 HtmlNode类

HtmlAgilityPack 之 HtmlNode类 HtmlAgilityPack中的HtmlNode类与XmlNode类差不多,提供的功能也大同小异。下面来看看该类提供功能。 一、静态属性 public static Dictionary<str...

516

HtmlAgilityPack 总结(一)

一个解析html的C#类库HtmlAgilityPack, 今天终于有时间整理一下,并把Demo分享一下。 HtmlAgilityPack是一个基于.Net的、第三方免费开源的微型类库,主要用于在服务器端解析html文档(在B/S结构的程序中客户端可以用Javascript、jquery解析html)。截止到本文发表时,HtmlAgilityPack的最新版本为 1.4.6。下载地址:ht

2万+

HtmlAgilityPack使用——XPath注意事项

在使用HtmlAgilityPack这个开源的类库进行网页内容解析的时候是非常的方便(使用方法见另一篇博客《HTML解析:基于XPath的C#类库HtmlAgiliytyPack》),其基于XPath路径语法进行高效的选择文档节点,当发起请求获取了网页html文件的时候,解析的大部分工作量就落到了XPath路径表达式的书写了。本文测试在VS2010开发环境,.NetFramework 4.0 ...

webdev 375

Html Agility Pack基础类介绍及运用

第一篇只对Html Agility Pack做了一个大概的介绍,在接下来的章节会比较深入的介绍Html Agility Pack。 Html Agility Pack 源码中的类大概有28个左右,其实不算一个很复杂的类库,但它的功能确不弱,为解析DOM已经提供了足够强大的功能支持,可以跟jQuery操作DOM媲美:) 基础类和基础方法介绍 Html Agility Pack最常用的...

weixin_30583563的博客 539

html解析器c#,HTML解析器HtmlAgilityPack的一些使用总结(C#)

/*c# HtmlAgilityPack--------------------------------* 关于节点的重要属性:Attributes             获取节点的属性集合ChildNodes            获取子节点集合(包括文本节点)HasAttributes           判断该节点是否含有属性HasChildNodes           判断该节点是否含...

weixin_39639505的博客 629

nextSibling使用注意(html的注释)

nextSilbling 属性的作用是:直接返回一个节点之后的节点(其后的节点与当前节点同属一个级别)。 <table><tr><td name='b'><input class="a" value="1"/></td> <td name='b'><input value="2"/></td>...

weixin_34194317的博客 462

关于nextSibling的用法

 不知道不知道不知道

十步一杀 2129

C# HTML解析工具HtmlAgilityPack XPath 模糊查询not()函数和contains()函数

如果想使用Xpath过滤属性中含有或不含有等逻辑判断,需要以下两个函数 Xpath 的not()函数 不含后指定属性等 contains() 属性中含有指定字符串的过滤 实例说明1 //选择不包含class属性的节点 var result = node.SelectNodes(".//span[not(@class)]"); //选择不包含class和id属性的节点 var result

天马3798 7376
上一篇: .NET中对XML文件的操作资料(未完)
下一篇: JavaScript简介
stypace
博客等级 码龄17年 72粉丝 84原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值