java解析html之HTMLparser初次尝试

2023-05-16

为了爬取一个网页的数据,尝试了一下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
 voidaccept(NodeVisitor visitor)
          Apply the visitor to this node.
 Objectclone()
          Allow cloning of nodes.
 voidcollectInto(NodeList list,NodeFilter filter)
          Collect this node and its child nodes into a list, provided the node satisfies the filtering criteria.
 voiddoSemanticAction()
          Perform the meaning of this tag.
 NodeListgetChildren()
          Get the children of this node.
 intgetEndPosition()
          Gets the ending position of the node.
 NodegetFirstChild()
          Get the first child of this node.
 NodegetLastChild()
          Get the last child of this node.
 NodegetNextSibling()
          Get the next sibling to this node.
 PagegetPage()
          Get the page this node came from.
 NodegetParent()
          Get the parent of this node.
 NodegetPreviousSibling()
          Get the previous sibling to this node.
 intgetStartPosition()
          Gets the starting position of the node.
 StringgetText()
          Returns the text of the node.
 voidsetChildren(NodeList children)
          Set the children of this node.
 voidsetEndPosition(int position)
          Sets the ending position of the node.
 voidsetPage(Page page)
          Set the page this node came from.
 voidsetParent(Node node)
          Sets the parent of this node.
 voidsetStartPosition(int position)
          Sets the starting position of the node.
 voidsetText(String text)
          Sets the string contents of the node.
 StringtoHtml()
          Return the HTML for this node.
 StringtoHtml(boolean verbatim)
          Return the HTML for this node.
 StringtoPlainTextString()
          A string representation of the node.
 StringtoString()
          Return the string representation of the node.
 

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

比如AndFilter,NotFilter,OrFilter,XorFilter

Class Summary
AndFilterAccepts nodes matching all of its predicate filters (AND operation).
CssSelectorNodeFilterA NodeFilter that accepts nodes based on whether they match a CSS2 selector.
HasAttributeFilterThis class accepts all tags that have a certain attribute, and optionally, with a certain value.
HasChildFilterThis class accepts all tags that have a child acceptable to the filter.
HasParentFilterThis class accepts all tags that have a parent acceptable to another filter.
HasSiblingFilterThis class accepts all tags that have a sibling acceptable to another filter.
IsEqualFilterThis class accepts only one specific node.
LinkRegexFilterThis class accepts tags of class LinkTag that contain a link matching a given regex pattern.
LinkStringFilterThis class accepts tags of class LinkTag that contain a link matching a given pattern string.
NodeClassFilterThis class accepts all tags of a given class.
NotFilterAccepts all nodes not acceptable to it's predicate filter.
OrFilterAccepts nodes matching any of its predicates filters (OR operation).
RegexFilterThis filter accepts all string nodes matching a regular expression.
StringFilterThis class accepts all string nodes containing the given string.
TagNameFilterThis 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,过滤主题div
			NodeFilter filter = new NodeFilter() {
				@Override
				public boolean accept(Node node) {
					if(node.getText().contains("style=\"border-bottom: 0px;\"")) {
						return true;
					} else {
						return false;
					}
				}
			};
			//定义一个Filter,过滤所有回复div
			NodeFilter replyfilter = new NodeFilter() {
				@Override
				public boolean accept(Node node) {
					String containsString = "id=\"r_";
					if(node.getText().contains(containsString)) {
						return true;
					} else {
						return false;
					}
				}
			};
			//组合filter
			OrFilter 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 div
				Node 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 div
				Node 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);
				//回复的tagNodeList
				NodeList 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;
	}


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

	@Test
	public  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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java解析html之HTMLparser初次尝试 的相关文章

  • 点阵屏上绘图——基于LCD12864 控制详解

    本文引用自 xff1a http blog csdn net s3c44b0x article details 7498706 原始地址 xff1a http www amobbs com thread 591361 1 1 html 相关
  • 使用iPad编写C++程序(转载)

    使用iPad编写C 43 43 程序 一 搭建C 43 43 环境 1在cydia内安装 deb 包 注 xff1a 在cydia 软件源 设置中改为开发者 xff0c 否则有些deb搜索不到 OpenSSH xff0c OpenSSL w
  • Python多线程学习(三、生产者与消费者)

    生产者与消费者问题是典型的同步问题 这里简单介绍两种不同的实现方法 1 xff0c 条件变量 view plaincopy to clipboardprint import threading import time class Produ
  • 在~Firmware下面用roslaunch 启动launch 报错 udp0: sendto:Invalid argument

    在 Firmware下面用roslaunch 启动launch 报错 xff0c 如下 roslaunch px4 mavros posix sitl launch 报错 ERROR 1658284290 546891096 udp0 se
  • roslaunch运行px4功能包 报错

    运行条件ubuntu 16 04 ros kinetic 隔段时间运行roslaunch 会如下错误 mavros posix sitl launch is neither a launch file in package px4 nor
  • tf2_ros::Buffer::Buffer(ros::Duration, bool)’未定义的引用

    新建一个功能包及 cpp文件后报错tf2 ros Buffer Buffer ros Duration bool 未定义的引用 opt ros kinetic include tf2 ros buffer h 51 xff1a 对 vtab
  • Android Studio 配置 JDK1.8 使用Lambda表达式

    Android Studio 配置 JDK1 8 使用Lambda表达式 JDK1 8 添加几项新特性譬如对集合的优化语法的便捷配合Lambda表达式使用可以让代码更加简便美观 xff0c 但对于一些没有接触Lambda表达式的同学们来说就
  • 深入解读四轴飞行器的硬件设计

    xfeff xfeff 转载自 xff1a http www openedv com posts list 20892 htm 传感器之一 xff1a 角速度传感器应用科里奥利力原理 xff1a 科里奥利力来自于物体运动所具有的惯性 xff
  • 【GIT】使用Vscode同步git仓库,错误和解决方法记录

    这里写目录标题 命令行操作仓库常见命令1 报错 在签出前 xff0c 请清理存储库工作树 2 报错 fatal unable to access 39 https github com 39 OpenSSL SSL read Connect
  • 基于k近邻(KNN)的手写数字识别

    作者 xff1a faaronzheng 转载请注明出处 xff01 最近再看Machine Learning in Action k近邻算法这一章节提供了不少例子 xff0c 本着Talk is cheap的原则 xff0c 我们用手写数
  • 机器学习算法地图(转自SIGAI)

    转自 xff1a http sigai cn paper 18 html 下面先看这张图 xff1a 图的左半部分列出了常用的机器学习算法与它们之间的演化关系 xff0c 分为有监督学习 xff0c 无监督学习 xff0c 强化学习 3 大
  • 一个非常适合单片机的滤波算法

    连接 xff1a http bbs 21ic com icview 170880 1 1 html 以下为原文 连接 xff1a http bbs 21ic com icview 170880 1 1 html 单片机大多资源小 xff0c
  • 6.蒙特卡洛方法(TSP)

    定义 xff1a 旅行商问题 xff0c 即TSP问题 xff08 Traveling Salesman Problem xff09 又译为旅行推销员问题 货郎担问题 xff0c 是数学领域中著名问题之一 假设有一个旅行商人要拜访n个城市
  • 云和AI时代下,需要怎样的存储?

    数字化浪潮席卷而来 xff0c 颠覆着传统的生产和生活方式 xff0c 随之产生的新经济和新应用给传统业务模式和产业结构带来前所未有的冲击 特别是云计算 人工智能 AI 和物联网 IoT 的兴起 xff0c 加快了传统产业升级改造的步伐 在
  • 人工智能6个核心技术

    机械学习 机械学习是多领域交叉的学科 xff0c 可以从学习模式和学习方法上面进行分类 xff0c 学习模式将机器学习分类为监督学习 无监督学习和强化学习等 xff0c 学习方法可以将机器学习分为传统机器学习和深度学习 机器学习按学习方式分
  • CAN总线的标准(二)

    一 OSI参考模型 CAN总线标准规定了物理层和数据链路层 xff0c 至于应用层需要用户自定义 不同的CAN标准仅物理层不同 物理层和数据链路层ISO11898 xff1b 应用层 xff1a 不同的应用领域使用不同的应用层标准 二 各层
  • 数据通信--ASCII码通信&16进制通信的区别

    16进制通信一般用于网络传输等的通信上 xff0c 传输效率高 数据量大是二进制通信 ASCII码通信一般用与串口通信等通信上 xff0c 数据量小 易于处理 便于调试 xff0c 它虽然是文本模式 xff0c 但本质仍然是二进制通信 在使
  • ubuntu下安装boost

    boost中 xff0c 用到了别的函数库 xff0c 所以为了使用boost中相应的功能 xff0c 需要先安装系统中可能缺失的库 第一步 安装依赖库 sudo apt get install mpi default dev 安装mpi库
  • 数据结构实验快速排序、冒泡排序算法(交换排序),使用STM32单片机测试(学计算机综合考试408悟单片机系列)

    快速排序和冒泡排序均属于交换排序范畴 xff0c 意味着其基本操作是交换两数 快速排序 xff0c 顾名思义快速的排序 xff0c 毫无遮拦得介绍了自己得特征 而冒泡排序也正如其名称 xff0c 如同养鱼冒泡一样慢条斯理锝排序 xff08
  • 操作系统-13-程序员应如何理解中断

    在这一节中我们聊一聊 xff0c 操作系统管理外设的中断机制 为什么要在这一节聊一聊操作系统如何管理外设呢 xff0c 外设管理是操作系统的核心任务之一 xff0c 理解操作系统的外设管理机制对于我们理解操作系统工作原理至关重要 通过第二章

随机推荐

  • Gitee实现本地代码上传他人的远程仓库

    前言 xff1a 需要下载git bash xff0c 并拥有自己的Gitee账号哦 关于git下载可以看这个博客 xff08 CSDN有很多 xff09 xff1a git git bash 下载与安装 娄笙悦的博客 CSDN博客 Git
  • 关于用elsevier-cas模板的一些问题

    关于用elsevier cas模板的一些问题 关于graphical abstract和highlight 这俩东西可能跟具体的期刊有关 xff0c 在我要投的这个期刊里边 xff0c 这俩是不需要的 xff0c 可以直接从模板中删除 关于
  • 几种供电总线技术

    PowerBus技术 PowerBus为可供电总线技术 xff0c 是业内唯一可以支持大功率负载供电和高速通讯的总线技术 xff0c 相比其他可供电总线技术 xff1a PowerBus供电效率高 xff0c 通过两根电源线最大可提供单个设
  • 使用dd复制将乌班图系统(Ubuntu22.04)完整迁移到新硬盘并扩容

    我的折磨历程 开始的时候用乌班图的时候 xff0c 不懂事 xff0c 根目录太小了 xff0c 后来就满了 xff0c 就就感觉完全没法用 xff0c 看着现在硬盘贼便宜 xff0c 去狗东买了个新的硬盘 感觉挂载硬盘并不能解决我的问题
  • 《剑指offer》面试题 12:矩阵中的路径(C++实现)

    题目 请设计一个函数 xff0c 用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径 路径可以从矩阵中任意一格开始 xff0c 每一步可以在矩阵中向左 右 上 下移动一格 如果一条路径经过了矩阵的某一格 xff0c 那么该路径不能再
  • CocosCreator项目实战(13):功能-排行榜

    文章目录 一 主域设置二 子域设置三 其他相关设置 参考Cocos接入微信小游戏官方文档 xff0c 为了保护其社交关系链数据 xff0c 微信小游戏增加了开放数据域的概念 只有在开放数据域中才能访问微信提供的wx getFriendClo
  • Android MotionLayout 运动布局的使用

    Google 在 2018 年开发者大会上推出一种新的布局组件 MotionLayout 其官方定义如下 xff1a MotionLayout is a layout type that helps you manage motion an
  • Jetpack练手(03):DataBinding

    文章目录 一 导入依赖二 搭建布局三 创建 ViewModel 数据对象四 修改布局为 DataBinding 布局五 绑定数据六 Demo 效果 一 导入依赖 新建 DataBindingDemo 工程 xff0c 参照 LiveData
  • Jetpack练手(04):Lifecycle

    文章目录 一 搭建布局二 非 Lifecycle 实现三 Lifecycle 实现四 Demo 效果 一 搭建布局 新建 LifecycleDemo 工程实现 界面停留时间计时 xff0c 在 activity main xml 搭建简单布
  • OpenDDS学习笔记(4):OpenDDS在Linux环境编译

    文章目录 一 编译前准备1 1 环境1 2 下载ACE 43 TAO与OpenDDS1 3 解压安装ACE 43 TAO与OpenDDS1 4 设置相关环境变量 二 编译2 1 设置config h2 2 设置Platform macros
  • OpenDDS学习笔记(2):DDS概述

    文章目录 一 DDS体系结构1 1 DLRL层1 2 DCPS层 二 DDS通信过程三 DDS通信特点四 DDS标准实现4 1 RTI DDS软件4 2 OpenSplice DDS软件4 3 OpenDDS软件 一 DDS体系结构 DDS
  • OpenDDS学习笔记(3):OpenDDS概述

    文章目录 一 DCPS概述1 1 基本组成1 2 内置主题1 3 QoS策略1 4 Listener1 5 条件 二 OpenDDS实现2 1 兼容性2 1 1 DDS兼容性2 1 2 DDS RTPS兼容性 2 2 OpenDDS架构2
  • FastRTPS学习笔记(2):安装、创建简单应用

    文章目录 一 FastRTPS v1 8 0 安装运行1 1 环境准备1 2 下载FastRTPS v1 8 01 3 编译安装1 4 创建简单应用1 4 1 编写简单程序1 4 2 编译简单程序1 4 3 运行简单示例 二 FastRTP
  • EOF是什么?

    转载自 xff1a http www ruanyifeng com blog 2011 11 eof html 我学习C语言的时候 xff0c 遇到的一个问题就是EOF 它是end of file的缩写 xff0c 表示 34 文字流 34
  • FastRTPS学习笔记(1):RTPS概述

    文章目录 一 RTPS简介二 RTPS优点三 RTPS架构3 1 结构模块3 2 消息模块3 3 行为模块3 4 发现模块 四 参考来源 一 RTPS简介 实时发布订阅协议 xff08 Real Time Publish Subscribe
  • 面试笔记:面经-猿辅导-一面

    文章目录 一 自我介绍二 项目相关三 Java后台3 1 Java异常处理3 1 1 Exception和Error的区别3 1 2 RuntimeException和CheckedException的区别 3 2 Java线程3 2 1
  • TensorFlow安装和下载(超详细)

    TensorFlow是一款开源的机器学习框架 xff0c 可用于构建和训练各种深度学习模型 在下面的回答中 xff0c 我将向您介绍如何在Windows Linux和Mac OS系统上安装和下载TensorFlow Windows系统上安装
  • geometry_msgs::PoseWithCovarianceStamped

    该消息表示带有时间标签和参考坐标的估计位姿 两部分构成 xff1a std msgs Header header geometry msgs PoseWithCovariance pose 1 std msgs Header msg主要由三
  • ubuntu vnc 下面小企鹅输入法 的安装及使用

    使用VNC View远程访问ubuntu xff0c 总是没有办法切换出小企鹅输入法的解决办法 安装Fcitx输入法 sudo apt get install fcitx 安装 im switch s fcitx 配置默认输入法为 fcit
  • java解析html之HTMLparser初次尝试

    为了爬取一个网页的数据 xff0c 尝试了一下Htmlparser来做小爬虫 下面是一个小案例 xff0c 用来爬取论坛的帖子内容 1 HtmlParser 简介 htmlparser是一个纯的java写的html解析的库 xff0c 主要