http://www-128.ibm.com/developerworks/cn/java/l-html-parser/
本文并非想通过分析HTML的语法然后从中解析出数据,这样做实现困难而且没有什么实际应用的意义,或者应该这样说:我们并不想自己去实现一个HTML语法的分析器。我们要做的仅仅是从HTML中提取我们所需的信息。不同于XML这种对格式要求非常严格的标志语言,HTML在推出时并没有对其格式进行严格的定义,比如HTML中标签并不一定要成对出现,但是又要求浏览器能尽量的正确显示其所要表达出来的内容。浏览器经过多年发展其适应能力越来越强,很多格式非常糟糕的HTML文件都能显示得令人满意。不过如果我们需要精确的获取HTML中包含的数据,这恐怕比显示一个HTML更令人头疼。现在终于找到治疗头疼的特效药了!
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
接下来我们要介绍的就是使用 JAVA 语言如何简单快速的攫取 HTML 中包含的数据。我们会借助一些现有的成熟 API 来完成这件事,因为如果仅仅是为了实现这个功能,完全没有必要自己去实现 HTML 的语法分析器。我们引入了一个开源的项目-- HTML Parser ,这是一个在 SourceForge.net 上比较活跃的项目之一,目前的最新版本是 1.4 发行版。有如 HTML Parser 网站的自我介绍: HTML Parser 是一个对现有的 HTML 进行分析的快速实时的解析器,事实上在应用过程中你更为惊叹于 HTML Parser 给你带来一些周到的处理。
考虑到很多读者并不清楚该项目的应用场合,因此我依照以前的步骤来组织这篇文章。首先是提出问题,讲述我在怎么一种情况下需要对 HTML 进行语法解析;其次是分析问题,如何考虑到使用 HTML Parser 来达到我所需要的目的;最后就是解决问题。
提出问题
在实际开发一个内容管理项目时,由于内容是基于 HTML 的格式进行存储以及编写,并提供了一个基于浏览器的所见即所得的 HTML 编辑器。用户经常会直接从其他网站上复制一些带格式的内容后直接发布,首页会显示这些内容的概要信息,概要信息直接切割内容,从中读取前几个字。这种做法引发的问题是,截断的内容包含不完整的格式信息,因为切割的长度是固定的,比如我取前 400 个字用于做概要显示,这时候经常把内容中的一些表格切断,这些包含不完整格式信息的内容带来的问题就是它将破坏整个页面的布局,我们碰到最常见的问题就是页面被撑大,从输出的页面源码中可以看出就是因为这些不完整的表格标签导致。
分析问题
解决我们前面提出的问题的办法唯有使内容的切割更加智能化,可以自动的处理例如表格被切断这个影响格式的罪魁祸首。之前的做法是在切割后的内容中搜索没有被正常结束的表格标签,这解决了大部分内容无法正常显示的问题,但是这仅仅处理了最简单的情况,一旦出现嵌套表格被切割的情况也就无能为力,如果我们再自己来处理嵌套表格的情况,那考虑的问题就非常的多,因为为了使页面的排版美观,网页设计师大量的使用表格来进行处理,事实上这也是编写 HTML 的唯一办法。因此你可能要对各种各样的表格嵌套方式进行单独的处理,想象一下你编写一个万行的代码来完成一个看似简单的问题,你的领导肯定跟你急了 ^_^,问题还在于你这一万行的代码并不一定可以解决问题。因此在这个问题的处理上我们要尽量采取一些成熟稳定的API,HTML Parser 就是一个用于解析 HTML 文本的开源项目,它可以准确高效的对HTML文本中的格式、数据进行处理,有将近二十位来自世界各地的工程师在为这个项目工作。
HTML Parser项目主要可以用在以下两个方面:
1. 信息提取
- 文本信息抽取,例如对HTML进行有效信息搜索
- 链接提取,用于自动给页面的链接文本加上链接的标签
- 资源提取,例如对一些图片、声音的资源的处理
- 链接检查,用于检查HTML中的链接是否有效
- 页面内容的监控
2. 信息转换
- 链接重写,用于修改页面中的所有超链接
- 网页内容拷贝,用于将网页内容保存到本地
- 内容检验,可以用来过滤网页上一些令人不愉快的字词
- HTML信息清洗,把本来乱七八糟的HTML信息格式化
- 转成XML格式数据
HTML Parser并没有对以上提到的一些应用进行专门的处理,但是它完全可以胜任上面提及的功能,在实际应用中如果遇见上面提及的问题可以使用该项目来处理。
解决问题
接下来我主要针对我们在前面提过那个网页截断的问题进行处理。我的做法是强行对HTML内容进行截断,然后把截断后的内容传递给HTML Parser,由它来补全缺漏的标签。这样做可能有些内容显示不全,但是至少不会破坏页面的排版。通过这样一个简单的例子可以了解HTML Parser的基本结构以及使用流程。
首先从SourceForge网站上下载HTML Parser的压缩包(下载网址参照文章最后的资料参考部分),下图是解压后的目录结构,其中画红线的是我们所需要的jar包文件。把这个文件加到项目的类路径中,其他类可以不管!
/**
* 获取HTML的预览信息,其中content是对象的一个属性,也就是待处理的HTML内容
* @return
*/
public String getPreviewContent(){
//截取前N个字符
String ct = StringUtils.left(content,MAX_COUNT);
//对一些未完成的标签先补齐,避免出现例如<tab这样的标签
if(ct!=null&&content!=null) {
int idx2 = ct.lastIndexOf('>');
int idx1 = ct.lastIndexOf('<');
if((idx2==-1 && idx1>=0) || idx1 > idx2) {
String ct2 = content.substring(ct.length());
int idx3 = ct2.indexOf('>');
if(idx3!=-1 && idx3<(MAX_COUNT2-MAX_COUNT)) {
ct += content.substring(ct.length(),ct.length()+idx3+1);
}
}
}
//对于一些页面嵌入了ActiveX对象进行预处理
if(ct!=null&&content!=null) {
int idx2 = ct.toLowerCase().lastIndexOf("</object>");
int idx1 = ct.toLowerCase().lastIndexOf("<object");
if((idx2==-1 && idx1>=0) || idx1 > idx2) {
String ct2 = content.substring(ct.length()).toLowerCase();
int idx3 = ct2.indexOf("</object>");
if(idx3!=-1)
ct += content.substring(ct.length(),ct.length()+idx3+9);
else
ct = ct.substring(0,idx1);
}
}
if(ct!=null&&content!=null) {
Parser parser = Parser.createParser(new String(ct.getBytes(),ISO8859_1));
<!-- code sample is too wide -->
//中文信息必须转码后方可传入
Node [] tables = parser.extractAllNodesThatAre (TableTag.class);
if(tables!=null&&tables.lengtd>0) {
TableTag tableTag = (TableTag)tables[0];
ct = ct.substring(0,tableTag.getStartPosition())
+ new String(tableTag.toHtml().getBytes(ISO8859_1));
//处理后的数据转回GBK的编码
}
}
return ct;
}
|
上面这段代码就是用于显示HTML概要信息的方法,其中粗体部分是使用HTML Parser进行处理的过程。类Parser是HTML Parser的入口,我们可以将HTML文本信息传入给它,或者可以直接传递一个URL地址,如下:
Parser parser = new Parser("http://www.javayou.com");
|
初始化一个Parser实例后,紧接着就是对所传入的HTML内容进行解析,大家注意红色粗体的那行代码,从方法名我们很容易理解,该方法就是将HTML内容中存在的所有的表格给解析出来放到一个数组去,该方法所需的参数就是节点的类型,我们这里用的是表格的标签,几乎HTML的标签中都有对应的一个对应的类,比如FormTag、InputTag、AppletTag等等,这些标签类都在org.htmlparser.tags包中。根据我们要处理不同的标签传入不同的类,这种做法使我们可以很方便的处理其他类型的标签。返回的数组中每个元素都是你传入类的一个实例,通过这个实例可以访问到当前这个标签的起始未知、结束标签的未知以及包含在标签中的文本信息,同时也可以访问其父标签以及所有的子标签等等,同时我们可以通过toHtml方法来对标签中包含的HTML信息进行清洗,HTML Parser会自动帮我们把一些没有关闭的标签加上,这样所生成的字符串中就包含着完整的格式控制信息,在页面上显示这样的信息也不会破坏版面布局,达到了我预期的效果。
为了使大家更直观的看到执行效果,我们再来一个小例子并附上执行的结果:
public static void main(String[] args) throws Exception {
//不完整格式的HTML信息
String html = "我们是害虫<table>1234567890<table>lk你好中国";
Parser parser = Parser.createParser(new String(html.getBytes(),"8859_1"));
Node [] tables = parser.extractAllNodesThatAre (TableTag.class);
for (int i = 0; i < tables.length; i++) {
TableTag tableTag = (TableTag)tables[i];
//打印出结束标签所在的未知
System.out.println("END POS:"+tableTag.getEndTag().getEndPosition());
//补齐未结束的标签并打印
System.out.println(new String(tableTag.toHtml().getBytes("8859_1")));
}
}
|
这段代码旨在找出一段不完整 HTML 信息中的所有表格标签,然后打印出经过格式化后的 HTML 信息,下图是在 Eclipse 环境下的执行结果。
为了更好的在实际的业务中应用HTML Parser 项目,HTML Parser 还提供了几个例子用于处理前面我们提到的功能实现。这些例子在解压目录下的 bin 都有批处理命令可以执行,执行时给命令传入 URL 地址或者是 html 文件的路径即可。
HTML Parser 项目仅仅是提供给我们一个简单而强健的 API 用于分析 HTML 文本信息,更多的应用模式还有待于我们自己去发掘,希望本文能将你引入 HTML Parser 的大门。
============================================================================================
1.6版
-
packagecom.thy.deltabletag;
-
importorg.htmlparser.NodeFilter;
-
importorg.htmlparser.Parser;
-
importorg.htmlparser.filters.NodeClassFilter;
-
importorg.htmlparser.tags.TableTag;
-
importorg.htmlparser.util.NodeList;
-
publicclassDeleteTableTag{
-
privatestaticintMAX_COUNT=0;
-
publicStringgetPreviewContent(){
-
Stringcontent="";
-
-
Stringct=content.substring(0,MAX_COUNT);
-
-
if(ct!=null&&content!=null){
-
intidx1=ct.lastIndexOf('<');
-
intidx2=ct.lastIndexOf('>');
-
if((idx2==-1&&idx1>=0)||idx1>idx2){
- Stringct2=content.substring(ct.length());
-
intidx3=ct2.indexOf('>');
-
if(idx3!=-1){
- ct+=content
-
.substring(ct.length(),ct.length()+idx3+1);
- }
- }
- }
-
-
if(ct!=null&&content!=null){
-
intidx2=ct.toLowerCase().lastIndexOf("</object>");
-
intidx1=ct.toLowerCase().lastIndexOf("<object");
-
if((idx2==-1&&idx1>=0)||idx1>idx2){
- Stringct2=content.substring(ct.length()).toLowerCase();
-
intidx3=ct2.indexOf("</object>");
-
if(idx3!=-1)
- ct+=content
-
.substring(ct.length(),ct.length()+idx3+9);
-
else
-
ct=ct.substring(0,idx1);
- }
- }
-
if(ct!=null&&content!=null){
-
try{
-
Parserparser=Parser.createParser(newString(ct.getBytes()),"GB2312");
-
-
-
NodeFilterfilter=newNodeClassFilter(TableTag.class);
- NodeListnodes=parser.extractAllNodesThatMatch(filter);
-
-
-
if(nodes!=null&&nodes.size()>0){
-
TableTagtableTag=(TableTag)nodes.elementAt(0);
-
ct=ct.substring(0,tableTag.getStartPosition())
-
+newString(tableTag.toHtml().getBytes("GB2312"));
- }
-
}catch(Exceptione){
- e.printStackTrace();
- }
-
- }
-
returnct;
- }
-
publicstaticvoidmain(String[]args)throwsException{
-
-
Stringhtml="我们是害虫<table>1234567890<table>lk你好中国是";
-
Parserparser=Parser.createParser(newString(html.getBytes()),"GB2312");
-
NodeFilterfilter=newNodeClassFilter(TableTag.class);
- NodeListnodes=parser.extractAllNodesThatMatch(filter);
-
if(nodes!=null){
-
for(inti=0;i<nodes.size();i++){
- TableTagtableTag=(TableTag)nodes.elementAt(i);
-
-
System.out.println("ENDPOS:"
- +tableTag.getEndTag().getEndPosition());
-
- System.out
-
.println(newString(tableTag.toHtml().getBytes("GB2312")));
- }
- }
- }
- }
分享到:
相关推荐
它提供了一种易于使用的API,用于抓取和解析网页内容,从而帮助开发者从HTML文档中提取所需的数据。jsoup的出现弥补了传统HTMLParser库更新不及时的问题,为开发者提供了更加高效、稳定且功能丰富的解决方案。 ### ...
Java 程序在解析HTML 文档时,相信大家都接触过htmlparser 这个开源项目,我曾经在IBM DW 上发表过两篇关于htmlparser 的文章,分别是:从HTML中攫取你所需的信息 和扩展HTMLParser 对自定义标签的处理能力。...
Java 程序在解析HTML 文档时,相信大家都接触过htmlparser 这个开源项目,我曾经在IBM DW 上发表过两篇关于htmlparser 的文章,分别是:从HTML中攫取你所需的信息 和扩展HTMLParser 对自定义标签的处理能力。...
Java 程序在解析HTML 文档时,相信大家都接触过htmlparser 这个开源项目,我曾经在IBM DW 上发表过两篇关于htmlparser 的文章,分别是:从HTML中攫取你所需的信息 和扩展HTMLParser 对自定义标签的处理能力。...
颜色代码查看器是一种非常实用的工具,主要用于帮助用户在计算机屏幕上快速、准确地获取颜色的数值表示...无论是为了匹配界面元素、创建配色方案,还是从现有的视觉元素中提取颜色,颜色代码查看器都能提供强大的支持。
这种题目的特点在于,它要求考生不仅要理解给定材料中的一句话,还需要从材料中找到与这句话相关的答题信息点,然后进行准确、简明的概括。 首先,面对这种新题型,考生需要仔细阅读题干,明确题目要求理解的句子所...
电脑内各种注册程序使用久了,密钥忘了咋办?用了它,一切好办。
在当今的商业环境中,小客户市场常常被误解和忽视,但事实证明,这个市场蕴含着巨大的利润潜力。ThunderBird & Company的分析揭示了两种常见的错误看法:一是将小客户视为“劣质客户”,从而放弃这部分市场;二是...
如何从这些残缺不全的字符中攫取完整的信息,是字符识别的关键问题。作为字符识别的组成部分之一的数字识别在邮政、交通及商业票据管理方面有着极高的应用价值。目前有很多种方法用于字符识别,主要分为神经网络识别...
信息战部队压缩敌对国家政权决策空间及战略优势,攫取战争利益情报机构搜集敏感的政治、军事、经济信息。 2. 威胁的多元性 – 情报机构。监听、社会工程学、网络侦察、渗透等都是情报机构的威胁方式。 3. 威胁的...
在淘宝诉美丽说的案件中,美丽说利用爬虫抓取淘宝的商品信息,涉及到了电商平台的数据安全与用户隐私;京东诉易迅网的案例则揭示了爬虫技术可能对电商平台的正常运营造成的干扰。 这些案例反映出,网络爬虫技术在...
本书以图配文,结合实例详细讲解了如何利用从网站上获取的各种数据了解网站的运营状况,如何从数据中攫取最有用的信息,如何优化站点,创造更大的网站价值。本书适合各类网站运营人员阅读。
目前是信息爆炸的时代,我们已经没有太多的精力去用双眼攫取有用的信息,《网页关键词监控 程序》监控机器人将有用的信息自动发给自己,解放双眼,掌控先机。软件简介 《网页关键词监控程序》是一款优秀批量多线程对...
编辑目录属性,例如使用关键字搜索功能,便于在大量清单中查找所需项目。详细定义执行装配的活动和属性,以便更精确地规划过程。同时,创建过程库,用于保存特殊进程的数据记录,过程库属性则允许添加更多详细信息。...
然而,任何模型中的节点每增加一个,连接数就会翻一倍,维系结构秩序所需要的综合成本也会增加一倍。如果成本不足以支持升级的时候,结构中的各要素就会被限制在原有模型的边界之内。 秩序和存续 秩序是一切的基础...
Internet的迅猛发展满足了人们对信息的渴求,然而Internet里也存在许多不安全因素,网络信息的非法攫取,网络体系的肆意破坏等等都将给企业带来难以估计的损失。因此,防火墙技术在企业网络安全防护中具有越来越重要...
选取2003--2006年间中国上市公司中发生的85笔大额且控制股东地位发生变更的非流通股转让交易为研究对象,通过实证研究表明: 中国上市公司中以大额股权转让溢价衡量的控股股东控制权私人收益规模平均达到10.66%;...
闪电交易攫取者可以帮助你赶上你想要的亚马逊闪电优惠,只要他们可用。有了这个扩展,即使你不在计算机上,你也可以尽快地选择你的闪电交易。 当你选择的交易即将到来的时候,你是否曾经陷入分心?不再。你可以专注...