HTML 和 XML 数据的分析与解析

5 篇文章 0 订阅
5 篇文章 0 订阅

目前在 Java 中,解析 HTML 工具主要包含以下几种:

1、jsoup:强大的 HTML 解析工具,支持以 jQuery 中 CSS Selector 的方式提取 HTML 中的元素,学习成本较低。
2、HtmlCleaner:另外一款开源的 Java 语言的 HTML 文档解析器,支持以 XPath 的方式提取 HTML 中的元素。另外,在此说明,学习 XPath 语法对于使用另外一款基于 Selenium 的爬虫工具特别有帮助。
3、Htmlparser:对 HTML 进行有效信息搜索和提取的一款 Java 工具,但该工具已长时间不维护了(上次更新时间为2011年)。

HtmlCleaner 解析 HTML
HtmlCleaner 下载
在 MVNRepository 中搜索 HtmlCleaner。并使用 Eclipse 或其他工具构建 Maven 工程,使用 Maven 工程中的 pom.xml 下载 HtmlCleaner 相关依赖 Jar 包。本篇以最新版 HtmlCleaner 配置为例:

<!-- https://mvnrepository.com/artifact/net.sourceforge.htmlcleaner/htmlcleaner -->
<dependency>
    <groupId>net.sourceforge.htmlcleaner</groupId>
    <artifactId>htmlcleaner</artifactId>
    <version>2.22</version>
</dependency>

Xpath 语法
XPath 是一门在 XML 文档中查找信息的语言,其可用来在 XML 文档中对元素和属性进行遍历。在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档节点(或称为根节点)。其在 HTML 解析中,主要是对节点进行选取,而在选取的过程中,需要路径进行定位。

在此仍以前面章节讲到的 w3school 网页的 HTML 为例(http://www.w3school.com.cn/b.asp),限于本文的篇幅,以下是经过我整理后的部分网页内容:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>浏览器脚本教程</title>
<link rel="stylesheet" type="text/css" href="/c5.css">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
</head>
<body id="homesecond" class="browserscripting">
<div id="navsecond">
    <div id="course">
        <ul>
            <li><a href="/js/index.asp" title="JavaScript 教程">JavaScript</a></li>
            <li><a href="/htmldom/index.asp" title="HTML DOM 教程">HTML DOM</a></li>
            <li><a href="/jquery/index.asp" title="jQuery 教程">jQuery</a></li>
            <li><a href="/ajax/index.asp" title="AJAX 教程">AJAX</a></li>
            <li><a href="/json/index.asp" title="JSON 教程">JSON</a></li>
            <li><a href="/dhtml/index.asp" title="DHTML 教程">DHTML</a></li>
            <li><a href="/e4x/index.asp" title="E4X 教程">E4X</a></li>
            <li><a href="/wmlscript/index.asp" title="WMLScript 教程">WMLScript</a></li>
        </ul>
    </div>
</div>
<div id="maincontent">
    <div id="w3school">
        <h1>浏览器脚本教程</h1>
        <p>
            <strong>从左侧的菜单选择你需要的教程!</strong>
        </p>
    </div>
    <div>
        <h2>JavaScript</h2>
        <p>
            JavaScript 是世界上最流行的脚本语言。
        </p>
        <p>
            JavaScript 是属于 web 的语言,它适用于 PC、笔记本电脑、平板电脑和移动电话。
        </p>
        <p>
            JavaScript 被设计为向 HTML 页面增加交互性。
        </p>
        <p>
            许多 HTML 开发者都不是程序员,但是 JavaScript 却拥有非常简单的语法。几乎每个人都有能力将小的 JavaScript 片段添加到网页中。
        </p>
        <p>
            如果您希望学习更多关于 JavaScript 的知识,请马上访问我们的 
            <a href="/js/index.asp" title="JavaScript教程">JavaScript 教程</a>。
        </p>
    </div>
    <div>
        <h2>HTML DOM</h2>
        <p>
            HTML DOM 定义了访问和操作 HTML 文档的标准方法。
        </p>
        <p>
            DOM 以树结构表达 HTML 文档。
        </p>
        <p>
            <a href="/htmldom/index.asp" title="HTML DOM 教程">开始学习 HTML DOM</a> !
        </p>
    </div>
</div>
</body>
</html>

下表是 Xpath 的常用语法,案例对应上面的 HTML 文档。
表达式	描述	实例	结果nodename	选取此节点的所有子节点	body	选取 body 元素的所有子节点。/	从根元素选取	/html	选取根元素 HTML。//	从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。	//div	选取所有 div 元素,而不管它们在文档的位置。.	选取当前节点	./p	选取当前节点下的 p 节点。..	选取当前节点的父节点	../p	选取当前节点的父节点下的 title。@	选取属性	//a[@href]	选取所有拥有名为 href 的属性的 a 元素。@	选取属性	//div [@id='course']	选取所有 id 属性为 course 的 div 节点。//div[@id='w3school']/h1	选取所有 id 属性为 w3school 的 div 节点下的 h1 节点。//body/a[1]	选取属于 body 子元素的第一个 a 元素。//body//a[last()]	选取属于 body 子元素的最后一个 a 元素。
定位一个节点可以使用多种写法,例如上面的 HTML,选取所有 id 属性为 w3school 的 div 节点下的 h1 节点,可以使用以下几种 Xpath 定位。

//div[@id='w3school']//h1
//div[@id='w3school']/h1
//*[@id='w3school']/h1

另外在浏览器中,可以在审查(元素)中,定位我们需要采集的数据,右键之后点击 copy -> copy xpath,获取相应的 Xpath 写法。

解析 HTML
使用 HtmlCleaner 首先要对其进行初始化,初始化之后,我们便可以使用 Xpath 语法操作节点。以下为 w3school 页面的解析案例。解析的内容如下:
在这里插入图片描述
对应的程序为:

//这里笔者使用jsoup获取html文件
Document doc = Jsoup.connect("http://www.w3school.com.cn/b.asp").timeout(5000).get(); /
String html =doc.html();  //转化成String格式
//使用Htmlcleaner解析数据
HtmlCleaner cleaner = new HtmlCleaner(); //初始化对象
//System.out.println(html);
TagNode node = cleaner.clean(html); //解析HTML文件
//通过Xpath定位标题的位置,这里使用//h1和/h1的结果是一样的
Object[]  ns = node.evaluateXPath("//div[@id='w3school']//h1");  
System.out.println("HTML中的标题是:\t" + ((TagNode)ns[0]).getText());  
Object[]  ns1 = node.evaluateXPath("//*[@id='w3school']/h1"); 
System.out.println("HTML中的标题是:\t" + ((TagNode)ns1[0]).getText());  
//遍历获取课程名以及课程地址
Object[]  ns2 = node.evaluateXPath("//*[@id='course']/ul//a");  //这里使用//a表示不考虑位置,如果使用/a获取不到内容
for(Object on : ns2) {  
    TagNode n = (TagNode) on;  
    System.out.println("课程名为:\t" + n.getText() + "\t地址为:\t" + n.getAttributeByName("href"));  
} 
//获取每个课程名称以及其对应的简介
Object[]  ns3 = node.evaluateXPath("//*[@id='maincontent']//div");
for (int i = 1; i < ns3.length; i++) {
    TagNode n = (TagNode) ns3[i]; 
    //获取课程名称
    String courseName = n.findElementByName("h2", true).getText().toString();
    //循环遍历所有的p节点获取课程简介
    Object[] objarrtr = n.evaluateXPath("//p");
    String summary = "";
    for(Object on : objarrtr) { 
        summary += ((TagNode) on).getText().toString();
    } 
    System.out.println(courseName + "\t" + summary);
}

在使用 evaluateXPath(String xPathExpression) 操作 TagNode 时得到的是 Object[] 数组,通过对该数组的操作便能够获取数据。另外,HtmlCleaner 还提供了很多种用法,例如上述程序中的 findElementByName()、getAttributeByName() 等操作方法,感兴趣的读者可以学习官方文档。利用上述程序解析得到的结果,如下图所示:
在这里插入图片描述
HtmlParser 解析 HTML
HtmlParser 下载
依旧采用 Maven 工程中的 pom.xml 下载 HtmlParser 相关依赖 Jar 包,配置如下:

<!-- https://mvnrepository.com/artifact/org.htmlparser/htmlparser -->
<dependency>
    <groupId>org.htmlparser</groupId>
    <artifactId>htmlparser</artifactId>
    <version>2.1</version>
</dependency>

工具使用介绍
HTMLParser 的核心模块是 Parser 类,在实际的应用中也是通过该类分析 HTML 文件。该类中常用的构造方法总结如下:

在这里插入图片描述
对大多数使用这来说,可以通过 URLConnection 或者通过其他工具获取的 HTML 字符串来初始化 Parser。HTMLParser 将解析过的信息保存为树结构,其中重要的是 Node 数据类型。Node 中包含的方法有对树结构操作的函数以及获取 Node 节点中包含内容的函数。
在这里插入图片描述
在这里插入图片描述
使用案例
首先我给出第一个使用案例。给定 HTML 字符串,使用 Parser(Lexer lexer) 构造,结合过滤器的使用提取网页中的所有链接(即 href 对应的内容以及链接对应的标题),仍以上面的 w3school 的页面为案例(http://www.w3school.com.cn/b.asp)。如下程序:

//这里笔者使用Jsoup获取html文件
Document doc = Jsoup.connect("http://www.w3school.com.cn/b.asp").timeout(5000).get(); 
String html =doc.html();  //转化成String格式
//使用Lexer构造
Lexer lexer = new Lexer(html);
Parser parser = new Parser(lexer);
//过滤页面中的链接标签
NodeFilter filter = new NodeClassFilter(LinkTag.class);
//获取匹配到的节点
NodeList list = parser.extractAllNodesThatMatch(filter);
//遍历每一个节点
for(int i=0; i<list.size();i++){
    Node node = (Node)list.elementAt(i); 
    System.out.println("链接为:" + ((LinkTag) node).getLink() + "\t标题为:" + node.toPlainTextString() );
}

上述程序对应的输出结果如下图所示:
在这里插入图片描述
第二个案例是基于 Filter 层层过滤的方式解析想要的数据。例如,w3school 页面中的:

在这里插入图片描述
该案例程序使用 Parser(String resource) 构造,程序如下:

//生成一个解析器对象,用网页的 url 作为参数
Parser parser = new Parser("http://www.w3school.com.cn/b.asp");
//设置网页的编码(GBK)
parser.setEncoding("gbk");
//过滤页面中的标签
NodeFilter filtertag= new TagNameFilter("ul");
NodeFilter filterParent = new HasParentFilter(filtertag);  //父节点包含ul
NodeFilter filtername = new TagNameFilter("li");  //选择的节点为每个li
NodeFilter filterId= new HasAttributeFilter("id");  //并且li节点中包含id属性
NodeFilter filter = new AndFilter(filterParent,filtername); //并操作
NodeFilter filterfinal = new AndFilter(filter,filterId); //并操作
NodeList list = parser.extractAllNodesThatMatch(filterfinal);  //选择匹配到的内容
//循环遍历
for(int i=0; i<list.size();i++){
    //获取li的第一个子节点
    Node node = (Node)list.elementAt(i).getFirstChild(); 
    System.out.println( "链接为:" + ((LinkTag) node).getLink() +"\t标题为:" + node.toPlainTextString() );
}

程序的输出结果如下:
在这里插入图片描述
第三个案例是基于 CSS 选择器来解析想要的数据。例如,w3school 页面中的:
在这里插入图片描述
这个案例程序我将使用 Parser(URLConnection connection) 构造,具体程序如下:

//使用URLConnection请求数据
URL url = new URL("http://www.w3school.com.cn/b.asp");
URLConnection conn = url.openConnection();
Parser parser = new Parser(conn);
//通过css选择器解析内容 
CssSelectorNodeFilter Filter=new CssSelectorNodeFilter ("#course > ul > li");  
NodeList list = parser.extractAllNodesThatMatch(Filter);  //选择匹配到的内容
//循环遍历
for(int i=0; i<list.size();i++){
    //获取li的第一个子节点
    Node node = (Node)list.elementAt(i).getFirstChild(); 
    System.out.println( "链接为:" + ((LinkTag) node).getLink() +"\t标题为:" + node.toPlainTextString() );
}

使用 CSS 选择器筛选是一种简单又快捷的方式,也是我个人最喜欢用的一种解析 HTML 的方式,这和 jsoup 有异曲同工之处。如要系统的学习 CSS 选择器的使用,读者可以参考:这里。

jsoup 解析 XML
为讲解 XML 数据的解析,我选取的案例是爬取网易汽车的销量数据,例如捷达汽车的销量,页面为:

http://db.auto.sohu.com/cxdata/xml/sales/model/model1001sales.xml

其部分 XML 文件如下:

<model id="1001" name="捷达">
    <sales date="2007-01-01" salesNum="14834"/>
    <sales date="2007-02-01" salesNum="9687"/>
    <sales date="2007-03-01" salesNum="18173"/>
    <sales date="2007-04-01" salesNum="18508"/>
    <sales date="2007-05-01" salesNum="19710"/>
    <sales date="2007-06-01" salesNum="20311"/>
    <sales date="2007-07-01" salesNum="17516"/>
</model>

利用 jsoup 选择器,可以快速的解析 XML 文件中的数据。解析捷达汽车的销售月份以及该月份的汽车销量,可采用如下程序:

//获取URL对应的HTML内容
Document doc = Jsoup.connect("http://db.auto.sohu.com/cxdata/xml/sales/model/model1001sales.xml").timeout(5000).get();
//Jsoup选择器解析
Elements sales_ele = doc.select("sales");
for (Element elem:sales_ele) {
    int salesnum=Integer.valueOf(elem.attr("salesnum"));
    String date = elem.attr("date");
    System.out.println("月份:" + date + "\t销量:" + salesnum);

}

程序解析数据的结果如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值