- 浏览: 274855 次
- 性别:
- 来自: 湖南岳阳
最新评论
-
ternus:
兄弟,我用boboBrowse 也遇到了排序的问题,上线了讨论 ...
lucene 分组 bobo-Browse 排序的问题 -
luli0822:
Awesome bookmarks of those guru ...
流行的jQuery信息提示插件(jQuery Tooltip Plugin) -
shenbai:
如果你要在前台运行,你应该run得是ElasticSearch ...
ElasticSearch 源码分析 环境入门 -
cl1154781231:
<s:peroperty value="#at ...
关于Struts2中标签的一些心得 -
RonQi:
转载的吗?http://blog.csdn.net/stray ...
利用bobo-browse 实现lucene的分组统计功能
htmlparser (HTML Parser )是 sourceforge.net 上的一个成熟的 java 项目。它可以解析 HTML 页面,用来抽取或修改其内容,通过过滤器、访问者来访问程序关心的标签(Tag )。
一般使用 htmlparser 来做 HTML 解析后的抽取工作,但对 HTML 内容进行结构化修改则比较少用到。前段有一个对 HTML 抓取后修改其中所有链接地址的需求,使用 htmlparser 将 HTML 页面中附带资源(non html resource)的 URL 地址都做一下转换,包括链接(LinkTag)、图片(ImageTag)、框架页(FrameTag)、表单(FormTag)标签中指定的资源地址, 还包括 head 中的 link(HeaderLinkTag)标签中指定的 CSS/favicon.ico 以及 script(ScriptExTag)标签中指定的 JS 文件资源地址。对于后二者 HeaderLinkTag 和 ScriptExTag 标签的处理功能在 htmlparser 是没有实现的,需要自己通过编写继承于 TagNode/CompositeTag 基类的自定义标签来做匹配、修改逻辑。
OK 言归正传,下面给出在 htmlparser 中修改 HTML 内容的 2 种方法。
首先,第 1 种修改方法可以通过自定义继承 UrlModifyingVisitor 的子类来自定义修改 URL 逻辑,通过 org.htmlparser .Parser 提供的遍历模式来完成修改。 直接上代码。
import java.net.MalformedURLException; import java.net.URL; import java.util.logging.Logger; import org.htmlparser.Tag; import org.htmlparser.Text; import org.htmlparser.tags.FormTag; import org.htmlparser.tags.FrameTag; import org.htmlparser.tags.ImageTag; import org.htmlparser.tags.LinkTag; import org.htmlparser.visitors.UrlModifyingVisitor; import org.lzy.fwswaper.FwswaperServlet; import org.lzy.fwswaper.htmlhandler.HtmlHandlerHelper; import org.lzy.fwswaper.util.ExceptionUtils; public class HtmlparserUrlModifier extends UrlModifyingVisitor { private static final Logger log = Logger.getLogger(HtmlparserUrlModifier.class.getName()); private URL base = null; public HtmlparserUrlModifier(URL base) { super(""); this.setBaseUrl(base); } public void setBaseUrl(URL base) { if (!HtmlHandlerHelper.isHttpLikeProtocolUrl(base)) throw new IllegalArgumentException(String.format( "Base url argument '%s' is not http like protocol. " + "They are not prefix with '%s' or '%s'", this.base.toString(), HtmlHandlerHelper.HttpProtocol, HtmlHandlerHelper.HttpsProtocol)); this.base = base; } public void visitStringNode(Text stringNode) { // MUST override this method. // Super class UrlModifingVistor wrote: 'this.modifiedResult.append (stringNode.toHtml());'. // It will append stringNode.toHtml() conent to outside of <html/> tag if not override it. } public void visitTag(Tag tag) { try { if (tag instanceof LinkTag) { LinkTag link = (LinkTag) tag; log.info(String.format("Found link: '%s' => '%s'.", link.getLinkText(), link.extractLink())); if (link.isHTTPLikeLink()) link.setLink(this.modifying(new URL(base, link.getLink()))); } else if (tag instanceof HeaderLinkTag) { HeaderLinkTag link = (HeaderLinkTag) tag; log.info(String.format("Found head link: '%s' => '%s'.", link.getLinkText(), link.getLink())); URL url = new URL(base, link.getLink()); if (HtmlHandlerHelper.isHttpLikeProtocolUrl(url)) link.setLink(this.modifying(url)); } else if (tag instanceof ScriptExTag) { ScriptExTag script = (ScriptExTag) tag; String src = script.getSrc(); if ((src != null) && (src.length() > 0)) { log.info(String.format("Found script: '%s' => '%s'.", script.getLanguage(), src)); URL url = new URL(base, src); if (HtmlHandlerHelper.isHttpLikeProtocolUrl(url)) script.setSrc(this.modifying(url)); } } else if (tag instanceof ImageTag) { ImageTag img = (ImageTag) tag; log.info(String.format("Found image => '%s'.", img.getImageURL())); URL url = new URL(base, img.getImageURL()); if (HtmlHandlerHelper.isHttpLikeProtocolUrl(url)) img.setImageURL(this.modifying(url)); } else if (tag instanceof FrameTag) { FrameTag frame = (FrameTag) tag; log.info(String.format("Found frame: '%s' => '%s'.", frame.getText(), frame.getFrameLocation())); URL url = new URL(base, frame.getFrameLocation()); if (HtmlHandlerHelper.isHttpLikeProtocolUrl(url)) frame.setFrameLocation(this.modifying(url)); } else if (tag instanceof FormTag) { FormTag form = (FormTag) tag; log.info(String.format("Found form: '%s' => (%s) '%s'.", form.getFormName(), form.getFormMethod(), form.extractFormLocn())); URL url = new URL(base, form.extractFormLocn()); if (HtmlHandlerHelper.isHttpLikeProtocolUrl(url)) form.setFormLocation(this.modifying(url)); } } catch(Exception e) { log.warning(String.format("Modify url failed. Exception message: '%s'.", ExceptionUtils.getStackTrace(e))); } super.visitTag(tag); } protected String modifying(URL url) throws MalformedURLException { // Modifying url and return. return null; } }
PrototypicalNodeFactory factory = new PrototypicalNodeFactory();
factory.registerTag(new HeaderLinkTag());
factory.registerTag(new ScriptExTag());
Parser parser = Parser.createParser(html, charset);
parser.setNodeFactory(factory);
// Match and modify link image and frame tag
url address.
HtmlparserUrlModifier modifier = new HtmlparserUrlModifier(this.base);
parser.visitAllNodesWith(modifier);
String html = modifier.getModifiedResult();
通过上面的 HtmlparserUrlModifier 中的具体处理,并在 org.htmlparser
.PrototypicalNodeFactory 中注册 HeaderLinkTag 和 ScriptExTag 这 2 个要匹配的自定义标签类型,我们就可以对 html 内容进行结构化修改了,实际看了 htmlparser
的源码就会发现根本上最后就是 setAttribute 方法的调用。
这里有两个问题需要说明:
1. 在继承 UrlModifyingVisitor 对它进行扩展时,一定要重载其 visitStringNode 方法,否则会发现在 htmlparser 处理后的结果中,在 html 标签外还会有页面所有的文本内容的副本,这里的文本是指那些用于在浏览器中显示的文字内容。正如上述代码中所示,在我重载的 visitStringNode 方法中没有做任何处理。通过 UrlModifyingVisitor 源码可以看到 visitStringNode 方法默认实现如下。
public void visitStringNode(Text stringNode) { modifiedResult.append (stringNode.toHtml()); }
2. 不能通过 org.htmlparser .Parser 类的 parse 方法在解析过程中对 html 内容进行修改,因为在解析完成后,你会发现必须通过 reset 方法来复位,这样之前的处理结果就全部失效了。
其次,第 2 种方法是通过 org.htmlparser .util.NodeList 保存结构化的 html 内容并对其修改,最后通过它的 toHtml 方法将修改结果导出。 示例代码如下所示。
private String parse(String html, String charset) throws ParserException { Parser parser = Parser.createParser(html, charset); NodeList list = parser.parse(null); String html = recurse(list).toHtml(); System.out.println(html); } private NodeList recurse(NodeList list) { if(list==null) return null; Node node = null; SimpleNodeIterator iterator = list.elements(); while(iterator.hasMoreNodes()) { node = iterator.nextNode(); if(node==null) break; if(node instanceof Tag ) { Tag tag = (Tag )node; // Modifying attributes or something else. recurse(node.getChildren()); } } return null; }
好了,这次要说的就是上面的这 2 个方法,希望能对有需要的兄弟有所帮助。记得上次在问答频道里有人问过这问题。
作者:lzy.je
出处:http://lzy.iteye.com
发表评论
-
Errors running builder 'DeploymentBuilder' on project_java
2014-10-09 11:54 739此问题一般发生在Myeclipse 保存文件并自动部署时候 ... -
MyEclipse的SVN插件的问题
2012-02-27 14:06 1716我的项目都统一使用了UTF-8编码 查看当前版本,还是提 ... -
Eclipse的SVN插件历史版本乱码的问题
2012-02-27 14:04 0我的项目都统一使用了UTF-8编码 查看当前版本,还是提 ... -
java中的io系统详解
2011-09-16 12:09 1080相关读书笔记、心得文章列表 Ja ... -
hibernate表关联注解
2011-08-02 11:39 1369好久就想玩一下hibernate注解了(因为不用hbm文件,维 ... -
TCP/IP传输层,你懂多少?
2011-05-12 17:13 1661你所不知道的传输层 题记:23页的文档上,满满当当的 ... -
关于Struts2中标签的一些心得
2011-05-06 17:21 1691最近在做Struts2+Hibernet的一个项目,在if标签 ... -
This wizard is not available because it requires a valid professional subscripti
2011-04-18 23:05 1830今天用myeclipse学习UML时,打开UML时出现了: ... -
Tomcat内存、连接数等性能参数设置
2011-04-08 09:59 1198默认参数不适合生产环 ... -
Java 垃圾回收策略调优
2011-03-28 17:52 1559JVM参数调优是一个很头 ... -
Eclipse 或 MyEclipse 不能自动编译 class文件(综合)
2011-03-25 11:50 4684有时候用Eclipse或者MyEclipse 的时候,发现不 ... -
AccessController.doPrivileged 小记
2011-03-24 11:43 1028AccessController.doPrivileged ... -
servlet 读取图片
2011-02-17 15:38 1105String path = "F:/wjbo ... -
获取文件长度http,ftp
2011-01-18 16:09 1692ftp: FTPClient ftp = new FTPCl ... -
类的设计原则
2010-12-13 18:14 1024开闭原则 Software entities ... -
收集的网站
2010-12-09 17:12 854NIO.2 入门,第 1 部分: 异步通道 API http ... -
看Hibernate源码 003 - ID Generator
2010-12-09 16:43 1310Hibernate的id生成有N种策略, 可以通过hbm文件或 ... -
看Hibernate源码 001
2010-12-09 10:40 1062我看书的方式一向是&quo ... -
Hibernate Memcached 配置
2010-12-08 15:39 2116官方网址: http://code.google.com/p/ ... -
tomcat如何配置虚拟目录及虚拟主机
2010-12-02 17:54 2151先说说如何用Eclipse来做servlet开发,那些proj ...
相关推荐
html解析器, 可满足90%以上的需求,可以分析自定义的标签, 开源项目, 最近4年没有修改记录, 2011.04.24有人再次进行了提交. 最新的htmlParser
如果要对HTML进行解析,提取HTML的数据或者修改HTML数据,HtmlParser是一个不错的选择,而且非常的简单好用
特此授予任何人免费获得本软件副本和相关文档文件(“软件”)的许可,不受限制地处理本软件,包括但不限于使用、复制、修改、合并的权利、发布、分发、再许可和/或出售软件的副本,并允许向其提供软件
将标准HTML元素,属性和内联样式转换为它们的React等效项,并提供一种修改和替换内容的简单方法。 安装 npm install react-html-parser # or yarn add react-html-parser 用法 import React from 'react' ; import ...
usage: ...或 引入src里面html2json.js/html2wxml.wxml/htmlparser.js/example.wxss...在example.wxss中,可自定义添加修改html标签对应的样式,以满足不同的需求,也欢迎提供全面的样式提交pull request。 标签列表:
selenium则提供了Chrome,IE,FireFox等的支持,每种浏览器都有execute_script和find_element_by_xx方法,可以方便的执行js脚本(包括修改元素)和读取html里面的元素。不足是selenium只提供对python2.6和2.7的支持...
12. Request的输出流可以避免流中内容直接缓冲到socket服务器。 13. Response的输入流可以有效的从socket服务器直接读取相应内容。 14. 在http1.0和http1.1中利用KeepAlive保持持久连接。 15. 直接获取服务器发送的...
用Java写的一个小工具,通过...这个小工具使用了GPL授权的HTMLParser库(htmlparser.sourceforge.net)。 这个小工具也采用GPL授权。代码以及Eclipse工程文件包含在压缩包内。欢迎修改加强,但是请遵循GPL授权与精神。
1.5 用不同的方法串联字符串 11 1.6 本章小结 12 1.7 习题 13 第2章 数值与运算符 15 2.1 不同类型的数值 15 2.2 程序文件 17 2.2.1 使用不同的类型 18 2.2.2 基本算术 20 2.2.3 一些惊喜 22 2.3 使用数值 23 2.3.1 ...
嵌套在html中 各种EJB之间的调用示例 7个目标文件 摘要:Java源码,初学实例,EJB调用实例 各种EJB之间的调用源码示例,用远程接口的引用访问EJB、函数将被FirstEJB调用,同时它将调用secondEJB 基于JAVA的UDP...
嵌套在html中 各种EJB之间的调用示例 7个目标文件 摘要:Java源码,初学实例,EJB调用实例 各种EJB之间的调用源码示例,用远程接口的引用访问EJB、函数将被FirstEJB调用,同时它将调用secondEJB 基于JAVA的UDP...
容易维护扩展(不需要修改主类就可以添加新的API支持) 注入型解释器(依据不同的返回格式注入相应的解释器) 集中管理请求参数与参数映射 以运行时异常的方式来管理错误的响应 使用泛型来做强类型编程 多协议扩展...
容易维护扩展(不需要修改主类就可以添加新的API支持) 注入型解释器(依据不同的返回格式注入相应的解释器) 集中管理请求参数与参数映射 以运行时异常的方式来管理错误的响应 使用泛型来做强类型编程 多协议扩展...
容易维护扩展(不需要修改主类就可以添加新的API支持) 注入型解释器(依据不同的返回格式注入相应的解释器) 集中管理请求参数与参数映射 以运行时异常的方式来管理错误的响应 使用泛型来做强类型编程 多协议扩展...
容易维护扩展(不需要修改主类就可以添加新的API支持) 注入型解释器(依据不同的返回格式注入相应的解释器) 集中管理请求参数与参数映射 以运行时异常的方式来管理错误的响应 使用泛型来做强类型编程 多协议扩展...
容易维护扩展(不需要修改主类就可以添加新的API支持) 注入型解释器(依据不同的返回格式注入相应的解释器) 集中管理请求参数与参数映射 以运行时异常的方式来管理错误的响应 使用泛型来做强类型编程 多协议扩展...
容易维护扩展(不需要修改主类就可以添加新的API支持) 注入型解释器(依据不同的返回格式注入相应的解释器) 集中管理请求参数与参数映射 以运行时异常的方式来管理错误的响应 使用泛型来做强类型编程 多协议扩展...
容易维护扩展(不需要修改主类就可以添加新的API支持) 注入型解释器(依据不同的返回格式注入相应的解释器) 集中管理请求参数与参数映射 以运行时异常的方式来管理错误的响应 使用泛型来做强类型编程 多协议扩展...
容易维护扩展(不需要修改主类就可以添加新的API支持) 注入型解释器(依据不同的返回格式注入相应的解释器) 集中管理请求参数与参数映射 以运行时异常的方式来管理错误的响应 使用泛型来做强类型编程 多协议扩展...