现在的位置: 首页 > 综合 > 正文

htmlcleaner xpath的一些tips

2018年05月11日 ⁄ 综合 ⁄ 共 5305字 ⁄ 字号 评论关闭

参考网上

列一些tips



http://hi.baidu.com/yuweiming/blog/item/ac2bc817ad598f04c83d6d46.html

HtmlCleaner supports XPath to find tagNode/attribute, but it is not fully supported XPath parser and evaluator.
See Object[] org.htmlcleaner.TagNode.evaluateXPath(String xPathExpression) throws XPatherException:

public Object[] evaluateXPath(String xPathExpression) throws XPatherException
Evaluates XPath expression on give node.
This is not fully supported XPath parser and evaluator. Examples below show supported elements:

  • //div//a
  • //div//a[@id][@class]
  • /body/*[1]/@type
  • //div[3]//a[@id][@href='r/n4']
  • //div[last() >= 4]//./div[position() = last()])[position() > 22]//li[2]//a
  • //div[2]/@*[2]
  • data(//div//a[@id][@class])
  • //p/last()
  • //body//div[3][@class]//span[12.2
  • data(//a['v' < @id])

/**
 * @author LiHuiRong
 * @created 2011-5-19 10:00
 */
public class TagNodeCaster {
  public static Document castTagNodeToDom4jDocument(HtmlCleaner cleaner, TagNode tagNode) throws IOException, DocumentException {
    StringWriter sw = new StringWriter();
    Serializer serializer = new SimpleXmlSerializer(cleaner.getProperties());
    serializer.write(tagNode, sw, "UTF-8");
    SAXReader reader = new SAXReader();
    StringReader strReader = new StringReader(sw.toString());
    Document doc = reader.read(strReader);
    return doc;
  }
 
  public static void main(String[] args) throws Exception {
    HtmlCleaner cleaner = new HtmlCleaner();
    TagNode root = cleaner.clean(new URL("http://localhost/test/taobao_view_shop.htm"));
    if (root != null) {
      Document doc = castTagNodeToDom4jDocument(cleaner, root);
      Element rootE = doc.getRootElement();
      String xpath = "//div[@class='bd']/div/div[@class='nav']/ul/li[not(@class)]/a/@href";
      Object obj = rootE.selectObject(xpath);
      DefaultAttribute da = (DefaultAttribute) obj;
      System.out.println(da.getValue());
    }
  }
}

http://mn960mn.blog.163.com/blog/static/114103084201091833316436/

1. HtmlCleaner cleaner = new HtmlCleaner(); 
2. TagNode node = cleaner.clean(new File(fileRoot), String defultCharSet);//在这一步骤中,得到经过基本处理后的一颗html 树,其中,fileRoot 为 保存的html的页面地址,defultCharSet 词程序的默认的分析编码,因为网页的编码格式会有几种,必须用相应的格式进行分析提取,否则乱码。Clean方法中参数,可以是文件,可以是url,可以是字符串内容。 
//按xpath提取 
3. Object[] metaKeyWord = node.evaluateXPath("/head/meta[@name='" 
+ keyWord + "']");// 利用xpath取出meta 中的keyword,要求具有一定的xpath 知识基础。 
4. if (metaKeyWord.length != 0) { 
String stringOfMetaKeyWord = (((TagNode) metaKeyWord[0]) 
.getAttributeByName("content"));//提取出meta中的关键词 

5. //按tag提取 
6. Object[] title = node.getElementsByName("title", true); 
if(title.length!=0){ 
String stringOfTitle = (((TagNode) title[0]).getText()).toString(); 

在我的应用中,我把htmlCleaner的用途分为两种,一种做特定的、有针对性的网页信息的提取,另一种做网页正文的提取。 
对于第一种,就举我遇到的一个问题作为例子吧。因为在做网页分析时,要考虑到编码的问题,网页的编码格式与预设分析的编码不一致,则提取失败。因此必须要先提取出网页的编码,然后判断是否与自己设定的一致,不一致的话,按照新的编码格式重新进行分析提取。例如,TagNode node = cleaner.clean(new
File(fileRoot), “gb2312”) , 在程序中用的是gb2312,而一篇网页的编码是 utf-8 ,那要首先根据Xpath 进行特定内容的提取(也就是你已经知道它在哪),提取网页编码的xpath 路径描述为: "/head/meta[@http-equiv='Content-Type']";用TagNode 中的evaluateXPath 方法便可提取出来。当然,按照此方法的理论分析,还可以应用此性质来做一些某些网站上的特定的信息的提取、定制。比如天气预报、新闻等等。但要熟练掌握Xpath的语法,至关重要。经典的xpath教程,网上有很多,而且例子也比较全,这里就不多在描述,但有一点要注意,htmlCleaner
对Xpath 仅仅是部分的语法支持,有些xpath 不能被完全识别,大家可以下载xpath的api ,定义自己的xpath 即可。 

对于第二种,就说一下我在处理类似内容时的具体思路吧。(总的来看,网页提取效果还是蛮不错的,最起码对于我的应用而言,足矣。之所以要在这分享一下,是因为自己也走过了不少弯路,看过多人的博客和所谓的技术文章)网页中主题内容,成块的文字描述一般都是用<p>来标示,当然更有一些用<tr> ,更有甚者直接扔在<div>中,对于此,采用了从细到粗,逐步删除的方法。首先根据标签或者xpath
路径 ,提取出无用的html描述语言,比如<script> 、<style>等等,然后将其删除,方法如下。 


Object[] nsscript = node.evaluateXPath("//script"); 
for (Object tt : nsscript) { 
((TagNode) tt).removeFromTree(); 

(在xpath中,// 代表所有的script 标签结点,即一个TagNode对象) 
然后,利用TagNode 的evaluateXPath 方法,只提取<body>中的链接,图像信息和文章。”/body//a”  “/body//img” “/body//p” ,同样的方法将其从Tree中删除,以免影响后续的提取结果。如此便可提取仅在<div>中定义的文字了,要注意的是提取的xpath是”/body/div”,只提取一层,以免重复。 

Object[] nsdiv_2 = node.evaluateXPath("/body/div"); 
for (int j = 0; j < nsdiv_2.length; j++) { 
if (j == nsdiv_2.length - 1) { 
TagNode t = (TagNode) nsdiv_2[j]; 
t.removeFromTree(); 


此外在这一步骤之前,最好将nsdiv_2 中的最后一个内容删除,因为基本上是网页的root,没有什么用处。 
怎么样,很简单吧,这只是一个简单的网页提取,当然要想更加精确,从分析DOM的方向入手,也是可以的。htmlCleaner,也提供了相关的方法和功能。如下一个简单的Demo。 

public class HtmlClean { 

    public void cleanHtml(String htmlurl, String xmlurl) { 
        try { 
            long start = System.currentTimeMillis(); 

            HtmlCleaner cleaner = new HtmlCleaner(); 
            CleanerProperties props = cleaner.getProperties(); 
            props.setUseCdataForScriptAndStyle(true); 
            props.setRecognizeUnicodeChars(true); 
            props.setUseEmptyElementTags(true); 
            props.setAdvancedXmlEscape(true); 
            props.setTranslateSpecialEntities(true); 
            props.setBooleanAttributeValues("empty"); 

            TagNode node = cleaner.clean(new File(htmlurl),"utf-8"); 

            System.out.println("vreme:" + (System.currentTimeMillis() - start)); 

            new PrettyXmlSerializer(props).writeXmlToFile(node, xmlurl,"utf-8"); 

            System.out.println("vreme:" + (System.currentTimeMillis() - start)); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    } 

    public static void main(String[] args) { 
        HtmlClean clean = new HtmlClean(); 
        clean.cleanHtml("html/1.htm", "1.xml"); 
    } 
}


http://hi.baidu.com/yuweiming/blog/item/ac2bc817ad598f04c83d6d46.html

/                    获取当前节点的下一级节点,只包括儿子
//                   获取当前节点的所有子节点,包括孙子等。
//table[@class]      获取所有含有class属性的table标签
//table[span[@class]] 获取含有span,有class属性作为子节点的节点。
//a[text()]    <a>a<b>b</b></a> 用来获取a
//a//text()    <a>a<b>b</b></a> 用来获取ab

contains

//a[/d[@class='class1']]/text() 获取含有d子节点并且d节点含有class,值为class1
//a[//d[@class='class1']]/text() 获取含有d子节点,包含孙子等,并且d节点含有class,值为class1

等值查询:
String xPath = "users/user[username='huo' and password='123']";
模糊查询:
String xPath = "users/user[contains(username,'huo') and contains(password,'123')]";

//table[@width][@border][@cellpadding][@cellspacing]//span[@class='posttopic']/../../..   ..是获取当前节点的父节点






抱歉!评论已关闭.