`
tuoxie007
  • 浏览: 160215 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

http parser 基本用法

    博客分类:
  • Java
阅读更多

手动解析HTML是一件很崩溃的事情,sun的swing里也有解析HTML的东东,不过已经是古董了,实在不好拿出来丢Java的人了。

今天要用的是Apache的一个开源项目,html parser。

它的强大不用多说,且看它提供的几个sample吧。

首先去htmlparser.sourceforge.net上去下载,在解压开之后目录里有几个目录,分别存放着src,jars,javadoc之类的,其中bin里有好几个xxx.cmd,用命令行运行那几个脚本,参数就加某个网页的地址就行了。

主意不要拿javaeye的网页做测试哦,不行的,因为sample里的HTTP客户端是用的sun的URLConnection,请求javaeye的话响应的内容是一个空文档,这只是URLConnection的众多bug之一,建议大家不要用哦,如果你只是测试的话那到无所谓咯。

其中stringextractor.cmd是解析出网页内的纯文本内容的,linkextractor.cmd是解析网页里的连接的,非常有用哦。

 

接下来就要开始编程了,如何使用这个好工具捏?貌似官方并米有详细的文档说明,就这几个sample就已经大致说清楚如何用了。我们找到这几个cmd文件,打开找到其中调用的是那个类,因为它的sample并没有单独拿出来,得要我们自己去它的source里去找。我的建议是在Eclipse的工程里添加那个jar文件,然后把jar文件设置src,这样代码看起来爽一些啦。

小研究一下那几个sample是如何实现的,然后想想你自己的需求,借题发挥吧,这是java程序员的强项了。

上面提到了那几个脚本的参数是网页地址,它的代码里也是在构建Parser对象的时候用的也是url字符串作为参数的,其实如果你想用URLConnection之外的其他Http客户端组件来代替html parser的内置请求方式,也不用担心,因为Parser对象同样提供了html内容作为参数的构建方式:Parser p = Parser.createParser(String html, String charser);

 

下面是我在项目中用的两个小method,模仿了sample里的代码

/**
* 用来抽取html里的连接地址,并转换了相对地址为绝对地址
*/

private void extractLinks(URL pageURL, Parser parser) {
		Map<String, String> links = new HashMap<String, String>();
		try {
			NodeFilter filter = new NodeClassFilter(LinkTag.class);
			NodeList list = parser.extractAllNodesThatMatch(filter);
			for (int i = 0; i < list.size(); i++) {
				LinkTag n = (LinkTag) list.elementAt(i);
				String link = n.getLink();
				if (!n.isHTTPLink()) {
					continue;
				}
				if (link.startsWith("http://")) {
					try {
						link = new URL(link).toString();
						links.put(HashUtil.md5(link), link);
					} catch (MalformedURLException e) {
						continue;
					}
				} else {
					try {
						link = new URL(pageURL, link).toString();
						links.put(HashUtil.md5(link), link);
					} catch (MalformedURLException e) {
						continue;
					}
				}
			}
		} catch (ParserException e) {
			// TODO 处理异常
			e.printStackTrace();
		} catch (RuntimeException e) {
			// TODO 处理异常
			e.printStackTrace();
		}
		doc.setDocs(createDoc(links));
	}
 
/**
* 抽取html里的文本内容,里面使用了一个自定义的节点访问器,TextExtractVisitor,下面一段有定义
*/


private Map<String, Object> extractText(Parser parser) {
		try {
			TextExtractVistor textExtractor = new TextExtractVistor();
			parser.visitAllNodesWith(textExtractor);
			doc.getText().setText(textExtractor.getText());
			doc.getText().setDigest(textExtractor.getDigest());
			doc.getText().setKeywords(textExtractor.getKeywords());
			doc.getText().setTitle(textExtractor.getTitle());
			return textExtractor.getHashedTextTags();
		} catch (ParserException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
 
/**
* 用来抽取html里文本等相关内容的节点访问器
*/


public class TextExtractVistor extends NodeVisitor {

	StringBuilder textBuf = new StringBuilder(4096);
	private boolean mIsScript;
	private boolean mIsStyle;
	private boolean mIsPre;
	protected int mCollapseState;
	private final String NEWLINE = System.getProperty("line.separator");
	private final int NEWLINE_SIZE = NEWLINE.length();
	private boolean mIsMeta;
	private boolean mIsH;
	private boolean isStrong;
	private StringBuilder digest = new StringBuilder(512);
	private StringBuilder keywords = new StringBuilder(100);
	private boolean isTtitle;
	private String title;
	private Map<String, Object> textTags = new HashMap<String, Object>();

	protected void carriageReturn() {
		int length;

		length = textBuf.length();
		if ((0 != length)
				&& ((NEWLINE_SIZE <= length) && (!textBuf.substring(
						length - NEWLINE_SIZE, length).equals(NEWLINE))))
			textBuf.append(NEWLINE);
		mCollapseState = 0;
	}

	public void visitStringNode(Text string) {
		if (!mIsScript && !mIsStyle) {
			String text = string.getText();
			textTags.put(HashUtil.md5(text), null);
			if (!mIsPre) {
				text = Translate.decode(text);
				text = text.replace('\u00a0', ' ');
				collapse(textBuf, text);
			} else {
				textBuf.append(text);
				
				if(mIsMeta){
					keywords.append(text);
				}else if(mIsH || isStrong){
					digest.append(text);
				}else if(isTtitle){
					title = text;
				}
			}
		}
	}


	public void visitTag(Tag tag) {
		String name = tag.getTagName();
		if (name.equalsIgnoreCase("PRE"))
			mIsPre = true;
		else if (name.equalsIgnoreCase("SCRIPT"))
			mIsScript = true;
		else if (name.equalsIgnoreCase("STYLE"))
			mIsStyle = true;
		else if (name.equalsIgnoreCase("META"))
			mIsMeta = true;
		else if (name.startsWith("[H|h]"))
			mIsH = true;
		else if (name.equalsIgnoreCase("STRONG"))
			isStrong = true;
		else if (name.equalsIgnoreCase("TITLE"))
			isTtitle = true;
		if (tag.breaksFlow())
			carriageReturn();
	}

	public void visitEndTag(Tag tag) {
		String name;

		name = tag.getTagName();
		if (name.equalsIgnoreCase("PRE"))
			mIsPre = false;
		else if (name.equalsIgnoreCase("SCRIPT"))
			mIsScript = false;
		else if (name.equalsIgnoreCase("STYLE"))
			mIsStyle = false;
		else if (name.equalsIgnoreCase("META"))
			mIsMeta = false;
		else if (name.startsWith("[H|h]"))
			mIsH = false;
		else if (name.equalsIgnoreCase("STRONG"))
			isStrong = false;
		else if (name.equalsIgnoreCase("TITLE"))
			isTtitle = false;
	}

	public String getText() {
		return textBuf.toString();
	}
	
	public String getDigest(){
		return digest.toString();
	}
	
	public String getKeywords(){
		return keywords.toString();
	}
	
	public String getTitle(){
		return title;
	}
	
	public Map<String, Object> getHashedTextTags(){
		return textTags;
	}
	
	protected void collapse(StringBuilder buffer, String string) {
		int chars;
		char character;

		chars = string.length();
		if (0 != chars) {
			for (int i = 0; i < chars; i++) {
				character = string.charAt(i);
				switch (character) {
				// see HTML specification section 9.1 White space
				// http://www.w3.org/TR/html4/struct/text.html#h-9.1
				case '\u0020':
				case '\u0009':
				case '\u000C':
				case '\u200B':
				case '\r':
				case '\n':
					if (0 != mCollapseState)
						mCollapseState = 1;
					break;
				default:
					if (1 == mCollapseState)
						buffer.append(' ');
					mCollapseState = 2;
					buffer.append(character);
				}
			}
		}
	}
}
 
分享到:
评论
2 楼 tuoxie007 2009-05-02  
Hooopo 写道

额 java搞个html parse 也弄那么麻烦...还是ruby好..

我正准备改行搞ruby捏
1 楼 Hooopo 2009-05-02  
额 java搞个html parse 也弄那么麻烦...还是ruby好..

相关推荐

Global site tag (gtag.js) - Google Analytics