`
tianhewulei
  • 浏览: 24508 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

htmlparser 工具类

 
阅读更多
package whu.util.tools;

import java.util.LinkedHashSet;
import java.util.Stack;

import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.PrototypicalNodeFactory;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.http.ConnectionManager;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

import whu.common.Global;
import whu.util.tags.FontTag;


public class FindTag {
		
	/**
	 * 通过给定的初始节点集合和指定的匹配tag序列,依次遍历初始节点集合的每一个元素,从每一个初始节点中过滤出相应的唯一一个节点,并把所有的返回数组
	 * @param sourceList
	 * @param sequence
	 * @return根据我们要求而过滤得出的节点
	 */
	public static Node[] getTargetNodeArray(NodeList sourceList,String[] sequence){
		if(sourceList==null||sourceList.size()==0)
		{
			return null;
		}
		else
		{
			Node[] roots = sourceList.toNodeArray();
			int cNum = roots.length;
			LinkedHashSet found = new LinkedHashSet();
			for (int i = 0; i < cNum; i++) {
				Node newNode = findNode(roots[i], sequence);
				if(newNode!=null)
					found.add(newNode);
			}
			return (Node[])found.toArray(new Node[found.size()]);
			
		}
	}
	   
	/**
	 * 通过给定的初始节点集合和指定的匹配tag序列,依次遍历初始节点集合的每一个元素,从中过滤出相应的所有节点,并把所有的返回数组
	 * @param sourceList
	 * @param sequence
	 * @return根据我们要求而过滤得出的节点
	 */
	public static Node[] getAllTargetNodeArray(NodeList sourceList,String[] sequence){
		if(sourceList==null||sourceList.size()==0)
		{
			return null;
		}
		else
		{
			Node[] roots = sourceList.toNodeArray();
			int cNum = roots.length;
			LinkedHashSet found = new LinkedHashSet();
			for (int i = 0; i < cNum; i++) {
				Node[] newNodes = findNodes(roots[i], sequence);
				if(newNodes!=null&&newNodes.length!=0)
					for(Node n:newNodes)
						found.add(n);
			}
			return (Node[])found.toArray(new Node[found.size()]);
			
		}
	}
	
	/**
	 * 通过给定的一个初始节点和指定的匹配tag序列,依次遍历初始节点的孩子集合的每一个元素,从中过滤出相应的唯一一个节点,并返回该节点
	 * @param sourceList
	 * @param sequence
	 * @return根据我们要求而过滤得出的节点
	 */
	public static Node getTargetNode(Node sourceNode,String[] sequence){
		if(sourceNode!=null)
		{
		 	//System.out.println(" sourceNode not null------ ");
			Node newNode = findNode(sourceNode, sequence);
			if(newNode!=null)
				return newNode;
			else
			{
			 	//System.out.println("result Node null ------ ");
				return null;
			}
		}
		else
		{
			//System.out.println(" sourceNode null------ ");
			return null;
		}
	}
	
	/**
	 * 通过给定的一个初始节点和指定的匹配tag序列,找出初始节点的子节点中符合要求的所有节点,并把所有的那些相似节点以数组的形式返回
	 * @param sourceList
	 * @param sequence
	 * @return根据我们要求而过滤得出的节点
	 */
	public static Node[] getSimilarNodeArray(Node sourceNode,String[] sequence){
		if(sourceNode!=null)
		{
			Node[] similarNodes = findNodes(sourceNode,sequence);
			return similarNodes;
		}
		else
			return null;
	}
	
	/**
	 * 通过给定的一个节点,按匹配序列进行查找,返回符合条件的唯一一个节点
	 * @param source
	 * @param sequence
	 * @return
	 */
	public static Node findNode(Node source, String[] sequence) {
	    Stack curNode = new Stack();
	    curNode.push(source);
	    return matchTags(curNode, sequence);
	}

	/**
	 * 通过给定的一个节点,按匹配序列进行查找,返回符合条件的所有相似节点
	 * @param source
	 * @param sequence
	 * @return
	 */
	public static Node[] findNodes(Node source, String[] sequence) {
	    Stack curNode = new Stack();
	    curNode.push(source);
	    return matchTags(curNode, sequence,true);
	}
	
	public static final int FIND_SUB = 0; // 找子节点
	public static final int FIND_SIB = 1; // 找同级节点
	public static final int FIND_END = 2; // 结束
	
	/**
	 * 本方法必须要求每个初始根节点必须有children。该方法返回符合条件的唯一一个节点
	 * @param curNode
	 * @param sequence
	 * @return
	 */
	public static Node matchTags(Stack curNode, String[] sequence) {
		int state = FIND_SUB; // 开始
		int i=0;  //记录匹配的tag序号
		int depth = sequence.length;  //记录查找的深度
		int[] index = new int[depth];  //记录每级匹配的序列索引,即那一级的所有孩子的序列号
	    while (state != FIND_END) {
	          Node cNode = (Node) curNode.pop(); // 当前节点
	          if (state == FIND_SUB) { // 查找子节点
	        	  if(i<depth)
	        	  {
	        		  //下面这一步的getChildren可能会报错
	        		  NodeList cList = cNode.getChildren();
	        		  if(cList!=null)
	        		  {
	        			  Node[] subNodes = cNode.getChildren().extractAllNodesThatMatch(new TagNameFilter(sequence[i])).toNodeArray(); 
	        			  if (subNodes == null || subNodes.length == 0) { // 没有子节点
	  	            			curNode.push(cNode);
	  	            			state = FIND_SIB; // 下一次需要找同级节点
	        			  }
	        			  else
	        			  {
	        				 
	        				  curNode.push(cNode);
	        				  curNode.push(subNodes[0]);
	        				  index[i]=0;//第i级的当前测试节点索引为0
	        				  i++;
	        				  state = FIND_SUB;
	        			  } 
	        		  }
	        		  else
	        		  {
	        			  curNode.push(cNode);
	            		state = FIND_SIB; // 下一次需要找同级节点
	        		  }
	        				  
	        	  }
	        	  else if(i==depth)//说明已经匹配到设定的深度了,可以取出该节点了
	        		  return cNode;        		  
	          }
	          else if (state == FIND_SIB) { // 查找同级节点
	        	  if (curNode.isEmpty()) {
	        		  state = FIND_END; // 已经没有可以找的了,需要退出查找过程,反之栈里面一定含有父节点,所以i>0
	        	  }
	        	  else {
	        		  Node parentNode = (Node) curNode.peek();
	        		  Node[] sibNodes = parentNode.getChildren().extractAllNodesThatMatch(new TagNameFilter(sequence[i-1])).toNodeArray();
	        		  int sibNum = sibNodes.length;
	        		  if(index[i-1]+1<sibNum){ //存在下一个同级节点
	        			  curNode.push(sibNodes[index[i-1] + 1]);
	        			  index[i-1]+=1;
    					  state = FIND_SUB; // 需要查找子节点
	        		  }
	        		  else{ // 这就是最后一个同级节点,故要返回上一级
	        			  state = FIND_SIB;
	        			  index[i-1]=0; //第i级匹配索引重设为0
    					  i--;
	        		  }
	            }
	          }
	        }    
	        return null;
	 	}
	
	/**
	 * 本方法必须要求初始根节点必须有children。该方法返回符合条件的一批相似节点
	 * @param curNode
	 * @param sequence
	 * @param similar 为true标识是查找一个相似的序列
	 * @return
	 */
	public static Node[] matchTags(Stack curNode, String[] sequence,Boolean similar) {
		int state = FIND_SUB; // 开始
		int i=0;  //记录匹配的tag序号
		int depth = sequence.length;  //记录查找的深度
		int[] index = new int[depth];  //记录每级匹配的序列索引,即那一级的所有孩子的序列号
		LinkedHashSet found = new LinkedHashSet(); //记录查出符合要求的节点数组
		if(true==similar)
		{
			while (state != FIND_END) {
				Node cNode = (Node) curNode.pop(); // 当前节点
				if (state == FIND_SUB) { // 查找子节点
					if(i<depth-1)
					{
						//下面这一步的getChildren可能会报错,不过又可能不会报错,因为我压进栈的节点都是在那一级符合我的要求的节点,就肯定是有子节点的,除非到了匹配的最后一级最后
						NodeList cList = cNode.getChildren();
						if(cList!=null)
						{
							Node[] subNodes = cList.extractAllNodesThatMatch(new TagNameFilter(sequence[i])).toNodeArray(); 
							if (subNodes == null || subNodes.length == 0) { // 没有子节点
								curNode.push(cNode);
								state = FIND_SIB; // 下一次需要找同级节点
							}
							else
							{
								curNode.push(cNode);
	  	            	  		curNode.push(subNodes[0]);
	  	            	  		index[i]=0;//第i级的当前测试节点索引为0
	  	            	  		i++;//进入下一级
	  	            	  		state = FIND_SUB;
							}
						}
						else
						{
							curNode.push(cNode);
	  	            		state = FIND_SIB; // 下一次需要找同级节点
						}
					}
					else if(i==depth-1)
					{
						NodeList cList = cNode.getChildren();
						if(cList!=null)
						{
							Node[] subNodes = cList.extractAllNodesThatMatch(new TagNameFilter(sequence[i])).toNodeArray(); 
							if (subNodes != null && subNodes.length != 0) { // 有子节点,由于是最后一级,故全部采集
								for(int j=0;j<subNodes.length;j++)
	        					  found.add(subNodes[j]);
							}
						}
						curNode.push(cNode);
						state = FIND_SIB; // 下一次需要找同级节点
	        		  
	        	  }
	          }
	          else if (state == FIND_SIB) { // 查找同级节点
	        	  if (curNode.isEmpty()) {
	        		  state = FIND_END; // 已经没有可以找的了,需要退出查找过程,反之栈里面一定含有父节点,所以i>0
	        	  }
	        	  else {
	        		  Node parentNode = (Node) curNode.peek();
	        		  Node[] sibNodes = parentNode.getChildren().extractAllNodesThatMatch(new TagNameFilter(sequence[i-1])).toNodeArray();
	        		  int sibNum = sibNodes.length;
	        		  if(index[i-1]+1<sibNum){ //存在下一个同级节点
	        			  curNode.push(sibNodes[index[i-1] + 1]);
	        			  index[i-1]+=1;
    					  state = FIND_SUB; // 需要查找子节点
	        		  }
	        		  else{ // 这就是最后一个同级节点,故要返回上一级
	        			  state = FIND_SIB;
	        			  index[i-1]=0; //第i级匹配索引重设为0
    					  i--;
	        		  }
	            }
	          }
	        }
			return (Node[])found.toArray(new Node[found.size()]);
		}
		return null;
	}
	
		
	/**
	 * 根据给定的节点名字、标签属性、标签值提取出符合条件的所有tag节点
	 * @param url
	 * @param tagName
	 * @param attributeName
	 * @param attributeValue
	 * @return符合条件的List
	 */
	public static NodeList getNodeList(String url,String tagName,String attributeName,String attributeValue)
	{
		ConnectionManager manager;
        manager = org.htmlparser.lexer.Page.getConnectionManager();
        Parser parser;
        try 
        {
        	
            parser = new Parser(manager.openConnection(url));
            parser.setEncoding(Global.PAGE_ENCODING);
            
            //下面的节点注册一定要放在最前面,才能把指定节点的所有孩子节点都按我们的要求解析(有些自定义标签必须能够解析)
            //注册新的结点解析器,其实我觉得在htmlparser的源码里面可以直接编写新的节点类,然后重新编译
    		PrototypicalNodeFactory factory = new PrototypicalNodeFactory ();
    		factory.registerTag(new FontTag());
    		parser.setNodeFactory(factory);
    		
    		NodeFilter filterAttribute = new HasAttributeFilter(attributeName,attributeValue);
            NodeFilter filterTag = new TagNameFilter(tagName);
            NodeFilter andFilter = new AndFilter(filterAttribute, filterTag);
            
            return parser.parse(andFilter);//如果没有对应的节点,则会返回size=0的NodeList
        }
        catch(ParserException e)
        {
        	e.printStackTrace();
        	return null;
        }
	}
	
	/**
	 * 根据给定的节点名字提取出符合条件的所有tag节点
	 * @param url
	 * @return符合条件的List
	 */
	public static NodeList getNodeList(String url,String tagName)
	{
		ConnectionManager manager;
        manager = org.htmlparser.lexer.Page.getConnectionManager();
        Parser parser;
        try 
        {
        	
            parser = new Parser(manager.openConnection(url));
            parser.setEncoding(Global.PAGE_ENCODING);
            
            //下面的节点注册一定要放在最前面,才能把指定节点的所有孩子节点都按我们的要求解析(有些自定义标签必须能够解析)
            //注册新的结点解析器,其实我觉得在htmlparser的源码里面可以直接编写新的节点类,然后重新编译
    		PrototypicalNodeFactory factory = new PrototypicalNodeFactory ();
    		factory.registerTag(new FontTag());
    		parser.setNodeFactory(factory);
    		
            NodeFilter filterTag = new TagNameFilter(tagName); 
            return parser.parse(filterTag);//如果没有对应的节点,则会返回size=0的NodeList
        }
        catch(ParserException e )
        {
        	e.printStackTrace();
        	return null;
        }
	}
}


自定义的标签,某些不常用的标签htmlparser并不支持,需要自己拓展,比如EM 、 FONT等
package whu.util.tags;

import org.htmlparser.tags.CompositeTag;

public class FontTag extends CompositeTag{
	private static final String[] mIds = new String[] {"FONT"};
	   
    public String[] getIds (){
        return (mIds);
    }
    public String[] getEnders (){
        return (mIds);
    }
}
分享到:
评论

相关推荐

    C# HTMLParser下载.rar

    HTMLParser通常会提供一个解析器类,通过这个类,我们可以读取HTML字符串或文件,并将其转换为可操作的对象模型。例如,我们可以使用解析器的`ParseDocument`方法解析HTML源代码,然后通过这个文档对象来访问DOM...

    htmlparser.jar文件

    在Java开发中,如果你需要处理或分析HTML内容,HTMLParser是一个非常有用的工具。这个库提供了一套API,使得开发者能够方便地遍历、修改或者提取HTML文档中的信息。 在描述中提到的“org.htmlparser.Node”和其他的...

    HtmlParser

    1. **创建自定义解析器**: 首先,我们需要继承Python的`HTMLParser`类,并重写其方法,如`handle_starttag`、`handle_endtag`和`handle_data`,以便在遇到HTML标签开始、结束或数据时执行特定操作。 2. **启动爬虫*...

    java解析html工具htmlparser的jar包及api文档

    API文档是使用HTMLParser的关键,它详尽地解释了库中每个类、方法和接口的用途。通过API文档,开发者可以了解如何初始化解析器,如何遍历HTML元素,以及如何处理各种HTML标签。例如,HTMLParser库可能会提供如`...

    c#版htmlparser htmlparser.dll htmlparser源代码

    `htmlparser.dll`是这个库的动态链接库文件,它包含了编译好的类和方法,可以直接在C#项目中引用以使用HTMLParser的功能。在C#项目中,我们可以通过添加对dll的引用来调用库中的方法,比如解析HTML字符串、查找特定...

    htmlparser库与教程

    1. **安装和引入HTMLParser**:首先,用户需要将htmlparser.jar添加到项目构建路径中,无论是通过IDE(如Eclipse或IntelliJ IDEA)还是通过构建工具(如Maven或Gradle)。 2. **基本概念**:理解HTMLParser的核心类...

    HtmlParser源码及demo

    7. **源代码(src)**:`src`目录通常包含项目的源代码,可能包括HTMLParser的类和接口,以及示例代码的Java文件。 8. **JAR文件**:`jar`文件可能是编译后的HTMLParser库,开发者可以直接引入到自己的项目中使用。...

    htmlparser网页分析

    9. 结合其他工具:HTMLParser可以与其他工具结合使用,如Jsoup,后者是一个更现代的HTML解析库,提供更友好的API和更强的CSS选择器支持。两者结合可以提高处理复杂HTML文档的效率。 10. 性能考虑:虽然HTMLParser...

    Objective-C的HTMLParser类代码

    Objective-C的HTMLParser类代码是iOS和Mac应用开发中用于解析HTML文档的一种工具。这个开源项目为开发者提供了方便,能够高效地处理HTML内容并从中提取有用的信息。在iOS和Mac平台,Objective-C作为主要的编程语言,...

    htmlparser的jar包

    总的来说,HTMLParser是一个强大且灵活的工具,适用于需要解析和操作HTML的Java应用,如爬虫、数据提取、网页自动化等场景。通过理解这两个jar包的功能和交互,我们可以有效地利用HTMLParser来处理复杂的HTML解析...

    htmlParser.jar包

    在很多Web抓取、信息提取以及网页分析的项目中,HTMLParser都是一个理想的工具。 HTMLParser库的设计考虑了易用性和灵活性,它提供了丰富的API,允许开发者通过编程方式来访问和操作HTML文档的各个元素,如标签、...

    htmlparser1.6最新版

    总之,HTMLParser 1.6作为一个强大且灵活的HTML解析库,对于需要处理HTML内容的Java开发者来说,是一个不可或缺的工具。通过熟练掌握其API和事件模型,开发者可以轻松地实现复杂的网页信息提取和解析任务。

    htmlparser(c#,java)

    - Java项目中,HTMLParser通常作为依赖项添加到构建工具(如Maven或Gradle)的配置文件中,通过`import`导入库的类。 5. 示例代码: - C#示例: ```csharp using HtmlAgilityPack; ...

    HTMLParser 2.0

    总的来说,HTMLParser 2.0是Python中一个实用的HTML解析工具,虽然相对基础,但能帮助开发者完成许多基本的HTML解析任务。通过熟练掌握其使用,可以更高效地处理HTML文档,从而在数据提取和信息分析中发挥重要作用。

    htmlparser2.1.jar

    1. 将htmlparser-2.1.jar文件添加到你的项目类路径中。 2. 引入必要的import语句,如`import org.htmlparser.*;` 3. 创建解析器实例,配置解析选项,然后解析目标URL或HTML字符串。 4. 使用提供的API遍历DOM或监听...

    java htmlparser 类JAR包下载

    1. 引入依赖:将HTMLParser的JAR包添加到项目的类路径中,或者在Maven或Gradle项目中配置相应的依赖。 2. 创建解析器:实例化HTMLParser对象,可以设置不同的解析策略,如严格解析或宽容解析。 3. 配置处理器:...

    HtmlParser c#源码+demo

    HTMLParser 是一个C#编写的库,用于解析HTML文档,提取和处理其中的数据。这个库可能包含了一...通过学习源码和示例,开发者可以更好地理解和应用这个工具,同时也可以根据需要对其进行定制,以适应不同的项目需求。

    HtmlParser源码及其jar包

    总的来说,HTMLParser是一个强大且灵活的工具,能够帮助Java开发者轻松地处理和解析HTML文档,无论是为了数据抓取还是其他Web相关的任务。了解和掌握这个库的使用,对于从事相关工作的IT专业人士来说是非常有价值的...

    HtmlParser 实现简易爬虫

    在提供的压缩包中,"lib"目录下的jar文件就是HTMLParser库,将其添加到项目的类路径中,这样就可以在代码中使用这个库了。 接下来,我们需要编写爬虫的核心部分,即解析和提取数据的逻辑。以下是一个简单的示例: ...

Global site tag (gtag.js) - Google Analytics