为了爬取一个网页的数据,尝试了一下Htmlparser来做小爬虫。

下面是一个小案例,用来爬取论坛的帖子内容。

1. HtmlParser 简介

htmlparser是一个纯的java写的html解析的库,主要用于改造或提取html。用来分析抓取到的网页信息是个不错的选择,遗憾的是参考文档太少。
项目主页: http://htmlparser.sourceforge.net/
API文档: http://htmlparser.sourceforge.net/javadoc/index.html

2. 建立Maven工程

添加相关依赖

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.fancy</groupId><artifactId>htmlParser</artifactId><version>0.0.1-SNAPSHOT</version><dependencies><dependency><groupId>org.htmlparser</groupId><artifactId>htmlparser</artifactId><version>2.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies>
</project>

2.1 创建一个解析器

用parser来抓取并分析一个网页。

parser并不会处理网页中的异步请求,在抓取页面后会把真个页面解析成DOM树,并以各种形式的节点/TAG存储,然后我们就可以用各种过滤器来帅选自己想要的节点。

htmlparser的已包含节点如下

org.htmlparser
Interface Node

All Superinterfaces:
Cloneable
All Known Subinterfaces:
Remark,Tag,Text
All Known Implementing Classes:
AbstractNode,AppletTag,BaseHrefTag, BodyTag, Bullet, BulletList, CompositeTag, DefinitionList, DefinitionListBullet, Div, DoctypeTag, FormTag, FrameSetTag, FrameTag, HeadingTag, HeadTag, Html, ImageTag, InputTag, JspTag, LabelTag, LinkTag, MetaTag, ObjectTag, OptionTag, ParagraphTag, ProcessingInstructionTag, RemarkNode, ScriptTag, SelectTag, Span, StyleTag, TableColumn, TableHeader, TableRow, TableTag, TagNode, TextareaTag, TextNode, TitleTag

网页被解析后获得的都是这些节点以及他们之间的父子包含关系。

每一个节点都包含如下方法(很多节点还会自己实现更多的方法,例如linktag有些方法用于获取link标签的url,检查这个url的协议类型...)


Method Summary
 void accept(NodeVisitor visitor)
          Apply the visitor to this node.
 Object clone()
          Allow cloning of nodes.
 void collectInto(NodeList list,NodeFilter filter)
          Collect this node and its child nodes into a list, provided the node satisfies the filtering criteria.
 void doSemanticAction()
          Perform the meaning of this tag.
 NodeList getChildren()
          Get the children of this node.
 int getEndPosition()
          Gets the ending position of the node.
 Node getFirstChild()
          Get the first child of this node.
 Node getLastChild()
          Get the last child of this node.
 Node getNextSibling()
          Get the next sibling to this node.
 Page getPage()
          Get the page this node came from.
 Node getParent()
          Get the parent of this node.
 Node getPreviousSibling()
          Get the previous sibling to this node.
 int getStartPosition()
          Gets the starting position of the node.
 String getText()
          Returns the text of the node.
 void setChildren(NodeList children)
          Set the children of this node.
 void setEndPosition(int position)
          Sets the ending position of the node.
 void setPage(Page page)
          Set the page this node came from.
 void setParent(Node node)
          Sets the parent of this node.
 void setStartPosition(int position)
          Sets the starting position of the node.
 void setText(String text)
          Sets the string contents of the node.
 String toHtml()
          Return the HTML for this node.
 String toHtml(boolean verbatim)
          Return the HTML for this node.
 String toPlainTextString()
          A string representation of the node.
 String toString()
          Return the string representation of the node.

节点过滤器,这些过滤器可以按照即诶但类型。节点之间父子关系,也可以自定义过滤器。多个过滤器之间可以组合成符合过滤器用于多条件过滤,

比如AndFilter,NotFilter,OrFilter,XorFilter

Class Summary
AndFilter Accepts nodes matching all of its predicate filters (AND operation).
CssSelectorNodeFilter A NodeFilter that accepts nodes based on whether they match a CSS2 selector.
HasAttributeFilter This class accepts all tags that have a certain attribute, and optionally, with a certain value.
HasChildFilter This class accepts all tags that have a child acceptable to the filter.
HasParentFilter This class accepts all tags that have a parent acceptable to another filter.
HasSiblingFilter This class accepts all tags that have a sibling acceptable to another filter.
IsEqualFilter This class accepts only one specific node.
LinkRegexFilter This class accepts tags of class LinkTag that contain a link matching a given regex pattern.
LinkStringFilter This class accepts tags of class LinkTag that contain a link matching a given pattern string.
NodeClassFilter This class accepts all tags of a given class.
NotFilter Accepts all nodes not acceptable to it's predicate filter.
OrFilter Accepts nodes matching any of its predicates filters (OR operation).
RegexFilter This filter accepts all string nodes matching a regular expression.
StringFilter This class accepts all string nodes containing the given string.
TagNameFilter This class accepts all tags matching the tag name.

抓取http://www.v2ex.com网站中的一篇帖子

首先要创建获取网页内容,分析网页元素结构制作过滤器;

可以看到回复div的id都是r_加六位数字,推荐使用正则表达式匹配,主题的样式是corder-bottom:0px(一定要缺人过滤器的结果,免得引入多余节点)。

创建一个方法,获得主题和回复节点集合

    /*** * 获取html中的主题和所有回复节点* * @param url* @param ENCODE* @return*/protected  NodeList getNodelist(String url, String ENCODE) {try {NodeList nodeList = null;Parser parser = new Parser(url);parser.setEncoding(ENCODE);//定义一个Filter,过滤主题divNodeFilter filter = new NodeFilter() {@Overridepublic boolean accept(Node node) {if(node.getText().contains("style=\"border-bottom: 0px;\"")) {return true;} else {return false;}}};//定义一个Filter,过滤所有回复divNodeFilter replyfilter = new NodeFilter() {@Overridepublic boolean accept(Node node) {String containsString = "id=\"r_";if(node.getText().contains(containsString)) {return true;} else {return false;}}};//组合filterOrFilter allFilter = new OrFilter(filter, replyfilter);nodeList = parser.extractAllNodesThatMatch(allFilter);return nodeList;} catch (ParserException e) {e.printStackTrace();return null;}}

好了有了这些节点接下来就是解析了。

这个例子代码只写了一部分元素的获取,剩下的活也是体力活慢慢分析节点关系,用过滤器或者dom树找目标节点。

下面的代码是将解析到的节点数据封装到bean

  public Forum parse2Thread(String url,String ENCODE) {List<Reply> replylist = new ArrayList<Reply>();   //回复列表Topic topic = new Topic();   //主题NodeFilter divFilter = new NodeClassFilter(Div.class);//div过滤器NodeFilter headingFilter = new NodeClassFilter(HeadingTag.class);//heading过滤器NodeFilter tagFilter = new NodeClassFilter(TagNode.class);//heading过滤器NodeList nodeList = this.getNodelist(url, ENCODE);//解析node到帖子实体for (int i = 0; i < nodeList.size(); i++) {Node node = nodeList.elementAt(i);if(node.getText().contains("style=\"border-bottom: 0px;\"")) {//如果node是主题NodeList list = node.getChildren();//node的子节点//header divNode headerNode = list.extractAllNodesThatMatch(new NodeClassFilter(Div.class)).elementAt(0);//帖子主题Node h1Node = headerNode.getChildren().extractAllNodesThatMatch(headingFilter).elementAt(0);topic.setTopicName(h1Node.toPlainTextString());//发帖人信息NodeList headerChrildrens = headerNode.getChildren();topic.setAnn_name(headerChrildrens.elementAt(15).toPlainTextString());topic.setTopicDescribe(headerChrildrens.elementAt(16).toPlainTextString());//发帖人头像链接Node frNode = headerChrildrens.extractAllNodesThatMatch(divFilter).elementAt(0);ImageTag imgNode = (ImageTag) frNode.getFirstChild().getFirstChild();topic.setAnn_img(imgNode.getImageURL());//cell divNode cellNode = list.extractAllNodesThatMatch(divFilter).elementAt(1);Node topic_content = cellNode.getChildren().extractAllNodesThatMatch(divFilter).elementAt(0);Node markdown_body = topic_content.getChildren().extractAllNodesThatMatch(divFilter).elementAt(0);topic.setTopicBody(markdown_body.toPlainTextString());//暂时不包含连接和图片纯文本} else if(node.getText().contains("id=\"r_")){//节点是回复Reply reply = new Reply();Node tableNode = node.getChildren().extractAllNodesThatMatch(tagFilter).elementAt(0);Node trNode = tableNode.getChildren().extractAllNodesThatMatch(tagFilter).elementAt(0);//回复的tagNodeListNodeList tagList = trNode.getChildren().extractAllNodesThatMatch(tagFilter);ImageTag reply_img = (ImageTag) tagList.elementAt(0).getChildren().extractAllNodesThatMatch(tagFilter).elementAt(0);reply.setReply_img(reply_img.getImageURL());//nodeList bodyNode = tagList;replylist.add(reply);}}System.out.println("-----------实体----------------");Forum forum = new Forum(topic, replylist);System.out.println(forum.toString());return null;}

好了。解析都做完了,在写个主方法分析一个帖子试试;

   @Testpublic  void test() throws Exception {Html2Domain parse = new Html2DomainImpl();parse.parse2Thread("http://www.v2ex.com/t/262409#reply6","UTF-8");}

看看运行结果:

这个内容过长,截图只能看到帖子名称,和帖子内容了,有兴趣的自己去测试把。请一定要注意地址,貌似这个网站帖子连接会有失效时间,假如测试获取失败请换个帖子地址试试。

附上项目代码:测试使用的是jdk1.6+eclipse kepler

http://pan.baidu.com/s/1mh9OuDi

java解析html之HTMLparser初次尝试相关推荐

  1. Java解析HTML之HTMLParser使用与详解

    1.相关资料 官方文档:http://htmlparser.sourceforge.NET/samples.html API:http://htmlparser.sourceforge.net/jav ...

  2. java解析字符串_用Java解析字符串有哪些不同的方法?

    用Java解析字符串有哪些不同的方法? 对于解析播放器命令,我最常使用split方法通过定界符对字符串进行分割,然后再通过一系列ifs或switches找出其余部分. Java中解析字符串的几种不同方 ...

  3. 用Java解析:您可以使用的所有工具和库

    如果需要从Java解析语言或文档,则从根本上讲有三种方法可以解决问题: 使用支持该特定语言的现有库:例如用于解析XML的库 手动构建自己的自定义解析器 生成解析器的工具或库:例如ANTLR,可用于构建 ...

  4. java解析网页全过程_Java网页解析

    介绍 今天给大家推荐一款最好的网页解析类库-HtmlCleaner.至少是目前为止最好的Java解析库. 与HtmlCleaner结缘是在年初的时候,因为一项工作需要解析Html页面,所以我在网上遍寻 ...

  5. Office中数学公式用Java解析,java解析word公式

    公司正在做教育类产品,在遇到数学公式时,我们一般会使用latex表达式来做保存和渲染. 在其中一个项目上,遇到一个需求是要从office文档(Word或Excel)中导入题目内容至数据库,题目内容中就 ...

  6. Java 解析纯真IP库

    JAVA解析纯真IP地址库 博客分类: JAVA Java log4j Cache 数据结构 J#  前几天看了下Ruby的IPParse,觉得很过瘾,上网查了下貌似很多IP数据库都要收费的,就下了个 ...

  7. poi处理word内容的公式_Office中数学公式用Java解析

    公司正在做教育类产品,在遇到数学公式时,我们一般会使用latex表达式来做保存和渲染. 在其中一个项目上,遇到一个需求是要从office文档(Word或Excel)中导入题目内容至数据库,题目内容中就 ...

  8. IDEA Java解析GeoJson.json文件

    IDEA Java解析GeoJson.json文件 一.遇到的问题 1. 无法导入成功 2. org.geotools.StyleFactory is not an ImageIO SPI class ...

  9. easyexcel生成excel_阿里JAVA解析Excel工具easyexcel

    java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有 ...

最新文章

  1. IT人应该具备的几种技能
  2. Servlet线程安全
  3. grailsgroovy的IllegalArgument异常
  4. RocketMQ 消息持久化机制
  5. CXF小窥:知道服务器端wsdl地址,如何本地测试服务接口
  6. vue定时ajax获取数据,vue 中使用 AJAX获取数据的方法
  7. Codeforces Round #485 (Div. 2)
  8. 搭载麒麟990 5G SoC 华为MatePad Pro 5G全球首发
  9. Android--Activity的跳转及Activity之间的数据传递
  10. 汉字的字向量、词向量和表示学习(中文词向量)
  11. 基于Montgomery算法的高速、可配置 RSA密码IP核硬件设计系列(三)——抵抗侧信道攻击设计方案
  12. 免费的PPT素材网站
  13. c++实现串口功能之termios.h头文件研读<一>
  14. 维度表和事实表的区别
  15. 微信状态栏隐藏 HTML,完美解决微信video视频隐藏控件和内联播放问题
  16. java isnull方法_isnull函数详解
  17. 把Date类型的Fri Feb 01 00:00:00 CST 2019转换成yyyy-MM-dd格式
  18. 一大波苹果CMS系统主题来袭
  19. Cesium加载各种互联网地图(一)
  20. 谷歌浏览器chrom兼容问题

热门文章

  1. 使用另一种方式连接数据库
  2. 0x00007FF7C49A4C42 处有未经处理的异常:0xC0000005: 读取位置 0x000001481A2D86C4 时发生访问冲突
  3. 定期定量采购_定期订货法与定量订货法分析
  4. java项目宕机出现原因,java服务宕机原因查询
  5. 《Google Android 开发入门与实战》
  6. ADC0809转换器
  7. 解决[W pthreadpool-cpp.cc:90] Warning: Leaking Caffe2 thread-pool after fork. (function pthreadpool)
  8. SPAN_EXCLUSIVE_INCLUSIVE用法、区别
  9. 华科大计算机学院学生宿舍,华中科大教授郑强不掀桌子,班级60学生住45间寝室,会有所改观吗...
  10. matlab实现移位寄存器,基于matlab的移位寄存器法m序列的产生