nekohtml使用笔记
1、透明地创建HTML解析器
利用Xerces2.0为基础,应用程序通过JAXP实例化解析器对象时,可以透明地创建HTML解析器,此时只需要将NekoHTML的jar文件,在CLASSPATH中放在Xerces的jar文件之前即可。nekohtmlXni.jar中的META-INF/services/org.apache.xerces.xni.parser.XMLParserConfiguration文件会被Xerces的读取并取代标准的设置文件,此处org.apache.xerces.xni.parser.XMLParserConfiguration文件的内容就是一个字符串"org.cyberneko.html.HTMLConfiguration"。这种方法的好处是简单透明,缺点是影响了Xerces在其它情况下的使用。
2、便利的HTML解析器类
要想避免上述的问题,可以使用org.cyberneko.html.parsers包的DOM和SAX解析器类来创建解析器,这两个类都使用了HTMLConfiguration类。解析器一旦创建之后,就可以解析HTML文件,并用标准的XML接口来访问文件中的信息,就象面对的是一个XML文件一样。
3、文档片段解析
除了DOM和SAX类,NekoHTML还提供了一个实验性质的DOMFragmentParser类,用以解析HTML文件的片段。我个人认为,由于浏览器的强大的容错能力,即使一个片段的HTML文件,也可以正确显示,由此也变相地造成了很多人不再关心的HTML的完整要求了。这个类,也许将是用的最多的。下面,看看nutch是如何使用nekoHTML的。
package net.nutch.fetcher;
...
import org.cyberneko.html.parsers.*;
import org.xml.sax.*;
import org.w3c.dom.*;
import org.w3c.dom.html.*;
import org.apache.html.dom.*;
/* A simple fetcher. */
public class Fetcher {
....
private DOMFragmentParser parser = new DOMFragmentParser();
....
private void handleFetch(URL url, FetchListEntry fle, Http.Response response)
throws IOException, SAXException {
//判断HTTP应答包的类型,只放过html文件
String contentType = response.getHeader("Content-Type");
if (contentType != null && !contentType.startsWith("text/html"))
throw new IOException("Unknown content-type: " + contentType);
//创建文件片段对象
DocumentFragment node = new HTMLDocumentImpl().createDocumentFragment();
//解析HTML内容
parser.parse(new InputSource(new ByteArrayInputStream(response.getContent())),node);
//取得全部文本内容
StringBuffer sb = new StringBuffer();
getText(sb, node);
String text = sb.toString();
//取得标题信息
sb.setLength(0);
getTitle(sb, node);
String title = sb.toString().trim();
//取得该页所有的出链
ArrayList l = new ArrayList();
getOutlinks(url, l, node);
//显示结果,存储信息
Outlink[] outlinks = (Outlink[])l.toArray(new Outlink[l.size()]);
LOG.fine("found " + outlinks.length + " outlinks in " + url);
outputPage(new FetcherOutput(fle, MD5Hash.digest(response.getContent()),
true, title, outlinks),
new FetcherContent(response.getContent()),
new FetcherText(text));
}
private static void getText(StringBuffer sb, Node node) {
if (node.getNodeType() == Node.TEXT_NODE) {
sb.append(node.getNodeValue());//取得结点值,即开始与结束标签之间的信息
}
NodeList children = node.getChildNodes();
if ( children != null ) {
int len = children.getLength();
for ( int i = 0; i < len; i++ ) {
getText(sb, children.item(i));//递归遍历DOM树
}
}
}
private static boolean getTitle(StringBuffer sb, Node node) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
if ("title".equalsIgnoreCase(node.getNodeName())) {
getText(sb, node);
return true;
}
}
NodeList children = node.getChildNodes();
if (children != null) {
int len = children.getLength();
for (int i = 0; i < len; i++) {
if (getTitle(sb, children.item(i))) {
return true;
}
}
}
return false;
}
private static void getOutlinks(URL base, ArrayList outlinks, Node node) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
if ("a".equalsIgnoreCase(node.getNodeName())) {
StringBuffer linkText = new StringBuffer();
getText(linkText, node);
NamedNodeMap attrs = node.getAttributes();
String target= null;
for (int i= 0; i < attrs.getLength(); i++ ) {
if ("href".equalsIgnoreCase(attrs.item(i).getNodeName())) {
target= attrs.item(i).getNodeValue();//在DOM树中,属性是一个结点。
break;
}
}
if (target != null)
try {
URL url = new URL(base, target);
outlinks.add(new Outlink(url.toString(),linkText.toString().trim()));
} catch (MalformedURLException e) {
// don't care
}
}
}
NodeList children = node.getChildNodes();
if ( children != null ) {
int len = children.getLength();
for ( int i = 0; i < len; i++ ) {
getOutlinks(base, outlinks, children.item(i));//递归遍历DOM树
}
}
}
....
}
//注意,此处传递给解析过程parse的文档片段对象,必须是由//org.w3c.dom.html.HTMLDocument类型的DOM文档对象创建,否则有异常。
// HTMLConfiguration可以用于创建任何基于XNI解析器,可参考下例
package sample;
import org.apache.xerces.parsers.AbstractSAXParser;
import org.cyberneko.html.HTMLConfiguration;
public class HTMLSAXParser extends AbstractSAXParser {
public HTMLSAXParser() {
super(new HTMLConfiguration());
}
}
三、设置解析器参数
为了更加精确的控制解析的动作,nekohtml提供了相应的设置函数。如下列:
// settings on HTMLConfiguration
org.apache.xerces.xni.parser.XMLParserConfiguration config =
new org.cyberneko.html.HTMLConfiguration();
config.setFeature("http://cyberneko.org/html/features/augmentations", true);
config.setProperty("http://cyberneko.org/html/properties/names/elems", "lower");
// settings on DOMParser
org.cyberneko.html.parsers.DOMParser parser =
new org.cyberneko.html.parsers.DOMParser();
parser.setFeature("http://cyberneko.org/html/features/augmentations", true);
parser.setProperty("http://cyberneko.org/html/properties/names/elems", "lower");
nekohtml功能(feature)列表
功能 默认值 描述
http://cyberneko.org/html/features/balance-tags True 是否允许增补缺失的标签。如果要以XML方式操作HTML文件,此值必须为真。此处提供设置功能,为了性能的原因。
http://cyberneko.org/html/features/balance-tags/ignore-outside-content False 是否忽略文档根元素以后的数据。如果为false,<html>和<bod>被忽略,所有的内容都被解析。
http://cyberneko.org/html/features/document-fragment False 解析HTML片段时是否作标签增补。此功能不要用在DOMParser上,而要用在DOMFragmentParser上。
http://apache.org/xml/features/scanner/notify-char-refs False 当遇到字符实体引用(如&#x20;)是否将(#x20)报告给相应地文档处理器。
http://apache.org/xml/features/scanner/notify-builtin-refs False 当遇到XML内建的字符实体引用(如&amp;)是否将(amp)报告给相应地文档处理器。
http://cyberneko.org/html/features/scanner/notify-builtin-refs False 当遇到HTML内建的字符实体引用(如&copy;)是否将(copy)报告给相应地文档处理器。
http://cyberneko.org/html/features/scanner/script/strip-comment-delims False 是否剥掉<script>元素中的等注释符。
http://cyberneko.org/html/features/augmentations False 是否将与HTML事件有关的infoset项包括在解析管道中。
http://cyberneko.org/html/features/report-errors False 是否报告错误。
nekohtml属性列表
属性 默认值 值域 描述
http://cyberneko.org/html/properties/filters null XMLDocumentFilter[] 在解析管道的最后按数组顺序追加自定义的处理组件(过滤器),必须为数组类型。
http://cyberneko.org/html/properties/default-encoding Windows-1252 IANA encoding names 默认的HTML文件编码
http://cyberneko.org/html/properties/names/elems upper upper,lower,match 如果整理识别出的元素名称
http://cyberneko.org/html/properties/names/attrs lower upper,lower,no-change 如果整理识别出的属性名称
四、管道过滤器
Xerces Native Interface (XNI)定义了一个解析器配置框架,在那儿一个个解析器以模块化组件的形式组成一个管道。这样一来,通过重新安排已有组件和/或新定制开发的组件,就可完成一个新的解析器配置工作。由于nekohtml是采用这个配置框架开发的,所以对解析器新增功能就很简单通过在默认的nekohtml解析管道的末端增加文档过滤器来实现。
要新开发一个过滤器,很简单地实现xerces2的org.apache.xerces.xni.parser包中的 XMLDocumentFilter接口即可。这个接口,一方面使组件成为管道中上一级的事件处理器,另一方面又成为下级的信息源。针对nekohtml 的过滤器开发,只需简单地扩展org.cyberneko.html.filters包中的DefaultFilter类即可。
将自行开发的过滤器加入管道,可参考以下两种办法:
XMLDocumentFilter noop = new DefaultFilter();
XMLDocumentFilter[] filters = { noop };
XMLParserConfiguration parser = new HTMLConfiguration();
parser.setProperty("http://cyberneko.org/html/properties/filters", filters);
nekohtml的org.cyberneko.html.filters 包中有DefaultFilter、
ElementRemover、Identity、Writer,能实现动态插入内容、删除元素、序列化HTML文档等,不详细述。
htmlparser解析自定义标签功能
import org.htmlparser.tags.CompositeTag;
public class StrongTag extends CompositeTag {
private static final String mIds[] = {
"strong"
};
private static final String mEndTagEnders[] = {
"strong"
};
public Strong()
{
}
public String[] getIds()
{
return mIds;
}
public String[] getEndTagEnders()
{
return mEndTagEnders;
}
}
上面就是定义这个tag标签继承CompositeTag
然后最重要的是,在使用的时候要注册这个tag
parser = new Parser(url);
PrototypicalNodeFactory p=new PrototypicalNodeFactory();
p.registerTag(new Li());
parser.setNodeFactory(p);
4行代码注册完成,,一个简单的标签自定义完成。
htmlparser获取网页上所有有用链接的方法
public static void getAllLink(String html, String parentUrl) {
Parser parser = new Parser();
try {
parser.setInputHTML(html);
NodeFilter filter = new NodeClassFilter(LinkTag.class);
NodeList nodes = parser.parse(filter);
for (Node node : nodes.toNodeArray()) {
LinkTag linkTag = (LinkTag) node;
String link = linkTag.getLink().trim();
// 过滤,过滤方法可以添加,比如在增加只爬去本域名或本主机名下的网站等等
if (!"".equals(link)) {
//处理一下那些不是以“http://”开头的url,比如以"/html/....或 html/...."开头的
URI uri = new URI(parentUrl);
URI _uri = new URI(uri, link);
String newUrl = _uri.toString();
urls.add(link);
}
}
} catch (ParserException e) {
throw new RuntimeException("htmlparser解析html文件时异常" + e);
} catch (URIException e) {
e.printStackTrace();
}
}
Java 正则表达
\ 反斜杠
\t 间隔 ('\u0009')
\n 换行 ('\u000A')
\r 回车 ('\u000D')
\d 数字 等价于[0-9]
\D 非数字 等价于[^0-9]
\s 空白符号 [\t\n\x0B\f\r]
\S 非空白符号 [^\t\n\x0B\f\r]
\w 单独字符 [a-zA-Z_0-9]
\W 非单独字符 [^a-zA-Z_0-9]
\f 换页符
\e Escape
\b 一个单词的边界
\B 一个非单词的边界
\G 前一个匹配的结束
^为限制开头
^java 条件限制为以Java为开头字符
$为限制结尾
java$ 条件限制为以java为结尾字符
. 条件限制除\n以外任意一个单独字符
java.. 条件限制为java后除换行外任意两个字符
两者取一「|」
J|A J或A
Java|Hello Java或Hello
限制为连续出现指定次数字符「{a}」
J{2} JJ
J{3} JJJ
◆文字替换(首次出现字符)
Pattern pattern = Pattern.compile("正则表达式");
Matcher matcher = pattern.matcher("正则表达式 Hello World,正则表达式 Hello World");
//替换第一个符合正则的数据
System.out.println(matcher.replaceFirst("Java"));
◆去除html标记
Pattern pattern = Pattern.compile("<.+?>", Pattern.DOTALL);
Matcher matcher = pattern.matcher("<a href=\"index.html\">主页</a>");
String string = matcher.replaceAll("");
System.out.println(string);
HtmlCleanner结合xpath用法
HtmlCleaner cleaner = new HtmlCleaner();
TagNode node = cleaner.clean(new URL("http://finance.sina.com.cn/money/nmetal/20091209/10157077895.shtml"));
//按tag取.
Object[] ns = node.getElementsByName("title", true); //标题
if(ns.length > 0) {
System.out.println("title="+((TagNode)ns[0]).getText());
}
// /html/body/div[2]/div[4]/div/div/div/div[2]/p
ns = node.evaluateXPath("//div[@class=\"blkContainerSblkCon\"]/p"); //选取class为指定blkContainerSblkCon的div下面的所有p标签
for (int i = 0; i < ns.length; i++) {
String in = cleaner.getInnerHtml((TagNode)ns[i]);
System.out.println("<p>"+in + "</p>");
}
String in = cleaner.getInnerHtml((TagNode)ns[0]);
System.out.println(in);
System.out.println(((TagNode)ns[0]).getText());
HtmlCleaner cleaner = new HtmlCleaner();
String url = "http://finance.sina.com.cn/nmetal/hjfx.html";
URL _url = new URL(url);
TagNode node = cleaner.clean(_url);
//按tag取.
Object[] ns = node.getElementsByName("title", true); //标题
if(ns.length > 0) {
System.out.println("title="+((TagNode)ns[0]).getText());
}
ns = node.evaluateXPath("//*[@class='Frame-Row3-01-C']/table[2]/tbody/tr/td/a"); //选取class为指定blkContainerSblkCon的div下面的所有p
for (int i = 0; i < ns.length; i++) {
//取链接文本
// String in = cleaner.getInnerHtml((TagNode)ns[i]);
// System.out.println(in);
//获取链接的
TagNode n = (TagNode) ns[i];
// System.out.println(n.getAttributeByName("href"));
System.out.println(new URL(_url,n.getAttributeByName("href")).toString());
}
// String in = cleaner.getInnerHtml((TagNode)ns[0]);
// System.out.println(in);
// System.out.println(((TagNode)ns[0]).getText());
// System.out.println("ul/li:");
// //按xpath取
// ns = node.evaluateXPath("//div[@class='d_1']//li");
// for(Object on : ns) {
// TagNode n = (TagNode) on;
// System.out.println("\ttext="+n.getText());
// }
// System.out.println("a:");
// //按属性值取
// ns = node.getElementsByAttValue("name", "my_href", true, true);
// for(Object on : ns) {
// TagNode n = (TagNode) on;
// System.out.println("\thref="+n.getAttributeByName("href")+", text="+n.getText());
// }
XPath文档:http://www.w3school.com.cn/xpath/xpath_syntax.asp
分享到:
相关推荐
1. **读取源代码**:使用JavaParser的`JavaSourceParser`解析源代码文件,生成对应的AST。 2. **遍历AST**:遍历AST,寻找`MethodCallExpr`节点,这些节点代表了方法调用。每遇到一个`MethodCallExpr`,提取出被...
《视频编辑MP4 Parser代码与jar包》 MP4 Parser是一种强大的工具,专门用于处理和解析MP4格式的视频文件。MP4(MPEG-4 Part 14)是广泛应用于互联网上的多媒体容器格式,它能包含视频、音频、字幕、图像等多种媒体...
【C++与MFC源代码parser_demo解析】 C++是一种通用的编程语言,以其灵活性、高效性和面向对象的特性而闻名。MFC(Microsoft Foundation Classes)是微软为Windows平台开发的应用程序提供的一套C++库,它封装了...
【标题】"C++、MFC源代码parser_src"是一个关于使用C++编程语言和Microsoft Foundation Class (MFC)库开发解析器的源代码集合。这个项目可能涉及到编译原理和程序设计,其中parser_src可能是指解析器的源代码部分。 ...
- 搜索和替换HTML代码中的特定字符串。 - 自动化网页测试,模拟用户交互。 在Delphi中使用自定义或第三方HTML解析器时,需要注意兼容性问题,因为不同的HTML语法和浏览器实现可能存在差异。此外,处理异常和错误也...
5. **错误容忍**:HTML-Parser具有良好的错误恢复能力,可以处理不规范的HTML代码。 在实际应用中,`HTML-Parser`常与`LWP::UserAgent`(用于HTTP请求)和`URI`(处理URL)等模块结合,实现网页抓取和自动化数据...
Python中的`html5-parser`库是一个高效的HTML5解析器,它使用C语言编写,从而提供了比纯Python解析更快的速度。这个库是为了解决在处理大量HTML数据时,需要快速、准确地解析文档的需求。在Python开发中,尤其是在...
1. **标签识别**:解析器首先需要能够识别HTML文档中的开始标签和结束标签,如`<div>`和`</div>`,并且区分大小写。 2. **属性解析**:对于每个标签,解析器需要解析其属性,例如`class="container"`,并将其存储为...
对html进行转换,适用爬虫/小程序富文本显示等;对html进行转换,适用爬虫/小程序富文本显示等对html进行转换,适用爬虫/小程序富文本显示等对html进行转换,适用爬虫/小程序富文本显示等
1. **灵活性**:`html-react-parser`允许开发者在解析过程中自定义处理规则,比如通过提供处理器函数来改变特定标签的行为,或者过滤某些不需要的HTML元素。 2. **安全性**:对于传入的HTML字符串,该库会进行适当...
1. **代码分析**:检查代码质量,找出潜在的 bug,比如未使用的变量、空指针异常等。 2. **代码格式化**:自动格式化代码,使其符合特定的编码规范。 3. **代码重构**:自动进行大规模的代码重构,如重命名变量、...
enju parser enju parser
XMLParser是一种用于解析XML文档的C++实现,它旨在提供简单、小巧且稳定的解决方案,以处理XML数据。...通过阅读TinyXMLParserSampleCode.pdf提供的示例代码,开发者可以快速掌握如何在实际项目中集成和使用XMLParser。
3. **错误处理与容错机制**: HTML DOM Parser通常包含良好的错误处理机制,能够处理不完整的HTML代码或非标准语法。这使得在处理来自用户输入或网络抓取的不完美HTML时,库能保持稳定,避免程序崩溃。 4. **API接口...
《gumbo-parser-0.10.1:HTML解析器详解及封装应用》 在Web开发领域,HTML解析器是不可或缺的一部分,它负责将HTML源代码转换为结构化的DOM(Document Object Model)树,便于程序处理和操作。gumbo-parser-0.10.1...
而"php-simple-html-dom-parser"是一个PHP库,专门用于处理和解析HTML文档,它提供了类似jQuery的API,使得操作HTML文档变得简单直观。这个包的Laravel版本则将这个强大的解析器集成到Laravel框架中,让开发者可以更...
html-dom-parser 在服务器(Node.js)和客户端(浏览器)上均可使用HTML到DOM解析器: HTMLDOMParser(string[, options])解析器将HTML字符串转换为描述DOM树JavaScript对象。例子const parse = require ( '...
1. **License.txt**:这个文件通常包含软件的授权协议信息,它规定了用户可以如何使用、修改和分发该库。了解这些信息对于遵循开源社区的规则至关重要,避免在商业项目中引发法律问题。 2. **Readme.txt**:这是一...
VS2013下配置Parser Generator1 Parser Generator是一款功能强大的解析器生成工具,能够帮助开发者快速生成解析器代码。在VS2013环境下配置Parser Generator1需要进行一些设置和配置,本文将详细介绍配置过程。 ...
1. **错误恢复机制**:jericho HTML Parser具备强大的错误恢复能力,能够处理不完整的标签、缺少的结束标签等常见HTML语法错误。 2. **文档模型**:它提供了一个丰富的文档模型,包括Element、Attribute、Text等类...