DOM树中的视觉特征和一致性是怎样的?

优采云 发布时间: 2021-06-03 18:33

  DOM树中的视觉特征和一致性是怎样的?

  参考iteye上文章的一篇文章,我恢复了文章的源码,还请博主见谅

  准确提取网页内容一直是​​数据提取和开发的头疼问题。目前,*敏*感*词*的研究成果很多,需要在实际项目中进一步探索和应用。

  以下为转载部分:

  应该说在WEB分割领域已经有很多研究工作了。由于 HTML 语法的灵活性,目前大多数网页都没有完全遵循 W3C 规范,这可能会导致 DOM 树结果出现错误。更重要的是,DOM树最初是为了浏览器中的布局展示而引入的,并不是为了描述WEB页面的语义结构。一些文献中提到基于标签将网页划分为内容块。这些块方法在过程中很简单。然而,面对日益复杂的网页和不规则的网页结果,拦截效果往往不尽如人意。

  另一种方法是从视觉特征中挖掘页面结构。一个典型的代表就是微软亚洲研究院提出的VIPS(Vision-based Page Segmentation)。它利用 WEB 页面的视觉线索,如背景颜色、字体颜色和大小、边框、逻辑块和逻辑块之间的间距等,结合语义块的 DOM 树,并将其应用于评估TREC2003。好结果。但是,由于视觉特征的复杂性,如何保证规则集的一致性是一大难点。另外,VIPS算法需要计算并保存DOM树中所有节点的视觉信息,导致算法消耗大量时间和内存。处理具有大量DOM节点的网页时性能不高。

  利用网页的视觉特性和DOM树的结构特性对网页进行屏蔽,采用逐层逐层删除的方法,删除与网页无关的噪声块文本,从而获得文本块。对得到的文本块应用VIPS算法得到完整的语义块,最后在语义块的基础上提取文本内容。实验证明该方法是可行的。

  文本网页可以分为两类:主题网页和目录网页。专题网页通常通过文本段落描述一个或多个主题。虽然主观网页也有图片和超链接,但这些图片和超链接并不是网页的主体。目录网页通常提供一组相关或不相关的链接。本文研究的正文信息提取是指从新闻主题网页中提取核心文本。从理论上讲,利用本文所述的研究成果,该算法稍加变换,也将适用于论坛类主题网页正文的提取。

  块统计算法

  算法首先将DOM树中的节点类型分为容器、文本、移除、图片四类。

  /**

* 检查指定DOM节点是否为容器类节点

* @param node

* @return

*/protectedboolean checkContainerType(DomNode node){return(node instanceofHtmlUnknownElement|| node instanceofHtmlFont|| node instanceofHtmlListItem|| node instanceofHtmlUnorderedList|| node instanceofHtmlDivision|| node instanceofHtmlCenter|| node instanceofHtmlTable|| node instanceofHtmlTableBody|| node instanceofHtmlTableRow|| node instanceofHtmlTableDataCell|| node instanceofHtmlForm);}/**

* 检查指定DOM节点是否为文本类节点

* @param node

* @return

*/protectedboolean checkTextType(DomNode node){return(node instanceofHtmlSpan|| node instanceofDomText|| node instanceofHtmlParagraph);}/**

* 检查指定DOM节点是否为移除类节点

* @param node

* @return

*/protectedboolean checkRemoveType(DomNode node){return(node instanceofHtmlNoScript|| node instanceofHtmlScript|| node instanceofHtmlInlineFrame|| node instanceofHtmlObject|| node instanceofHtmlStyle|| node instanceofDomComment);}/**

* 检查指定DOM节点是否为图片类节点

* @param node

* @return

*/protectedboolean checkImageType(DomNode node){return(node instanceofHtmlImage);}

  该算法以文本型节点作为检测的直接对象,在检测过程中遇到去除型节点就去除,遇到图片型节点不计算,直接跳过,但不计算不删除类型。节点,当遇到容器节点时,直接检测其子节点。

  /**

* 检查指定节点是否含有容器类节点,如果有则继续递归跟踪,否则探测该节点文本数据

* @param nodeList

* @return 是否含有容器类节点

*/protectedboolean checkContentNode(List nodeList){boolean hasContainerNode =false;if(nodeList !=null){for(DomNode node : nodeList){if(checkRemoveType(node)){

node.remove();}elseif(checkContainerType(node)){List list = node.getChildNodes();if(list !=null){

hasContainerNode =true;if(!this.checkContentNode(list)){if(cleanUpDomNode(node)){

checkNode(node);}}}}else{if(node.isDisplayed()&& checkTextType(node)){

checkNode(node);}else{

cleanUpDomNode(node);}}}}return hasContainerNode;}/**

* 清理指定节点内的无效节点

* @param element

* @return 该节点是否有效

*/protectedboolean cleanUpDomNode(DomNode element){if(element ==null){returnfalse;}List list = element.getChildNodes();int linkTextLength =0;boolean flag =false;if(list !=null){for(DomNode node : list){if(checkTextType(node)){continue;}elseif(checkRemoveType(node)){

node.remove();

flag =true;}elseif(checkImageType(node)){//图片类型节点暂时不作处理}elseif(node instanceofHtmlAnchor){String temp = node.asText();

temp = encoder.encodeHtml(temp);int length =Chinese.chineseLength(temp.trim());if(length >0){

linkTextLength += length;}}elseif(checkContainerType(node)){if(!cleanUpDomNode(node)){

node.remove();}

flag =true;}}}String content = element.asText();

content = encoder.encodeHtml(content);return(flag ||Chinese.chineseLength(content.trim())- linkTextLength >50||(content.trim().length()-Chinese.chineseLength(content)>5&&!flag));}

  当算法第一次检测到一个有效的文本块时,它会记录该文本块的父节点块并推断它是网页正文所在的区域。之后,当找到一个概率更高的块时,它直接替换前一个。网页正文区域中的块。

  /**

* 推测正文文本区域信息

* @param node

*/protectedvoid checkNode(DomNode node){String temp = node.getTextContent();

temp = encoder.encodeHtml(temp);int length =Chinese.chineseLength(temp.trim());

temp =null;if(contentNode !=null&& contentNode.equals(node.getParentNode())){

maxLength += length;}elseif(length > maxLength){

maxLength = length;

contentNode = node.getParentNode();}}

  这种逻辑适用于新闻、博客等整个网页中只有一个文本区的主题网页,而不适用于论坛、贴吧等网页中有多个兄弟文本区的主题网页。这里可以稍微修改一下,对所有检测到的文本块及其区域进行联合统计和预测,可以应用于论坛主题的网页。

  这一步采用递归检测,检测结果为0个或1个DOM节点(如果是论坛主题页面,识别结果为N个DOM节点)。

  /**

* 在N个DOM节点中搜索正文文本所在的节点

* @param nodeList

* @return

*/publicDomNode searchContentNode(List nodeList){

checkContentNode(nodeList);if(cleanUpDomNode(contentNode)){return contentNode;}else{returnnull;}}

  机器学习

  当智能识别模块成功识别网页正文后,会自动保存该网页的相关信息和检测结果数据(目前只记录检测到的正文区域的XPath,可能会支持序列化稍后保存。并反序列化对象以存储更多检测结果),下次您检测该网页或从该网页所在的域中检测其他网页时,它会首先从知识库中提取以前的经验来提取文本。如果提取失败,则继续尝试智能识别。目前每个域只支持保存一条经验,但后面可以扩展成一个列表,按照申请成功的数量进行排序,甚至可以在模块中添加过滤链,先将任务通过过滤器智能识别前链,如果根据以往经验在过滤链中提取成功,则直接返回,否则智能识别模块检测正文。未来还可以将机器学习和人工指导结合起来,既可以独立积累知识,也可以加载认为是从数据源添加的知识。

  以下代码不构成真正的机器学习。其实这里只做一个演示。

  /**

* 在网页中搜索正文文本

* @param html

* @return 识别成功后,将封装一个PageData对象返回

* 之所以返回一个对象,是考虑到将来可能加强该算法后,能够从页面中抽取更多数据,PageData对象能够更好的封装这些结果

*/publicstaticPageData spotPage(HtmlPage html){if(html ==null){returnnull;}String domain =URLHelper.getDomainByUrl(html.getUrl());String contentXPath = contentXPathMap.get(domain);PageData pageData =null;HtmlEncoder encoder =HtmlEncoderFactory.createHtmlEncoder(html.getPageEncoding());AutoSpot2_2 spoter =newAutoSpot2_2(encoder);List nodeList =null;if(contentXPath !=null){

log.debug("在经验库中找到站点["+ domain +"]的相关数据,正在尝试应用. . .");

nodeList =(List) html.getByXPath(contentXPath);}else{

log.debug("第一次遇到站点["+ domain +"],正在尝试智能识别. . .");}if(nodeList ==null|| nodeList.isEmpty()){

nodeList = html.getBody().getChildNodes();

log.debug("经验库中关于站点["+ domain +"]的相关数据无法应用于当前网页,正在尝试重新识别. . .");}if(nodeList !=null){DomNode node = spoter.searchContentNode(nodeList);if(node !=null){

pageData =newPageData();

pageData.setContent(encoder.encodeHtml(node.asXml()));

pageData.setTitle(html.getTitleText());

contentXPathMap.put(domain, node.getCanonicalXPath());}}return pageData;}

  

  

  目前,该算法的检测结果还勉强可以接受。通过对百度新闻的新闻页面进行跟踪识别,识别成功率超过90%,准确率低很多,不到80%。 %。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线