热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

【背景】之前使用HtmlAgilityPack期间,遇到了2个bug:1.InnerText没有包含对应字符串(但是用NextSibling.InnerText却可以得到)对于

【背景】

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

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

对于html:




?






1



用如下的代码:




?






1

2

3

4


//

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


//

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


"POST" action="/gp/item-dispatch/ref=olp_atc_fm_1" >

    "hidden" name="session-id" value="182-0726239-4848949">

    "hidden" name="qid" value="">

    "hidden" name="sr" value="">

    "signInToHUC" type="hidden" value="0" name="signInToHUC">

    "hidden" name="metric-asin.B0083PWAPW" value="1">

    "hidden" name="registryItemID.1" value="">

    "hidden" name="registryID.1" value="">

    "hidden" name="itemCount" value="1">

    "hidden" name="offeringID.1"value="%2F%2FeHHmpktM3oPoQj%2FOWhDI%2FpHyvwwFCwEfNIBEgFcfAHzKHAzVK%2BZfhkmBFO%2BPbow9JfdOmrE6eKME4ydhLTTK1Dgaf8O3N7SyOR%2F136TvVh0lfJypEt4Q%3D%3D">

    "hidden" name="isAddon" value="0">

    "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" css string">"21" name="submit.addToCart" css string">"112"/>


可以通过:




?






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:

bubuko.com,布布扣

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

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

bubuko.com,布布扣

 

所以,应该是对应的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节点:

bubuko.com,布布扣

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

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

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

Problem parsing children of a node with HtmlAgilityPack

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

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

其相关的讨论见:

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

再参考:

HtmlAgilityPack — Does 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


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

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)

class="line number7 index6 alt2">{

    //something error

class="line number9 index8 alt2">}

else

{

    foreach (HtmlNode postItemNode in postItemNodeList)

    {

        //http://www.amazon.com/gp/item-dispatch/ref=olp_atc_used_1

        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<stringstring> postDict = new Dictionary<stringstring>();

 

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

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

bubuko.com,布布扣

 

【总结】

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

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

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



【后记】

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

发现,

其实上述两个,所谓的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)

class="line number2 index1 alt1">{

    HtmlAgilityPack.HtmlDocument htmlDoc = newHtmlAgilityPack.HtmlDocument();

 

    htmlDoc.LoadHtml(html);

 

    return htmlDoc;

class="line number8 index7 alt1">}

换成:




?






1

2

3

4

5

6

7

8

9

10

11

12

13


public HtmlAgilityPack.HtmlDocument htmlToHtmlDoc(string html)

class="line number2 index1 alt1">{

    HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();

 

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

    //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就是我们所希望的内容了。

 

另外:

1.对于是否还有其他特殊的html的tag,也是默认被处理为子节点变为sibling的,就不知道了。

2.等有空再去深究背后的那个HTML 3.2规范是怎么定义的。


推荐阅读
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 网络爬虫的规范与限制
    本文探讨了网络爬虫引发的问题及其解决方案,重点介绍了Robots协议的作用和使用方法,旨在为网络爬虫的合理使用提供指导。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 自定义滚动条美化页面内容
    当页面内容超出显示范围时,为了提升用户体验和页面美观,通常会添加滚动条。如果默认的浏览器滚动条无法满足设计需求,我们可以自定义一个符合要求的滚动条。本文将详细介绍自定义滚动条的实现过程。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 微软推出Windows Terminal Preview v0.10
    微软近期发布了Windows Terminal Preview v0.10,用户可以在微软商店或GitHub上获取这一更新。该版本在2月份发布的v0.9基础上,新增了鼠标输入和复制Pane等功能。 ... [详细]
  • Framework7:构建跨平台移动应用的高效框架
    Framework7 是一个开源免费的框架,适用于开发混合移动应用(原生与HTML混合)或iOS&Android风格的Web应用。此外,它还可以作为原型开发工具,帮助开发者快速创建应用原型。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 本文对比了杜甫《喜晴》的两种英文翻译版本:a. Pleased with Sunny Weather 和 b. Rejoicing in Clearing Weather。a 版由 alexcwlin 翻译并经 Adam Lam 编辑,b 版则由哈佛大学的宇文所安教授 (Prof. Stephen Owen) 翻译。 ... [详细]
  • javascript分页类支持页码格式
    前端时间因为项目需要,要对一个产品下所有的附属图片进行分页显示,没考虑ajax一张张请求,所以干脆一次性全部把图片out,然 ... [详细]
  • 本文介绍了如何使用 CMD 批处理脚本进行文件操作,包括将指定目录下的 PHP 文件重命名为 HTML 文件,并将这些文件复制到另一个目录。 ... [详细]
  • 两个条件,组合控制#if($query_string~*modviewthread&t(&extra(.*)))?$)#{#set$itid$1;#rewrite^ ... [详细]
  • 本文详细介绍了DMA控制器如何通过映射表处理来自外设的请求,包括映射表的设计和实现方法。 ... [详细]
  • 本文详细介绍了如何利用Duilib界面库开发窗体动画效果,包括基本思路和技术细节。这些方法不仅适用于Duilib,还可以扩展到其他类似的界面开发工具。 ... [详细]
  • Spark中使用map或flatMap将DataSet[A]转换为DataSet[B]时Schema变为Binary的问题及解决方案
    本文探讨了在使用Spark的map或flatMap算子将一个数据集转换为另一个数据集时,遇到的Schema变为Binary的问题,并提供了详细的解决方案。 ... [详细]
author-avatar
霸气小米鱼鱼_156
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有