<?xml version="1.0" encoding="gb2312"?>

<!-- RSS generated by oioj.net on 4/16/2004 ; 感谢LeXRus提供 RSS 2.0 文档; 此文件可自由使用，但请保留此行信息 --> 
<!-- Source download URL: http://blogger.org.cn/blog/rss2.asp       -->
<rss version="2.0">

<channel>
<title>dongdong的照相机</title>
<link>http://blogger.org.cn/blog/blog.asp?name=Spirit_Dongdong</link>
<description>dongdong的博客</description>
<copyright>blogger.org.cn</copyright>
<generator>W3CHINA Blog</generator>
<webMaster>webmaster@blogger.org.cn</webMaster>
<item>
<title><![CDATA[【转载】JAVA与模式 摘录]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=Spirit_Dongdong&amp;id=47609</link>
<author>Spirit_Dongdong</author>
<pubDate>2009/11/27 22:44:14</pubDate>
<description><![CDATA[QWAN(无名的质)、Gate（门）、Way（道）<BR>利用道从门演化成质，就是采用一定的模式利用一种语言达到软件的完美。<BR><BR>无名天地之始，有名万物之母。<BR>名是死的混沌。<BR><BR>道生一，一生二，二生三，三生万物。万物负阴而抱阳，冲气以为和。<BR>气聚而有其形，气散而归于无形。<BR><BR>《老子》：善为士者不武。－－好的设计师不会在他设计的系统中再做<WBR>大规模的修改。<BR>《老子》：天下有道，却走马以粪；天下无道，戎马生于效。<BR><BR>开闭原则：对扩展开放，对修改关闭。－－抽象化是关键<WBR>，对可变性进行封装。<BR>《太玄》：知固而不知革，物失其则；知革而不知固，物失其均。<BR>所有类图的继承结构都不会超过两层，否则就会失去对于可变性的封装<WBR>原则，就会在一个封装内含有多个可变元素。<BR><BR>里式代换原则：任何基类可以出现的地方，子类一定可以出现。 <BR>依赖倒转原则：要依赖与抽象，不要依赖与实现。<BR>合成/聚合复用原则：要尽量使用合成和聚合，少使用继承。<BR>迪米特法则：一个软件实体应该尽可能少的与其他实体发生相互作用。<BR>接口隔离原则：应当为client提供尽可能小的单独的接口<WBR>，而不是提供大的总的接口。<BR><BR>可插拔性的关键在于存在一个接口，以及每个构件都实现了这个接口。<BR><BR>应当优先使用接口实现抽象类型。<BR><BR>抽象类是用来继承的，具体类不是用来继承的。 <BR>抽象类应该具有尽可能多的共同代码，应当具有尽可能少的数据。<BR><BR>类之间的继承是很容易被滥用的复用工具。<BR>防止继承滥用的原则：<BR>
<OL>
<LI>区分has-a和is-a的区别 
<LI>子类有扩展超类的责任，而不是替换掉 
<LI>不要从工具类继承</LI></OL></WBR></WBR></WBR></WBR>]]></description>
</item><item>
<title><![CDATA[【转载】HTMLParser的初步整理]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=Spirit_Dongdong&amp;id=47608</link>
<author>Spirit_Dongdong</author>
<pubDate>2009/11/27 17:37:05</pubDate>
<description><![CDATA[
<P>书上没有详细介绍HTMLParser细致的使用，所以需要看<A href="http://htmlparser.sourceforge.net/javadoc/index.html" target=_blank><FONT color=#4690ff>文档</FONT></A>来来进一步了解HTMLParser。</P>
<P>我首先整理一些方法，以便查找。</P>
<P>Interface Node：</P>
<TABLE cellSpacing=0 cellPadding=2 width=554 border=1>
<TBODY>
<TR>
<TD vAlign=top width=155>getChildren()</TD>
<TD vAlign=top width=68>NodeList</TD>
<TD vAlign=top width=329>get the children of this node</TD></TR>
<TR>
<TD vAlign=top width=160>getStartPosition()</TD>
<TD vAlign=top width=73>int</TD>
<TD vAlign=top width=329>get the starting position of the node.</TD></TR>
<TR>
<TD vAlign=top width=164>getEndPosition()</TD>
<TD vAlign=top width=77>int</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=167>getFirstChild()</TD>
<TD vAlign=top width=80>Node</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=169>getLastChild()</TD>
<TD vAlign=top width=82>Node</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=171>getParent()</TD>
<TD vAlign=top width=84>Node</TD>
<TD vAlign=top width=329><FONT color=#808080>this will always return null when parsing with the Lexer.</FONT></TD></TR>
<TR>
<TD vAlign=top width=172>getNextSibling()</TD>
<TD vAlign=top width=85>Node</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=173>getPreviousSibling()</TD>
<TD vAlign=top width=86>Node</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=173>getPage()</TD>
<TD vAlign=top width=86>page</TD>
<TD vAlign=top width=329>get the page this node came from. <BR>return the page that supplied this node.</TD></TR>
<TR>
<TD vAlign=top width=173>getText()</TD>
<TD vAlign=top width=86>String</TD>
<TD vAlign=top width=329>return the text of the node.</TD></TR>
<TR>
<TD vAlign=top width=173>toHtml()</TD>
<TD vAlign=top width=86>String</TD>
<TD vAlign=top width=329>return the HTML for this node.</TD></TR>
<TR>
<TD vAlign=top width=173>toHtml(boolean)</TD>
<TD vAlign=top width=86>String</TD>
<TD vAlign=top width=329>return the HTML for this node.</TD></TR>
<TR>
<TD vAlign=top width=173>toPlainTextString()*</TD>
<TD vAlign=top width=86>String</TD>
<TD vAlign=top width=329>a string representation of the node.</TD></TR>
<TR>
<TD vAlign=top width=173>toString()</TD>
<TD vAlign=top width=86>String</TD>
<TD vAlign=top width=329>return the string representation of the node.</TD></TR>
<TR>
<TD vAlign=top width=173>collectInto(NodeList,NodeFilter)*</TD>
<TD vAlign=top width=86>void</TD>
<TD vAlign=top width=329>collect this node and its child nodes into a list,provided the node satisfies the filtering criteria.</TD></TR>
<TR>
<TD vAlign=top width=173>accept(NodeVisitor)</TD>
<TD vAlign=top width=86>void</TD>
<TD vAlign=top width=329>apply the visitor to this node.</TD></TR>
<TR>
<TD vAlign=top width=173>setchildren(NodeList)</TD>
<TD vAlign=top width=86>void</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=173>setStartPosition(int)</TD>
<TD vAlign=top width=86>void</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=173>setEndPosition(int)</TD>
<TD vAlign=top width=86>void</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=173>setPage(Page)</TD>
<TD vAlign=top width=86>void</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=173>setParent(Node)</TD>
<TD vAlign=top width=86>void</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=173>setStartPosition(int)</TD>
<TD vAlign=top width=86>void</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=173>setText(String)</TD>
<TD vAlign=top width=86>void</TD>
<TD vAlign=top width=329>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=173>clone()</TD>
<TD vAlign=top width=86>Object</TD>
<TD vAlign=top width=329>allow cloning of nodes</TD></TR></TBODY></TABLE>
<P>*:</P>
<P>toPlainTextString():</P>
<P>&nbsp;&nbsp;&nbsp; A string representation of the node. This is an imp<WBR>ortant method, it allows a simple string transformation of a web page, regardless of a node. For a Text node this is obviously the textual contents itself. For a Remark node this is the remark contents (sic). For tags this is the text contents of it's children (if any). Because multiple nodes are combined when presenting a page in a browser, this will not reflect what a user would see.</P>
<P>简单来说，就是返回节点内所有文本。</P><PRE>System.out.println (node.toPlainTextString ());</PRE><PRE>&nbsp;</PRE><PRE>collectInto(NodeList,NodeFilter):</PRE><PRE>  将满足NodeFilter的所有node存到NodeList中。</PRE><PRE>&nbsp;</PRE><PRE>疑问：一系列的set的方法，有什么使用意义？accept和clone怎么使用？</PRE>
<P> </P>
<P>Package org.htmlparser.filters </P>
<TABLE cellSpacing=0 cellPadding=2 width=554 border=1>
<TBODY>
<TR>
<TD vAlign=top width=167>AndFilter</TD>
<TD vAlign=top width=385>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=167>CssSelectorNodeFilter</TD>
<TD vAlign=top width=385>接受所有支持CSS2选择器的节点。</TD></TR>
<TR>
<TD vAlign=top width=167>HasAttributeFilter</TD>
<TD vAlign=top width=385>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=167>HasChildFilter</TD>
<TD vAlign=top width=385>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=167>HasParentFilter</TD>
<TD vAlign=top width=385>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=167>HasSiblingFilter</TD>
<TD vAlign=top width=385>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=167>IsEqualFilter</TD>
<TD vAlign=top width=385>This class accepts on<WBR>ly on<WBR>e specific node.</TD></TR>
<TR>
<TD vAlign=top width=167>LinkRegexFilter</TD>
<TD vAlign=top width=385>接受所有linkTag标签的link值，匹配给定的正则表达式的节点。</TD></TR>
<TR>
<TD vAlign=top width=167>LinkStringFilter</TD>
<TD vAlign=top width=385>接受所有linkTag标签的link值，匹配给定的字符串的节点。</TD></TR>
<TR>
<TD vAlign=top width=167>NodeClassFilter</TD>
<TD vAlign=top width=385>接受所有接受指定的类的节点。</TD></TR>
<TR>
<TD vAlign=top width=167>NotFilter</TD>
<TD vAlign=top width=385>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=167>OrFilter</TD>
<TD vAlign=top width=385>&nbsp;</TD></TR>
<TR>
<TD vAlign=top width=167>RegexFilter</TD>
<TD vAlign=top width=385>接受所有满足指定正则表达式的String Nodes。</TD></TR>
<TR>
<TD vAlign=top width=167>StringFilter</TD>
<TD vAlign=top width=385>接受所有满足指定String的String Nodes。</TD></TR>
<TR>
<TD vAlign=top width=167>TagNameFilter</TD>
<TD vAlign=top width=385>&nbsp;</TD></TR></TBODY></TABLE>]]></description>
</item><item>
<title><![CDATA[【转载】使用 HttpClient 和 HtmlParser 实现简易爬虫]]></title>
<link>http://blogger.org.cn/blog/more.asp?name=Spirit_Dongdong&amp;id=47585</link>
<author>Spirit_Dongdong</author>
<pubDate>2009/11/26 0:06:20</pubDate>
<description><![CDATA[<A></A>
<P>转载自<A href="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/index.html">http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/index.html</A></P>
<P><A name="1.使用 HttpClient 和 HtmlParser 实现简易爬虫"><SPAN class=atitle>使用 HttpClient 和 HtmlParser 实现简易爬虫</SPAN></A></P>
<P>这篇文章介绍了 HtmlParser 开源包和 HttpClient 开源包的使用，在此基础上实现了一个简易的网络爬虫 (Crawler)，来说明如何使用 HtmlParser 根据需要处理 Internet 上的网页，以及如何使用 HttpClient 来简化 Get 和 Post 请求操作，构建强大的网络应用程序。</P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><BR><IMG height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox href="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/index.html#main" cmImpressionSent="1"><B><FONT color=#5c81a7>回页首</FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name="2.HttpClient 与 HtmlParser 简介"><SPAN class=atitle>HttpClient 与 HtmlParser 简介</SPAN></A></P>
<P>本小结简单的介绍一下 HttpClinet 和 HtmlParser 两个开源的项目，以及他们的网站和提供下载的地址。</P>
<P><A name=N1005C><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>HttpClient 简介</FONT></STRONG></SPAN></A></P>
<P>HTTP 协议是现在的因特网最重要的协议之一。除了 WEB 浏览器之外， WEB 服务，基于网络的应用程序以及日益增长的网络计算不断扩展着 HTTP 协议的角色，使得越来越多的应用程序需要 HTTP 协议的支持。虽然 JAVA 类库 .net 包提供了基本功能，来使用 HTTP 协议访问网络资源，但是其灵活性和功能远不能满足很多应用程序的需要。而 Jakarta Commons HttpClient 组件寻求提供更为灵活，更加高效的 HTTP 协议支持，简化基于 HTTP 协议的应用程序的创建。 HttpClient 提供了很多的特性，支持最新的 HTTP 标准，可以访问<A href="http://hc.apache.org/httpclient-3.x/" cmImpressionSent="1"><FONT color=#5c81a7>这里</FONT></A>了解更多关于 HttpClinet 的详细信息。目前有很多的开源项目都用到了 HttpClient 提供的 HTTP功能，登陆<A href="http://wiki.apache.org/jakarta-httpclient/HttpClientPowered" cmImpressionSent="1"><FONT color=#5c81a7>网址</FONT></A>可以查看这些项目。本文中使用 HttpClinet 提供的类库来访问和下载 Internet上面的网页，在后续部分会详细介绍到其提供的两种请求网络资源的方法： Get 请求和 Post 请求。Apatche 提供免费的 HTTPClien t源码和 JAR 包下载，可以登陆<A href="http://hc.apache.org/downloads.cgi" cmImpressionSent="1"><FONT color=#5c81a7>这里</FONT></A> 下载最新的HttpClient 组件。笔者使用的是 HttpClient3.1。</P>
<P><A name=N10071><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>HtmlParser 简介</FONT></STRONG></SPAN></A></P>
<P>当今的 Internet 上面有数亿记的网页，越来越多应用程序将这些网页作为分析和处理的数据对象。这些网页多为半结构化的文本，有着大量的标签和嵌套的结构。当我们自己开发一些处理网页的应用程序时，会想到要开发一个单独的网页解析器，这一部分的工作必定需要付出相当的精力和时间。事实上，做为 JAVA 应用程序开发者， HtmlParser 为其提供了强大而灵活易用的开源类库，大大节省了写一个网页解析器的开销。 HtmlParser 是 <A href="http://sourceforge.net/" cmImpressionSent="1"><FONT color=#5c81a7>http://sourceforge.net</FONT></A> 上活跃的一个开源项目，它提供了线性和嵌套两种方式来解析网页，主要用于 html 网页的转换(Transformation) 以及网页内容的抽取 (Extraction)。HtmlParser 有如下一些易于使用的特性：过滤器 (Filters)，访问者模式 (Visitors)，处理自定义标签以及易于使用的 JavaBeans。正如 HtmlParser 首页所说：它是一个快速，健壮以及严格测试过的组件；以它设计的简洁，程序运行的速度以及处理 Internet 上真实网页的能力吸引着越来越多的开发者。 本文中就是利用HtmlParser 里提取网页里的链接，实现简易爬虫里的关键部分。HtmlParser 最新的版本是HtmlParser1.6，可以登陆<A href="http://sourceforge.net/project/showfiles.php?group_id=24399" cmImpressionSent="1"><FONT color=#5c81a7>这里</FONT></A>下载其源码、 API 参考文档以及 JAR 包。</P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><BR><IMG height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox href="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/index.html#main" cmImpressionSent="1"><B><FONT color=#5c81a7>回页首</FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=3.开发环境的搭建><SPAN class=atitle>开发环境的搭建</SPAN></A></P>
<P>笔者所使用的开发环境是 Eclipse Europa，此开发工具可以在 <A href="http://www.eclipse.org/" cmImpressionSent="1"><FONT color=#5c81a7>www.eclipse.org</FONT></A> 免费的下载；JDK是1.6，你也可以在 <A href="http://www.java.sun.com/" cmImpressionSent="1"><FONT color=#5c81a7>www.java.sun.com</FONT></A> 站点下载，并且在操作系统中配置好环境变量。在 Eclipse 中创建一个 JAVA 工程，在工程的 Build Path 中导入下载的Commons-httpClient3.1.Jar，htmllexer.jar 以及 htmlparser.jar 文件。</P><BR><A name=N10094><B>图 1. 开发环境搭建</B></A><BR><IMG height=459 alt=" 开发环境搭建" src="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/images/image001.jpg" width=572> <BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><BR><IMG height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox href="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/index.html#main" cmImpressionSent="1"><B><FONT color=#5c81a7>回页首</FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name="4.HttpClient 基本类库使用"><SPAN class=atitle>HttpClient 基本类库使用</SPAN></A></P>
<P>HttpClinet 提供了几个类来支持 HTTP 访问。下面我们通过一些示例代码来熟悉和说明这些类的功能和使用。 HttpClient 提供的 HTTP 的访问主要是通过 GetMethod 类和 PostMethod 类来实现的，他们分别对应了 HTTP Get 请求与 Http Post 请求。</P>
<P><A name=N100AA><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>GetMethod</FONT></STRONG></SPAN></A></P>
<P>使用 GetMethod 来访问一个 URL 对应的网页，需要如下一些步骤。</P>
<OL type=1>
<LI>生成一个 HttpClinet 对象并设置相应的参数。 
<LI>生成一个 GetMethod 对象并设置响应的参数。 
<LI>用 HttpClinet 生成的对象来执行 GetMethod 生成的 Get 方法。 
<LI>处理响应状态码。 
<LI>若响应正常，处理 HTTP 响应内容。 
<LI>释放连接。 </LI></OL>
<P>清单 1 的代码展示了这些步骤，其中的注释对代码进行了较详细的说明。</P><BR><A name=N100CD><B>清单 1.</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>/* 1 生成 HttpClinet 对象并设置参数*/
  HttpClient httpClient=new HttpClient();
  //设置 Http 连接超时为5秒
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
  
  /*2 生成 GetMethod 对象并设置参数*/
  GetMethod getMethod=new GetMethod(url);	 
  //设置 get 请求超时为 5 秒
getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT,5000);
  //设置请求重试处理，用的是默认的重试处理：请求三次
getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
          new DefaultHttpMethodRetryHandler());
  
  /*3 执行 HTTP GET 请求*/
  try{ 
	  int statusCode = httpClient.executeMethod(getMethod);
	  /*4 判断访问的状态码*/
      if (statusCode != HttpStatus.SC_OK) 
      {
System.err.println("Method failed: "+ getMethod.getStatusLine());
      }
  
      /*5 处理 HTTP 响应内容*/
      //HTTP响应头部信息，这里简单打印
  Header[] headers=getMethod.getResponseHeaders();
      for(Header  h:  headers)
  	      System.out.println(h.getName()+" "+h.getValue());*/
      //读取 HTTP 响应内容，这里简单打印网页内容
      byte[] responseBody = getMethod.getResponseBody();//读取为字节数组
System.out.println(new String(responseBody));
      //读取为 InputStream，在网页内容数据量大时候推荐使用
      InputStream response = getMethod.getResponseBodyAsStream();//
      …
}
catch (HttpException e) 
{
	  // 发生致命的异常，可能是协议不对或者返回的内容有问题
		  System.out.println("Please check your provided http address!");
e.printStackTrace();
	 } 
catch (IOException e)
  {
	        // 发生网络异常
		e.printStackTrace();
	 } finally {
		         /*6 .释放连接*/
			getMethod.releaseConnection();		   
		    }
</PRE></TD></TR></TBODY></TABLE><BR>
<P>这里值得注意的几个地方是：</P>
<OL type=1>
<LI>设置连接超时和请求超时，这两个超时的意义不同，需要分别设置。 
<LI>响应状态码的处理。 
<LI>返回的结果可以为字节数组，也可以为 InputStream，而后者在网页内容数据量较大的时候推荐使用。 </LI></OL>
<P>在处理返回结果的时候可以根据自己的需要，进行相应的处理。如笔者是需要保存网页</P>
<P>到本地，因此就可以写一个 saveToLocaleFile(byte[] data, String filePath) 的方法，将字节数组保存成本地文件。后续的简易爬虫部分会有相应的介绍。</P>
<P><A name=N100E9><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>PostMethod</FONT></STRONG></SPAN></A></P>
<P>PostMethod 方法与 GetMethod 方法的使用步骤大体相同。但是由于 PostMethod 使用的是HTTP 的 Post 请求，因而请求参数的设置与 GetMethod 有所不同。在 GetMethod 中，请求的参数直接写在 URL 里，一般以这样形式出现：http://hostname:port//file?name1=value1&amp;name2=value …。请求参数是 name，value 对。比如我想得到百度搜索“Thinking In Java”的结果网页，就可以使 GetMethod 的构造方法中的 url 为：http://www.baidu.com/s?wd=Thinking+In+Java 。而 PostMethod 则可以模拟网页里表单提交的过程，通过设置表单里 post 请求参数的值，来动态的获得返回的网页结果。清单 2 中的代码展示了如何创建一个 Post 对象，并设置相应的请求参数。</P><BR><A name=N100F4><B>清单2</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>PostMethod postMethod = new PostMethod("http://dict.cn/");
postMethod.setRequestBody(new NameValuePair[]{new NameValuePair("q","java")});
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><BR><IMG height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox href="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/index.html#main" cmImpressionSent="1"><B><FONT color=#5c81a7>回页首</FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name="5.HtmlParser 基本类库使用"><SPAN class=atitle>HtmlParser 基本类库使用</SPAN></A></P>
<P>HtmlParser 提供了强大的类库来处理 Internet 上的网页，可以实现对网页特定内容的提取和修改。下面通过几个例子来介绍 HtmlParser 的一些使用。这些例子其中的代码，有部分用在了后面介绍的简易爬虫中。以下所有的代码和方法都在在类 HtmlParser.Test.java 里，这是笔者编写的一个用来测试 HtmlParser 用法的类。</P>
<UL>
<LI>迭代遍历网页所有节点 </LI></UL>
<P>网页是一个半结构化的嵌套文本文件，有类似 XML 文件的树形嵌套结构。使用HtmlParser 可以让我们轻易的迭代遍历网页的所有节点。清单 3 展示了如何来实现这个功能。</P><BR><A name=N1010E><B>清单 3</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>// 循环访问所有节点，输出包含关键字的值节点
	public static void extractKeyWordText(String url, String keyword) {
		try {
            //生成一个解析器对象，用网页的 url 作为参数
			Parser parser = new Parser(url);
			//设置网页的编码,这里只是请求了一个 gb2312 编码网页
			parser.setEncoding("gb2312");
			//迭代所有节点, null 表示不使用 NodeFilter
			NodeList list = parser.parse(null);
            //从初始的节点列表跌倒所有的节点
			processNodeList(list, keyword);
		} catch (ParserException e) {
			e.printStackTrace();
		}
	}

	private static void processNodeList(NodeList list, String keyword) {
		//迭代开始
		SimpleNodeIterator iterator = list.elements();
		while (iterator.hasMoreNodes()) {
			Node node = iterator.nextNode();
			//得到该节点的子节点列表
			NodeList childList = node.getChildren();
			//孩子节点为空，说明是值节点
			if (null == childList)
			{
				//得到值节点的值
				String result = node.toPlainTextString();
				//若包含关键字，则简单打印出来文本
				if (result.indexOf(keyword) != -1)
					System.out.println(result);
			} //end if
			//孩子节点不为空，继续迭代该孩子节点
			else 
			{
				processNodeList(childList, keyword);
			}//end else
		}//end wile
	}
</PRE></TD></TR></TBODY></TABLE><BR>
<P>上面的中有两个方法：</P>
<OL type=1>
<LI>private static void processNodeList(NodeList list, String keyword) </LI></OL>
<P>该方法是用类似深度优先的方法来迭代遍历整个网页节点，将那些包含了某个关键字的值节点的值打印出来。</P>
<OL type=1>
<LI>public static void extractKeyWordText(String url, String keyword) </LI></OL>
<P>该方法生成针对 String 类型的 url 变量代表的某个特定网页的解析器，调用 1中的方法实现简单的遍历。</P>
<P>清单 3 的代码展示了如何迭代所有的网页，更多的工作可以在此基础上展开。比如找到某个特定的网页内部节点，其实就可以在遍历所有的节点基础上来判断，看被迭代的节点是否满足特定的需要。</P>
<UL>
<LI>使用 NodeFilter </LI></UL>
<P>NodeFilter 是一个接口，任何一个自定义的 Filter 都需要实现这个接口中的 boolean accept() 方法。如果希望迭代网页节点的时候保留当前节点，则在节点条件满足的情况下返回 true；否则返回 false。HtmlParse 里提供了很多实现了 NodeFilter 接口的类，下面就一些笔者所用到的，以及常用的 Filter 做一些介绍：</P>
<OL type=1>
<LI>对 Filter 做逻辑操作的 Fitler 有：<A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5CAndFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>AndFilter</FONT></A>，<A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5CNotFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>NotFilter</FONT></A> ，<A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5COrFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>OrFilter</FONT></A>，<A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5CXorFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>XorFilter</FONT></A>。 </LI></OL>
<P>这些 Filter 来组合不同的 Filter，形成满足两个 Filter 逻辑关系结果的 Filter。</P>
<OL type=1>
<LI>判断节点的孩子，兄弟，以及父亲节点情况的 Filter 有：<A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5CHasChildFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>HasChildFilter</FONT></A> <A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5CHasParentFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>HasParentFilter</FONT></A>，<A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5CHasSiblingFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>HasSiblingFilter</FONT></A>。 
<LI>判断节点本身情况的 Filter 有 <A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5CHasAttributeFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>HasAttributeFilter</FONT></A>：判读节点是否有特定属性；<A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5CLinkStringFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>LinkStringFilter</FONT></A>：判断节点是否是具有特定模式 (pattern) url 的节点； </LI></OL>
<P><A href="http://www.ibm.com///F:%5Ccommon_tools%5Ceclipseplugins%5Chtmlparser1_6%5Cdocs%5Cjavadoc%5Corg%5Chtmlparser%5Cfilters%5CTagNameFilter.html" cmImpressionSent="1"><FONT color=#5c81a7>TagNameFilter</FONT></A>：判断节点是否具有特定的名字；NodeClassFilter：判读节点是否是某个 HtmlParser 定义好的 Tag 类型。在 org.htmlparser.tags 包下有对应 Html标签的各种 Tag，例如 LinkTag，ImgeTag 等。</P>
<P>还有其他的一些 Filter 在这里不一一列举了，可以在 org.htmlparser.filters 下找到。</P>
<P>清单 4 展示了如何使用上面提到过的一些 filter 来抽取网页中的 &lt;a&gt; 标签里的 href属性值，&lt;img&gt; 标签里的 src 属性值，以及 &lt;frame&gt; 标签里的 src 的属性值。</P><BR><A name=N10179><B>清单4</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>// 获取一个网页上所有的链接和图片链接
	public static void extracLinks(String url) {
		try {
			Parser parser = new Parser(url);
			parser.setEncoding("gb2312");
//过滤 &lt;frame&gt; 标签的 filter，用来提取 frame 标签里的 src 属性所、表示的链接
			NodeFilter frameFilter = new NodeFilter() {
				public boolean accept(Node node) {
					if (node.getText().startsWith("frame src=")) {
						return true;
					} else {
						return false;
					}
				}
			};
//OrFilter 来设置过滤 &lt;a&gt; 标签，&lt;img&gt; 标签和 &lt;frame&gt; 标签，三个标签是 or 的关系
	 OrFilte rorFilter = new OrFilter(new NodeClassFilter(LinkTag.class), new 
NodeClassFilter(ImageTag.class));
	 OrFilter linkFilter = new OrFilter(orFilter, frameFilter);
	//得到所有经过过滤的标签
	NodeList list = parser.extractAllNodesThatMatch(linkFilter);
	for (int i = 0; i &lt; list.size(); i++) {
		Node tag = list.elementAt(i);
		if (tag instanceof LinkTag)//&lt;a&gt; 标签 
		{
			LinkTag link = (LinkTag) tag;
			String linkUrl = link.getLink();//url
			String text = link.getLinkText();//链接文字
			System.out.println(linkUrl + "**********" + text);
		}
		else if (tag instanceof ImageTag)//&lt;img&gt; 标签
		{
			ImageTag image = (ImageTag) list.elementAt(i);
			System.out.print(image.getImageURL() + "********");//图片地址
			System.out.println(image.getText());//图片文字
		}
		else//&lt;frame&gt; 标签
		{
//提取 frame 里 src 属性的链接如 &lt;frame src="test.html"/&gt;
			String frame = tag.getText();
			int start = frame.indexOf("src=");
			frame = frame.substring(start);
			int end = frame.indexOf(" ");
			if (end == -1)
				end = frame.indexOf("&gt;");
			frame = frame.substring(5, end - 1);
			System.out.println(frame);
		}
	}
} catch (ParserException e) {
			e.printStackTrace();
}
}
</PRE></TD></TR></TBODY></TABLE><BR>
<UL>
<LI>简单强大的 StringBean </LI></UL>
<P>如果你想要网页中去掉所有的标签后剩下的文本，那就是用 StringBean 吧。以下简单的代码可以帮你解决这样的问题：</P>
<P><B>清单5</B></P>
<P>StringBean sb = new StringBean();</P>
<P>sb.setLinks(false);//设置结果中去点链接</P>
<P>sb.setURL(url);//设置你所需要滤掉网页标签的页面 url</P>
<P>System.out.println(sb.getStrings());//打印结果</P>
<P>HtmlParser 提供了强大的类库来处理网页，由于本文旨在简单的介绍，因此只是将与笔者后续爬虫部分有关的关键类库进行了示例说明。感兴趣的读者可以专门来研究一下 HtmlParser 更为强大的类库。</P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><BR><IMG height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox href="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/index.html#main" cmImpressionSent="1"><B><FONT color=#5c81a7>回页首</FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=6.简易爬虫的实现><SPAN class=atitle>简易爬虫的实现</SPAN></A></P>
<P>HttpClient 提供了便利的 HTTP 协议访问，使得我们可以很容易的得到某个网页的源码并保存在本地；HtmlParser 提供了如此简便灵巧的类库，可以从网页中便捷的提取出指向其他网页的超链接。笔者结合这两个开源包，构建了一个简易的网络爬虫。</P>
<P><A name=N101A4><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>爬虫 (Crawler) 原理</FONT></STRONG></SPAN></A></P>
<P>学过数据结构的读者都知道有向图这种数据结构。如下图所示，如果将网页看成是图中的某一个节点，而将网页中指向其他网页的链接看成是这个节点指向其他节点的边，那么我们很容易将整个 Internet 上的网页建模成一个有向图。理论上，通过遍历算法遍历该图，可以访问到Internet 上的几乎所有的网页。最简单的遍历就是宽度优先以及深度优先。以下笔者实现的简易爬虫就是使用了宽度优先的爬行策略。</P><BR><A name=N101AE><B>图 2. 网页关系的建模图</B></A><BR><IMG height=308 alt=网页关系的建模图 src="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/images/image002.jpg" width=507> <BR>
<P><A name=N101BB><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>简易爬虫实现流程</FONT></STRONG></SPAN></A></P>
<P>在看简易爬虫的实现代码之前，先介绍一下简易爬虫爬取网页的流程。</P><BR><A name=N101C5><B>图 3. 爬虫流程图</B></A><BR><IMG height=373 alt=爬虫流程图 src="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/images/image003.jpg" width=374> <BR>
<P><A name=N101D2><SPAN class=smalltitle><STRONG><FONT face=Arial size=3>各个类的源码以及说明</FONT></STRONG></SPAN></A></P>
<P>对应上面的流程图，简易爬虫由下面几个类组成，各个类职责如下：</P>
<P>Crawler.java：爬虫的主方法入口所在的类，实现爬取的主要流程。</P>
<P>LinkDb.java：用来保存已经访问的 url 和待爬取的 url 的类，提供url出对入队操作。</P>
<P>Queue.java： 实现了一个简单的队列，在 LinkDb.java 中使用了此类。</P>
<P>FileDownloader.java：用来下载 url 所指向的网页。</P>
<P>HtmlParserTool.java： 用来抽取出网页中的链接。</P>
<P>LinkFilter.java：一个接口，实现其 accept() 方法用来对抽取的链接进行过滤。 </P>
<P>下面是各个类的源码，代码中的注释有比较详细的说明。</P><BR><A name=N101F2><B>清单6 Crawler.java</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>package com.ie;

import java.util.Set;
public class Crawler {
	/* 使用种子 url 初始化 URL 队列*/
	private void initCrawlerWithSeeds(String[] seeds)
	{
		for(int i=0;i&lt;seeds.length;i++)
			LinkDB.addUnvisitedUrl(seeds[i]);
	}
	
	/* 爬取方法*/
	public void crawling(String[] seeds)
	{
		LinkFilter filter = new LinkFilter(){
			//提取以 <A href="http://www.twt.edu.cn/" cmImpressionSent="1"><CODE><FONT color=#5c81a7>http://www.twt.edu.cn</FONT></CODE></A> 开头的链接
			public boolean accept(String url) {
				if(url.startsWith("http://www.twt.edu.cn"))
					return true;
				else
					return false;
			}
		};
		//初始化 URL 队列
		initCrawlerWithSeeds(seeds);
		//循环条件：待抓取的链接不空且抓取的网页不多于 1000
		while(!LinkDB.unVisitedUrlsEmpty()&amp;&amp;LinkDB.getVisitedUrlNum()&lt;=1000)
		{
			//队头 URL 出对
			String visitUrl=LinkDB.unVisitedUrlDeQueue();
			if(visitUrl==null)
				continue;
			FileDownLoader downLoader=new FileDownLoader();
			//下载网页
			downLoader.downloadFile(visitUrl);
			//该 url 放入到已访问的 URL 中
			LinkDB.addVisitedUrl(visitUrl);
			//提取出下载网页中的 URL
			
			Set&lt;String&gt; links=HtmlParserTool.extracLinks(visitUrl,filter);
			//新的未访问的 URL 入队
			for(String link:links)
			{
					LinkDB.addUnvisitedUrl(link);
			}
		}
	}
	//main 方法入口
	public static void main(String[]args)
	{
		Crawler crawler = new Crawler();
		crawler.crawling(new String[]{"http://www.twt.edu.cn"});
	}
}
</PRE></TD></TR></TBODY></TABLE><BR><BR><A name=N10201><B>清单7 LinkDb.java</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>package com.ie;

import java.util.HashSet;
import java.util.Set;

/**
 * 用来保存已经访问过 Url 和待访问的 Url 的类
 */
public class LinkDB {

	//已访问的 url 集合
	private static Set&lt;String&gt; visitedUrl = new HashSet&lt;String&gt;();
	//待访问的 url 集合
	private static Queue&lt;String&gt; unVisitedUrl = new Queue&lt;String&gt;();

	
	public static Queue&lt;String&gt; getUnVisitedUrl() {
		return unVisitedUrl;
	}

	public static void addVisitedUrl(String url) {
		visitedUrl.add(url);
	}

	public static void removeVisitedUrl(String url) {
		visitedUrl.remove(url);
	}

	public static String unVisitedUrlDeQueue() {
		return unVisitedUrl.deQueue();
	}

	// 保证每个 url 只被访问一次
	public static void addUnvisitedUrl(String url) {
		if (url != null &amp;&amp; !url.trim().equals("")
 &amp;&amp; !visitedUrl.contains(url)
				&amp;&amp; !unVisitedUrl.contians(url))
			unVisitedUrl.enQueue(url);
	}

	public static int getVisitedUrlNum() {
		return visitedUrl.size();
	}

	public static boolean unVisitedUrlsEmpty() {
		return unVisitedUrl.empty();
	}
}
</PRE></TD></TR></TBODY></TABLE><BR><BR><A name=N1020A><B>清单8 Queue.java</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>package com.ie;

import java.util.LinkedList;
/**
 * 数据结构队列
 */
public class Queue&lt;T&gt; {

	private LinkedList&lt;T&gt; queue=new LinkedList&lt;T&gt;();
	
	public void enQueue(T t)
	{
		queue.addLast(t);
	}
	
	public T deQueue()
	{
		return queue.removeFirst();
	}
	
	public boolean isQueueEmpty()
	{
		return queue.isEmpty();
	}
	
	public boolean contians(T t)
	{
		return queue.contains(t);
	}
	
	public boolean empty()
	{
		return queue.isEmpty();
	}
}
</PRE></TD></TR></TBODY></TABLE><BR><BR><A name=N10213><B>清单 9 FileDownLoader.java</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>package com.ie;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;

public class FileDownLoader {
	
	/**根据 url 和网页类型生成需要保存的网页的文件名
	 *去除掉 url 中非文件名字符 
	 */
	public  String getFileNameByUrl(String url,String contentType)
	{
		url=url.substring(7);//remove http://
		if(contentType.indexOf("html")!=-1)//text/html
		{
			url= url.replaceAll("[\\?/:*|&lt;&gt;\"]", "_")+".html";
			return url;
		}
		else//如application/pdf
		{
return url.replaceAll("[\\?/:*|&lt;&gt;\"]", "_")+"."+ \
          contentType.substring(contentType.lastIndexOf("/")+1);
		}	
	}

	/**保存网页字节数组到本地文件
	 * filePath 为要保存的文件的相对地址
	 */
	private void saveToLocal(byte[] data,String filePath)
	{
		try {
			DataOutputStream out=new DataOutputStream(
new FileOutputStream(new File(filePath)));
			for(int i=0;i&lt;data.length;i++)
			out.write(data[i]);
			out.flush();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/*下载 url 指向的网页*/
	public String  downloadFile(String url)
	{
		  String filePath=null;
		  /* 1.生成 HttpClinet 对象并设置参数*/
		  HttpClient httpClient=new HttpClient();
		  //设置 Http 连接超时 5s
		  	  httpClient.getHttpConnectionManager().getParams().
setConnectionTimeout(5000);
		  
		  /*2.生成 GetMethod 对象并设置参数*/
		  GetMethod getMethod=new GetMethod(url);	 
		  //设置 get 请求超时 5s
		  getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT,5000);
		  //设置请求重试处理
		  getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
			new DefaultHttpMethodRetryHandler());
		  
		  /*3.执行 HTTP GET 请求*/
		  try{ 
			  int statusCode = httpClient.executeMethod(getMethod);
			  //判断访问的状态码
			  if (statusCode != HttpStatus.SC_OK) 
			  {
System.err.println("Method failed: "+ getMethod.getStatusLine());
				  filePath=null;
			  }
			  
			  /*4.处理 HTTP 响应内容*/
 byte[] responseBody = getMethod.getResponseBody();//读取为字节数组
			  //根据网页 url 生成保存时的文件名
filePath="temp\\"+getFileNameByUrl(url,
		   getMethod.getResponseHeader("Content-Type").getValue());
			saveToLocal(responseBody,filePath);
		  } catch (HttpException e) {
				   // 发生致命的异常，可能是协议不对或者返回的内容有问题
				   System.out.println("Please check your provided http 
address!");
				   e.printStackTrace();
				  } catch (IOException e) {
				   // 发生网络异常
				   e.printStackTrace();
				  } finally {
				   // 释放连接
				   getMethod.releaseConnection();		   
				  }
				  return filePath;
	}
	//测试的 main 方法
	public static void main(String[]args)
	{
		FileDownLoader downLoader = new FileDownLoader();
		downLoader.downloadFile("http://www.twt.edu.cn");
	}
}
</PRE></TD></TR></TBODY></TABLE><BR><BR><A name=N1021C><B>清单 10 HtmlParserTool.java</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>package com.ie;

import java.util.HashSet;
import java.util.Set;

import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

public class HtmlParserTool {
	// 获取一个网站上的链接,filter 用来过滤链接
	public static Set&lt;String&gt; extracLinks(String url,LinkFilter filter) {

		Set&lt;String&gt; links = new HashSet&lt;String&gt;();
		try {
			Parser parser = new Parser(url);
			parser.setEncoding("gb2312");
			// 过滤 &lt;frame &gt;标签的 filter，用来提取 frame 标签里的 src 属性所表示的链接
			NodeFilter frameFilter = new NodeFilter() {
				public boolean accept(Node node) {
					if (node.getText().startsWith("frame src=")) {
						return true;
					} else {
						return false;
					}
				}
			};
			// OrFilter 来设置过滤 &lt;a&gt; 标签，和 &lt;frame&gt; 标签
			OrFilter linkFilter = new OrFilter(new NodeClassFilter(
					LinkTag.class), frameFilter);
			// 得到所有经过过滤的标签
			NodeList list = parser.extractAllNodesThatMatch(linkFilter);
			for (int i = 0; i &lt; list.size(); i++) {
				Node tag = list.elementAt(i);
				if (tag instanceof LinkTag)// &lt;a&gt; 标签
				{
					LinkTag link = (LinkTag) tag;
					String linkUrl = link.getLink();// url
					if(filter.accept(linkUrl))
						links.add(linkUrl);
				} else// &lt;frame&gt; 标签
				{
		        // 提取 frame 里 src 属性的链接如 &lt;frame src="test.html"/&gt;
					String frame = tag.getText();
					int start = frame.indexOf("src=");
					frame = frame.substring(start);
					int end = frame.indexOf(" ");
					if (end == -1)
						end = frame.indexOf("&gt;");
					String frameUrl = frame.substring(5, end - 1);
					if(filter.accept(frameUrl))
						links.add(frameUrl);
				}
			}
		} catch (ParserException e) {
			e.printStackTrace();
		}
		return links;
	}
	//测试的 main 方法
	public static void main(String[]args)
	{
Set&lt;String&gt; links = HtmlParserTool.extracLinks(
"http://www.twt.edu.cn",new LinkFilter()
		{
			//提取以 <A href="http://www.twt.edu.cn/" cmImpressionSent="1"><CODE><FONT color=#5c81a7>http://www.twt.edu.cn</FONT></CODE></A> 开头的链接
			public boolean accept(String url) {
				if(url.startsWith("http://www.twt.edu.cn"))
					return true;
				else
					return false;
			}
			
		});
		for(String link : links)
			System.out.println(link);
	}
}
清单11 LinkFilter.java
package com.ie;

public interface LinkFilter {
	public boolean accept(String url);
}
</PRE></TD></TR></TBODY></TABLE><BR>
<P>这些代码中关键的部分都在 HttpClient 和 HtmlParser 介绍中说明过了，其他部分也比较容易，请感兴趣的读者自行理解。</P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><BR><IMG height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox href="http://www.ibm.com/developerworks/cn/opensource/os-cn-crawler/index.html#main" cmImpressionSent="1"><B><FONT color=#5c81a7>回页首</FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=7.总结><SPAN class=atitle>总结</SPAN></A></P>
<P>这篇文章主要是介绍与展示了如何使用开源的 HttpClinet 包和 HtmlParser 包，以及结合这两者来给出了一个简易网络爬虫程序的实现，当然这个爬虫与实际真正的爬虫还是有所差距。由于更多的目的是关注这两个开源包的运用，加上本文篇幅有限，因此，没有对这两个开源包做非常详尽的介绍。希望这篇文章能够引导读者对 HttpClient 包和 HtmlParser 产生兴趣，从而利用他们构建强大的 JAVA 网络应用程序。 </P>]]></description>
</item>
</channel>
</rss>