httpclient与htmlparser等技术札记这是开发远程数据时学的新知识记录_第1页
httpclient与htmlparser等技术札记这是开发远程数据时学的新知识记录_第2页
httpclient与htmlparser等技术札记这是开发远程数据时学的新知识记录_第3页
httpclient与htmlparser等技术札记这是开发远程数据时学的新知识记录_第4页
httpclient与htmlparser等技术札记这是开发远程数据时学的新知识记录_第5页
已阅读5页,还剩87页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第1/88 本书由JavaEye提供的DIY功能自动生成于2009-01-—#! #!#2008-12-08关键字:Http是ApacheJakartaCommon下的子项目,可以用来提供高效的、的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议的版本和建议。本文首先介绍HTTP,然后根据作Http基本功能的使^╳_▄42?使用Http需要以下6个步骤创建Http的实GetMethod。在GetMethodexecutemethod读Httphttp=newHttp创建GET方法的实例。在GET方法的构造函数中传入待连接的地址即可。用GetMethod将会自动处理转发过程,如果想要把自动处理转发过程去掉的话,可以调用方法setFwRedirects(f)。GetMethodgetMethod=new 调用实例http的execteMethod方法来执行getMethod。由于是执行在网络上的程序,在运行cethod方法的时候,需要处理两个异常,分别是tinIOExcion。引起第一种异常的原因主要可能是在构造getMethod的时候传入的协议不对,比如不将"http"写成"htp",务回的内容不正常等,并且该异常发生是不可恢复的;第二种异常一般是由于网络原因引起的异常,对于这种异常(IOExcin),Http会根据你指定的恢复策略自动试着重新执行executeMethod方法。Http的恢复策略可以自定义(通过实现接口HttpMethodRetryHandlr来实现)。通过http的方法setParametr设置你实现的恢复策略,本文中使用的是系统提供的默认恢复策略,该策略在碰到第二类异常的时候将自动重试3次。excuteMethod返回值是一个整数,表示了执行该方法后服务器返回的状态码,该状态码能表示出该方法执行是否成功、需要认证或者页面发生了跳转(默认状态下GetMethod的实例是自动处理跳转的)等。newintstatusCode=if(statusCode!=HttpStatus.SC_OK)System.err.println("Methodfailed:"+}在返回的状态码正确后,即可取得内容。取得目标地址的内容有三种方法:第一种,getResponsBody,该方法返回的是目标的二进制的byte流;第二种,getRespBodyAsStig,这个方法返回的是String类型,值得注意的是该方法返回的String的编码是根据系统默认的编码方式,所以返回的String值可能编码类型有误,在本文的"字符编码"部分中将对此做详细介绍;第三种,getRespeyAsStream,这个方法对于目标地址中有大量数据需要传输是最佳的。在这里我们使用了最简单的getRespeBody方法。byte[]responseBody=packageimport publicclassGetSample{publicstaticvoidmain(String[]args) http=newHttpGetMethodgetMethod=new newDefaultHttpMethodRetryHandler());tryintstatusCode=http if(statusCode!=HttpStatus.SC_OK){System.err.println("Methodfailed:+}byte[]responseBody=System.out.println(new}catch(HttpExceptione)System.out.println("Pleasecheckyourprovidedhttpaddress!");}catch(IOExceptione)}finally}}}根据RFC26,对POST的解释如下:POST方法用来向目的服务器发出请求,要求它接受被附在请求后的实体,并把它当作请求队列(Requetie)中请求URI所指定资源的附加新子项。POST被设计成用统一的方法实现下列功能:对现有资源的注释(Annotationofexisting调用Http中的PostMethd与GetMethod类似,除了设置Posthd的实例与GetMethod有些不同之外,剩下的步骤都差不多。在下面的例子中,省去了与GetMethod相同的步骤,只说明与上面不同的地方,并以登录BBS为例子进行说明。构造PostMd之前的步骤都相同,与GetMethod一样,构造PotMethod也需要一个URI参数,在本例中,登录的地址是。在创建了PostMethod的实例之后,需要给method实例填充表单的值,在BBS的登录表单中需要有两个域,第一个是用户名(叫id),二是(叫paswd)。表单中的域用类NmeValuePair来表示,该类的构造函数第一个参数是,第二参数是该域的值;将表单所有的值设置到PostMethod中用方法sBody。另外由于BBS登录成功后会转向另外一个页面,但是Http 对于要求接受后继服务的请求,比如POT和PUT,不支持自动转发,因此需要自己对页面转向做处理。具体的页面转向处理请参见下面的"自动转向"部分。代码如下:Stringurl="PostMethodpostMethod=newNameValuePair[]data={newNameValuePair("id","youUserName"),newNameValuePair("passwd","yourPwd")};postMethodintstatusCode= // //301或者if(statusCode==HttpStatus.SC_MOVED_PERMANENTLY||statusCode==HttpStatus.SC_MOVED_TEMPORARILY){HeaderlocationHeader=postMethod.getResponseHeader("location");Stringlocation=null;if(locationHeader!=null)location=locationHeader.getValue();System.out.println("Thepagewasredirectedto:"+location);}elseSystem.err.println("Locationfieldvalueis}}某目标页的编码可能出现在两个地方,第一个地方是服务器返回的http头中,另外一个地方是得到的l页面中。Type:text/html;charset=UTF-8。这个头信息表明该页的编码是UTF-8,但是服务器返回的头信息未必与内容能匹配上。比如对于一些双字节语言国家,可能服务器返回的编码类型是UTF-8,但真正的内容却不是UTF-8编码的,因此需要在另外的地方去得到页面的编码信息;但是如果服务器返回的编码不是UTF-8,而是具体的一些对于象xml或者html这样的文件,允许作者在页面中直接指定编码类型。比如在html中会有<metahttp-equiv="Content-Type"content="text/html;charset=gb2312"/>这样的;或者在xml中会有<?xmlversion="1.0"encoding="gb2312"?>这样的,在这些情况下,可能与http头中返回的编码信息,需privatestaticfinalStringCONTENT_CHARSET="GBK";//http内容时使用的字符 =new 字符串编码改变的方法:Stringtarget=newString(orig.getBytes("ISO-8859-Http三种不同的认证方案:Basic,DigestandNTLM.这些方案可用于服务器或对客户端的认证,简服务器认证(Server 处理服务器认证几乎是透明的,仅需要开发人员提供登录信息(logincredentials)。登录信息保存在HttpState类的实例中,可以通过setCredentials(Stringrealm,Credentialscred)和getCredentials(Stringrealm)来获取或设置。注意,设定对非特定站点所需要的登录信息,将realm参数置为null.Http 证,可以通过HttpMethod类的setDoAuthentication(booleandoAuthentication)方法关闭,而且这次关闭在这种模式时,Http 会主动将basic认证应答信息传给服务器,即使在某种情况下服务器可能返回认证失败的应答,这样做主要是为了减少连接的建立。为使每个新建的HttpStat实例都实行抢先认证,可以如下设置系统属性。setSystemProperty(Authenticator.PREEMPTIVE_PROPERTY,"true"); 2)认证 除了登录信息需单独存放以外,认证与服务器认证几乎一致。用setCredentials(Stringrealm,Credentialscred)和getCredentials(Stringrealm)设、取登录信息。认证方案(authentication是HTTP中规定最早的也是最兼容(?)的方案,遗憾的是也是最不安全的一个方案,因为它以明码传送用户名和密码。它要求一个UsernamsswrdCredeias实例,可以指定服务器端的空间或采用默认的登录信息。igest是在HTTP.1中增加的一个方案,虽然不如Bac得到的软件支持多,但还是有广泛的使用。Digest方案比c方案安全得多,因它根本就不通过网络传送实际的,传送的是利用这个对从服务器传来的一个随机数(nonce的加密串。它要求一个UserPaswrdredeils实例,可以指定服务器端的空间或采用默认的登录信息。这是Http支持的最复杂的认证协议。它M$设计的一个私有协议,没有公开的规范说明。一开始由于设计的缺陷,NTM的安全性比Digest差,后来经过一个Sik补丁后,安全性则比较Digest高。NTLM需要一个NTredentils实例.注意,由于NTLM不使用空间(rea)的概念,Http利用服务器的作访问空间的名字。还需要注意,提供给NTredeils的用户名,不要用的前缀-如:""是正确的,而 \"则是错的.NTLM认证的工作机制与basic和digest有很大的差别。这些差别一般由 从 API的角度来看,NTLM与其它认证方式一样的工作,差别是需要提供'NTCredentials'实例而不'UserePsswrdCredenia'(其实,前者只是扩展了后者)NTLM认证,空间是连接到的机器的域名,这对多主机会有一些麻烦.只有Http 连接中指定的才是认证用的。建议将realm设为null以使用默认的设置。NTM只是认证了接而不是一请求,所以每当一个新的连接建立就要进行一次认证,且在认证的过程中保持连接是非常重要的。因此,NTLM不能同时用于认证和服务器认证,也不能用于http.0连接或服务器不支持持久连接的情况。由于技术限制,以及为保证.0发布版API的稳定,Http还不能自动处重定向,但对重定向到同一主机、同一端口且采用同一协议的情况Http可以支持。不能自动的处理的情况,包括需要人工交互的情况,或超出http的能力。301302303SeeOther.307当收到简单的重定向时,程序应从HttpMethod对象中抽取新的URL并将其。另,限制一下重定向次数是个好的主意,这可以避免递归循环。新的URL可以从头字段Location中抽取,如下:StringHeaderlocationHeader=method.getResponseHeader("location");if(locationHeader!=null){redirectLocation=}else//Theresponseisinvalidanddidnotprovidethenewlocation//theresource.Reportanerrororpossiblyhandlethe//likea404NotFound}300304HttpStatus.SC_NO305使用.根据RFC26中对自动转向的定义,主要有两种: 和 。 表示永久的移走(MovedPermanely),当返回的是1,则表示请求的资源已经被移到一个固定的新地方,任何向该地址发起请求都会被转到新的地址上。02表示暂时的转向,比如在服务器端的servlt程序调用了sendReirec方法,则在客户端就会得到一个32的代码,这时服务器返回的头信息中location的值就是seedrect转向的目标地址。p支持自动转向处理,但是象POSTPUT方式这种要求接受后继服务的请求方式,暂时不支持自动转向,因此如果碰到POST方式提交后返回的是01或者02的话需要自己处理。就像刚才在POSThod中举的例子:如果想进入登录BBS后的页面,必须重新发起登录的请求,请求的地址可以在头字段location过需要注意的是,有时候location返回的可能是相对路径,因此需要对location返回的值做一些处理才可以发起向新地址的请求。另外除了在头中包含的信息可能使页面发生重定向外,在页面中也有可能会发生页面的重定向。引起页面自动转发的是:<metahtequiv="reres"5;l= ">。如果你想在程序中也处理这种情况的话得自己分析页面来实现转向。需要注意的是,在上面那个中url的值也可以是一个相对地址,如果是这样的话,需要对它做一些处理后才可以转发。 能自动管理,包括允许服务器设置并在需要的时候自动将 后发送到服务器端。不幸的是,对如何处理,有几个规范互相:Netscape草案,RFC2109,RFC2965,而且还有很大数量的软件商的 实现不遵循任何规范.为了处理这种状 提供了策略驱动的管理方式。Http 规范有:Netscape草案,是最早的 规范,基于rfc19。尽管这个规范与rc109有较大的差别,这样做可以与一些服务器兼容。rfc109,是wc发布的第一个规范。理论上讲,所有的服务器在处理 (版1)时,都要遵循此规范,正因如此,Http将其设为默认的规范。遗憾的是,这个规范太严格了,以致很多服务器不正确的实施了该规范或仍在作用Nescae规范。在这种情况下,应使用兼容规范。兼容性规范,设计用来兼容尽可能多的服务器,即使它们并没有遵循。当解析 出现问题时,应考虑采用兼容性规范。RFC2965规范暂时没有被Http支持(在以后的版本为会加上),它定义了版本2,并说明了 newHttp new spec", 用一个浏览器服务器,以确认服务器应答正常如果在使,关掉试试另找一个服务器来试试(如果运行着不同的服务器软件更好)检查代码是否按中讲的思路编写设置log级别为debug,题原因打开wiretrace,来追踪客户端与服务器的通信,以确实问题出现在什么地方用 nt或netcat手工将信息发送到服务器,适合于猜测已经找到了原因而进行试验时将netcat以方式运行,用作服务器以检查http 试试,bug可能在的版本中修复了向邮件列表求帮助向bugzilla报借助JavaSecureSocketExtension(JSSE),Http 全面支持SecureSocketsLayer(SSL)或IETFTransportLayerSecurity(TLS)协议上的HTTP。JSSE已经jre1.4及以后的版本中,以前的版本则需要手工安装设置,具体过程参见Sun或本学习笔记。 =new GetMethodhttpget=newGetMethod("https: Httphttp=newHttp();http.getHostConfiguration().set("my host",8080);http.getState().setCredentials("my- -realm","my newUsernamePasswordCredentials("my- -username","my- GetMethodhttpget=newGetMethod("https: factory。这个socketfactory负责打一个到服务器的端口,使用标准的或第的SSL函数库,并进行象连接https),一个定制的socketfactory,和一个默认的端中号(如https的443端口).Protocolmyhttps=newProtocol("https",newMySSLSocketFactory(),443);然后,这个实例可被设置为协议的处理器。Httphttp =newHttp ",443,myhttps);GetMethodhttpget=newGetMethod("/"); 通过调用Protocl.regiterProtcl方法,将此定制的实例,为某一特定协议的默认的处理器。由此,可以很方便地定制自己的协议类型(如myhttps)。newProtocol("https",newMySSLSocketFactory(), =new GetMethodhttpget=newGetMethod("myhttps: newProtocol("https",newMySSLSocketFactory(),443)); =newHttp GetMethodhttpget=newGetMethod("https: 已知的限制和问题持续的SSL连接在Sun的低于.4JM上不能工作,这是由于JVMbg造成。通过服务器时,非抢先认证(No-preemptieautheniion)会失败,这是由于Http 的设计缺陷造成的,以后的版本中会修改。importjava.io.BufferedReader;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.io.Writer;.ssl.SSLSocketFactory;publicclassTest{publicstaticfinalStringTARGET_HTTPS_SERVER=" publicstaticfinalintTARGET_HTTPS_PORT=443;publicstaticvoidmain(String[]args)throws{Socketsocket=SSLSocketFactory.getDefault().createSocket(TARGET_HTTPS_SERVER,TARGET_HTTPS_PORT);tryWriterout=OutputStreamWriter(socket.getOutputStream(),"ISO-8859-1");out.write("GET/out.write("Host:"+TARGET_HTTPS_SERVER+":"+TARGET_HTTPS_PORT+"\r\n");out.write("Agent:SSL-TEST\r\n");BufferedReaderin=newnewInputStreamReader(socket.getInputStream(),"ISO-8859-1"));Stringline=null;while((line=in.readLine())!={}}finally}}}使用多线程的主要目的,是为了实现并行的。在http运行的过程中,每个http协议的方法,使用一pConnein实例。由于连接是一种有限的资源,每个连接在某一时刻只能供一个线程和方法使用,所以需要确保在需要时正确地分配连接。Http 采用了一种类似jdbc连接池的方法来管理连接,这个管理工作由liHttpConnecinManager完成。MultiThreadedHttpConnectionManagerconnectionManager=newMultiThreadedHttpConnectionManager();Http=newHttp此是,可以在多个线程中被用来执行多个方法。每次调用Http.executeMethod()方法,都会去器。管理器支持两个设置:maxConnectionsPerHost每个主机的最大并行数,默认为2maxTotalConnections客户端总并行最大数,默认为20管理器重新利用时,采取早归还者先重用的方式(leastrecentlyusedapproach)。 MultiThreadedHttpConnectionManagerconnectionManager=newHttp=newHttpGetMethodget=newGetMethod("");try{//printresponsetostdout}finally//besuretheconnectionisreleasedbacktothe//manager} 在method.rleaseConi)后并没有把关闭,这个方法只是将返回给connectionmanager。如果使用Http =wp ()实例化一个p eionmanager默认实现是使用{this.alwaysClose=}alwaysClose设为true在释放之后connectionmanager就会关闭链。在我们Http=newHttp()这样实例化一个时connectionmanager是这样被实例化的this.httpConnectionManager=newSimpleHttpConnectionManager();因此alwaysClose默认是fals,conin是不会被主动关闭的,因此我们就有了一个客户端关闭的方法。解决方法:manager会关闭connection。Http=newHttp(newHttpParams(),new2、实例化代码使用:Http=newHttp();在method.releaseConnection();之后加publicvoidshutdown()} =newHttppublicvoidcloseIdleConnections(longidleTimeout){longmaxIdleTime=System.currentTimeMillis()-idleTimeout;if(idleStartTime<=maxIdleTime){}}method.setRequestHeader("Connection","close");importimportimport *用*@authorpublicclass{publicstaticvoidmain(String[]args)throwsHttp=newHttpGetMethodget=newGetMethod("http FilestoreFile=newFile("c:/2008FileOutputStreamoutput=new 23. 2008-12-08关键字:importjava.util.Map;importorg.htmlparser.Node;importorg.htmlparser.NodeFilter;importorg.htmlparser.Parser;importorg.htmlparser.tags.LinkTag;importorg.htmlparser.util.NodeList;importcom.yao.http.HttpRespons;*@authorpublicclassTestpublicstaticvoidmain(String[]{try/*首先我们先使用HttpRequester类和HttpRespons类获得一个HTTP请求中的数据(HTML文档)。可以从Map<String,String>map=newHashMap<String,String>();HttpRequesterrequest=newHttpRequester();HttpResponshr=request.sendGet("ht Parserparser=Parser.createParser(hr.getContent(),hrtry//通过过滤器过滤出<A>NodeListnodeListparserpublicbooleanaccept(Nodeif(nodeinstanceofLinkTag)//标returnfalse;}for(inti=0;i<nodeList.size();i++)LinkTagn=(LinkTag)nodeList.elementAt(i);System.out.print(n.getStringText()+"==>>");}}catch(Exception{}}catch(Exception{}}} 2008-12-08关键字:通过使用Log4,可以指定日志信息输出的目的地,控制每一条日志的输出格式,定义日志信息的级别。所有这些功能通过一个配置文件灵活进行配置。...一个Logger可以有多个Appender,也就是说日志信息可以同时输出到多个设备上,每个Appender一种Layout(示例见下图)。↗Appender1→/﹨↘Appender2→ packageorg.apache.log4j;publicclassLogger//Creation&retrievalmethods:publicstaticLoggergetRootLogger();publicstaticLoggergetLogger(String//printingpublicvoiddebug(Objectmessage);publicvoidinfo(Objectmessage);publicvoidwarn(Objectmessage);publicvoiderror(Objectmessage);publicvoidfatal(Objectmessage);//genericprintingpublicvoidlog(Priorityp,Object}一共有五种,级别由高到低依次是:fatal、error、warn、info、debug。获得Logger调用以下方法之一输出日志信息:publicvoiddebug(Objectmessage); publicvoidinfo(Objectmessage); //输出info级别的日志信息;publicvoidwarn(Objectmessage); publicvoiderror(Objectmessage); publicvoidfatal(Objectmessage); publicvoidlog(Priorityp,Objectmessage);//输出参数Priority以上方法只有当它的级别大于或等于Logger组件配置的日志级别时才调用。以前面我们配置的myLogger为例,它的日志级别为WARN,那么在程序中,它的warn)、error()、fatal()方被执行。对log有当它的参数Priority指定的日志级别大于或等于WARN时,它才会被执行。在写程序的时候,为了调试程序,我们会在很多出错的地方输出大量的日志信息。当程序调试完,不需要这些信息时,将程序中这些输出日志信息代码删除吗?这样费时费力,对于大型程序几乎不可行。通过对日志分级,假如不想输出WARN级别的日志信息,则Logger组件的级别调高即可,省时。Log4J提供了一个rootLogger,它是所有Logger组件的“祖先”,它存在,且不能通过名字检索或引用,通过Logger.getRootLogger()方法取得它。配置rootLogger代码:可在配置文件中方便地配置存在继承关系的Logger前面的Loggr组件的子类。例如:以上代码中,mySonLogger是myLogger的子类Logger组件。Logger.黙认情况下,子类Logger组件会继承父类所有的Appender,把它们加入到自己的Logger组件的additivity标志设为false,那么它就不会继承父类Appender。additivity标志默认rootLogger:日志级别=INFOappender↑myLogger:日志级别=WARNappender↑mySonLogger:日志级别=nullappender rootLogger WARN .文件.GUI组件(GUI(Remotesocket.NT的记录器(NTEvent.UNIXSyslog守护进程(RemoteUNIXSyslog一个Logger可同时对应多个Appender,示例:myLogger配置二个Appender:file,console:.org.apache.log4j.TTCCLayout(包含日志产生的时间、线程和类别等信息);WARN-Thisisalogmessagefromthelog4j.appender.file.layout.ConversionPattern=%t%p%m%nTHREAD-1WARNThisisalogmessagefromthemyLogger J支持二种配置文件格式:XLJavaJava属性文件格式配置文件:.配置Logger配置rootLogger语法为:.配置Appender配置日志信息输出目的地Appender,语法为:.配置Layout下面为一配置文件示例,文件名为##LOGGERS#configurerootlogger#definealoggernamedmyLogger#defineasecondloggerthatisachildtomyLogger##APPENDERS#defineanappendernamedconsole,whichissettobeaConsoleAppender#defineanappendernamedfile,whichissettobeaRollingFileAppender##LAYOUTS#assianaSimpleLayouttoconsoleappender#assianaPatternLayouttofileappenderLoggermyLogger=.日志记录器,配置Log4J环境自动快速地使用默认myLogger.debug("Thieisalogmessagefromthe"+importimportpublicclassTestpublicstaticvoidmain(String[]args)//GetaninstanceoftheLoggermyLogger=//GetaninstanceoftheLoggermySonLogger=//LoadtheproertiesusingthePropertyConfigurator//LogMessagesusingtheParentmyLogger.debug("Thieisalogmessagefromthe"+myLogger.getName());myL("Thieisalogmessagefromthe"+myLogger.getName());myLogger.warn("Thieisalogmessagefromthe"+myLogger.getName());myLogger.error("Thieisalogmessagefromthe"+myLogger.getName());myLogger.fatal("Thieisalogmessagefromthe"+myLogger.getName());mySonLogger.debug("Thieisalogmessagefromthe"+mySonLogger.getName());mySonL("Thieisalogmessagefromthe"+mySonLogger.getName());mySonLogger.warn("Thieisalogmessagefromthe"+mySonLogger.getName());mySonLogger.error("Thieisalogmessagefromthe"+mySonLogger.getName());mySonLogger.fatal("Thieisalogmessagefromthe"+mySonLogger.getName());}}WARN-ThieisalogmessagefromthemyLogger&;ERROR-ThieisalogmessagefromthemyLoggerFATAL-ThieisalogmessagefromthemyLoggerWARN-ThieisalogmessagefromthemyLogger.mySonLoggerERROR-ThieisalogmessagefromthemyLogger.mySonLoggerFATAL-ThieisalogmessagefromthemyLogger.mySonLogger另在Test.class所在的下看到一个log.txt文件,内容如下:WARN-ThieisalogmessagefromthemyLogger.mySonLoggerERROR-ThieisalogmessagefromthemyLogger.mySonLoggerFATAL-ThieisalogmessagefromthemyLogger.mySonLoggerWARN-ThieisalogmessagefromthemyLoggerERROR-ThieisalogmessagefromthemyLoggerFATAL-ThieisalogmessagefromthemyLoggerWARN-ThieisalogmessagefromthemyLogger.mySonLoggerWARN-ThieisalogmessagefromthemyLogger.mySonLoggerERROR-ThieisalogmessagefromthemyLogger.mySonLoggerERROR-ThieisalogmessagefromthemyLogger.mySonLoggerFATAL-ThieisalogmessagefromthemyLogger.mySonLoggerFATAL-ThieisalogmessagefromthemyLogger.mySonLoggermySonLogger的日志在控制台上输出了二次,这是因为mySonLogger继承了父类consoleAppender,本身又定义了一个consoleAppender,因而有二个consoleAppender。创建一个Serlt,在它初始化方法中Log4J配置文件并配置Log4J环境,这个Srlt在Web应用启动时候被加载和初始化,然后就可在其它Web组件中获取Logger对象并输出日志。importjavax.servlet.*;importjavax.servlet.http.*;importjava.io.*;importimportorg.apache.log4j.PropertyConfigurator;publicclassLog4JServletextends{publicvoidinit()throwsServletExceptionStringpath=Stringpropfile=path+getInitParameter("propfile");}}<%@pageLoggermyLogger=LoggermySonLogger=Logger.getLogger("myLogger.mySonLogger");myLogger.debug("Thieisalogmessagefromthe"+myLogger.getName());myL("Thieisalogmessagefromthe"+myLogger.getName());myLogger.warn("Thieisalogmessagefromthe"+myLogger.getName());myLogger.error("Thieisalogmessagefromthe"+myLogger.getName());myLogger.fatal("Thieisalogmessagefromthe"+myLogger.getName());mySonLogger.debug("Thieisalogmessagefromthe"+mySonLogger.getName());mySonL("Thieisalogmessagefromthe"+mySonLogger.getName());mySonLogger.warn("Thieisalogmessagefromthe"+mySonLogger.getName());mySonLogger.error("Thieisalogmessagefromthe"+mySonLogger.getName());mySonLogger.fatal("Thieisalogmessagefromthe"+mySonLogger.getName());<formname="loginForm"method="post"action="dispatcher">username:<inputtype="text"name="username">password:<inputtype="text"<inputtype="submit"name="submit" 创建Log4J的配置文件perties,存放 编译Log4JServlet,存放 :<WEB应用所 WARN-ThieisalogmessagefromthemyLoggerERROR-ThieisalogmessagefromthemyLoggerFATAL-ThieisalogmessagefromthemyLoggerWARN-ThieisalogmessagefromthemyLogger.mySonLoggerERROR-ThieisalogmessagefromthemyLogger.mySonLoggerFATAL-ThieisalogmessagefromthemyLogger.mySonLogger WARN-ThieisalogmessagefromthemyLogger.mySonLoggerERROR-ThieisalogmessagefromthemyLogger.mySonLoggerFATAL-ThieisalogmessagefromthemyLogger.mySonLogger#!&时间:2008-12-时间:2008-12-【】正则表达式是烦琐的,但是强大的,学会之后的应用会让你除了提高效率外,会给你带来成就感。只要认真去阅读这些资料,加上应用的时候进行一定的参考,掌握正则表达式不是问题。1956年,一位叫StephenKleene的数学家在McCulloch和Pitts早期工作的基础上,了一篇标题为“神经网的表示法”的,引入了正则表达式的概念。正则表达式就是用来描述他称为“正则集的代数”的表达式,因此采▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃#!目前,正则表达式已经在很多软件中得到广泛的应用,包括*nix(LinuxUnix等),HP等操作系统,正则表达式的使用,可以通过简单的办法来实现强大的功能。为了简单有效而又不失强大,造成了正则表达式代码的难度较大,学习起来也不是很容易,所以需要付出一些努力才行,之后参照一定的参考,使用例子:这样的代码曾经多次把给吓退过。可能很多人也是被这样的代码给吓跑的吧。继续阅读本文将让也可以自由应用这样的代码。注意:这里的第7部分跟前面的内容看起来似乎有些重复,目的是把前面表格里的部分重新描述了一次,目的是让这些内容更容易理解。$!1956年,一位叫StephenKleene的数学家在McCulloch和Pitts早期工作的基础上,了一篇标题为 随后,发现可以将这一工作应用于使用KenThompson的计算搜索算法的一些早期研究,KenThompson是UnixUnix中的qed编辑器。如他们所说,剩下的就是众所周知的历史了。从那时起直至现在正则表达式都是基于文本的编辑器和搜索工具中的一个重要部分。%!正则表达式(regularexpression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某串、 dir*.txt或ls*.txt中的*.txt就不是一个正则表达式,因为这里*与正则式的*的含义是不同的。正则表达式是由普通字符(例如字符a到z)以及特殊字符(称为元字符)组成的文字模式。正则表达式字符含义匹配由x\cMControl-MxA-Za-zc c' x0c\cL x0a\cJ x0d\cM \ x09\cI \x0b\cK所谓特殊字符,就是一些有特殊含义的字符,如上面说的"*.txt"中的*,简单的说就是表示任何字符串的意思。如果要查找文件名中有*的文件,则需要对*进行转义,即在其前加一个\。ls\txt。正则表达式有以下特殊字符。$RegExpMultiline$n'\r$$。)***n[标记一个中括号表达式的开始。要匹配[,请使用\[。\||\|构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与操作符将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。贪婪或最小匹配。字符描述 匹配前面的子表达式零次或多次。例如,zo*z"zoo"。*{0, 匹配前面的子表达式一次或多次。例如,'zo"zo""zoo""z"{1,} 匹配前面的子表达式零次或一次。例如,"do(es"do"does"do"0,1 nn'o{2}'"Bob"'ofoodo

mnnmnmo{1,3}"fooooood"o。'o?'用来描述字符串或单词的边界,^和$分别指字符串的开始与结束,\b描述单词的前或后边界,\B词边界。不能对定位符使用限定符。其中:是非捕获元之一,还有两个非捕获元是=和!,这两个还有的含义,前者为正向预查,在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串,后者为负向预查,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的内容。子匹配的缓冲区编号从1开始,连续编号直至最大9个子表达式。每个缓冲区都可以使用'\',其中n为一个标识特定缓冲区的一位或两位十进制数。or&!操作符描述 *n}n, ,\ '!\

RegExpMultiline,^\n'r' 匹配输入字符串的结束位置。如果设置了RegExpMultiline,$\n'r' 匹配前面的子表达式零次或多次。例如,zo*z"zoo"。*{0, 匹配前面的子表达式一次或多次。例如,'zo"zo""zoo"z"{1,} 匹配前面的子表达式零次或一次。例如,"do(es"do"does"do"0,1 nn'o{2}'"Bob'ofoodo?

'o+'。'o{0,}''o*'mnnmnmo{1,3}"fooooood"o。'o{0,1}''o?'oooo",'o"o",而'o+'将匹配所有'o'。

式的各个部分是很有用。例如,'industr(?:y|ies)就是一个比'industry|industries'更简略的表达式。patternws=95|"Windos"Windw",但不能匹配"Winds1s"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从使用。例如'Windows(?!95|98|NT|2000)'能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的 匹配x或y。例如,'z|food'能匹配"z"或"food"。'(z|f)ood'则匹配"zood"或"food"。 字符集合。匹配所包含的任意一个字符。例如,'[abc]'可以匹配"in"中的'a'。 负值字符集合。匹配未包含的任意字符。例如,'[^abc]'可以匹配"in"中的'p'。 字符范围。匹配指定范围内的任意字符。例如,'[a-z]'az 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]'az' 匹配非单词边界。'er\B"verb'er'"never"'er'x\cMControl-MxA-Za-zc c' x0c\cL x0a\cJ x0d\cM \ x09\cI \x0b\cK '\x04'&"1"ASCII 标识一个八进制转义值或一个向后。如果\n之前至少n个获取的子表达式,则n为向后。否则,如果n为八进制

标识一个八进制转义值或一个向后。如果\nm之前至少有nm个获得子表达式,则nm为向后。如果\nm之前至匹配八进制转义值nm。 n0-3ml0-7),nml 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹 (! # /Windows(?=95|98|NT )!一切从最基本的开始。模式,是正规表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:串"onceuponatime"匹配,与"ThereoncewasamanfromNewYork"不匹配。正如如^符号表示开头一这个模式与"Whokeptallofthiscashinabucket"匹配,与"buckets"不匹配。字符^和$同时使用时,ThereoncewasamanfromNewYorkWhokeptallofhiscashinabucket.在该模式中的字母(-c)是字面的字符,也就是说,他们表示该字母本身,数字也是一样的。其他一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠(\)打头。制表符的转义序列是:\t。所以如果我们要检测一个字符串是否以制表符开头,可以用这个模式:在INTERNET的程序中,正规表达式通常用来验证用户的输入。当用户提交一个FORM以后,要判断输入的、地址、 地址、号码等是否有效,用普通的基于字面的字符是不够的。所以要用一种更自由的描述我们要的模式的办法,它就是字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符放在一个方括号里:[a-z]//匹配所有的小写字母[A-Z[a-zA-Z]//匹配所有的字母[0-9]//匹配所有的数字[0-9\.[\f\r\t\n]//匹配所有的白字符同样的,这些也只表示一个字符,这是一个非常重要的。如果要匹配一个由一个小写字母和一位数字组成的字符串,比如"z"、"t"或"g7",但不是"ab"、"rd3"或"b2"的话,用这个模式:[^a-z]//除了小写字母以外的所有字符[^\\\/\^]^)之外的所有字符特殊字符"."(点,句号)在正规表达式中用来表示除了“新行”之外的所有字符。所以模式"^.$"与任何两个字符的、以数字5结尾和以其他非“新行”字符开头的字符串匹配。模式"."可以匹配任何字符串,除了空串和只包括一个“新行”的字符串。[[:alpha:[[:digit:]][[:space:]][[:upper:]][[:lower:]][[:xdigit:]]任何16进制的数字,相当于[0-9a-fA-7.3到现在为止,你已经知道如何去匹配一个字母或数字,但的情况下,可能要匹配一个单词或一组数面的内容的重复出现的次数。^[a-zA-Z_]$^[[:alpha:]]{3}$所有的3^a$字母^a{4}$^a{2,4}$aa,aaa或^a{1,3}$a,aa或^a{2,}$包含多于两个a如:,}如:\t{2这些例子描述了花括号的三种不同的用法。一个数字,{x}的意思是“前面的字符或字符簇只出现x次”;一个数字加逗号,{,}的意思是“前面的内容出现x或的次数”;两个用逗号分隔的数字,{,y}“内容至少出现x次,但不超过y次”。我们可以把模式扩展到的单词或数字://所有的小数最后一个例子不太好理解,是吗?这么看吧:与所有以一个可选的负号(\{0,1}开头(^)、跟着0个或的数字([{0,1})再跟上0个或多个数字([0。下面你将知道能够使用的更为简单的方法。{0,1}是相等的,它们都代表着:“0个或1个前面的内容”或“前面的内容是可选的”。所以刚才的例子可以简化为:特殊字符"*"与{0,}是相等的,它们都代表着“0{1,}是相等的,!'时间:2008-12-时间:2008-12-需要做一个垂直搜索引擎,比较了nekohtml和htmlparsernekohtml在容错性、性能等方面的口碑好像比htmlparser好(htmlunit也用的是nekohtml),但感觉nekohtml的测试用例和文档都比htmlparser的使用,有空再研究nekohtml和mozillahtmlparser的使用。HTMLHTMLParserisaJavalibraryusedtoparseHTMLineitheralinearornestedfashion.Primarilyusedfortransformationorextraction,itfeaturesfilters,visitors,customtagsandeasytouseJavaBeans.Itisafast,robustandwelltestedpackage.Thetwofundamentaluse-casesthatarehandledbytheparserareextractionandtransformation(thesynthesesuse-case,whereHTMLpagesarecreatedfromscratch,isbetterhandledbyothertoolsclosertothesourceofdata).Whilepriorversionsconcentratedondataextractionfromwebpages,Version1.4oftheHTMLParserhassubstantialimprovementsintheareaoftransformingwebpages,withsimplifiedtagcreationandediting,andverbatimtoHtml()methodoutput. * 取节点起始位置的方法:getStartPosition、getEndPositionVisitor方法遍历节点时候方法:accept(NodeVisitorvisitor)Filter方法:collectIntoNodeListlistNodeFilterfilter)* *叶子节点HTMLParserisaJavalibraryusedtoparseHTMLineitheralinearornestedfashion.Primarilyusedfortransformationorextraction,itfeaturesfilters,visitors,customtagsandeasytouseJavaBeans.Itisafast,robustandwelltestedpackage.Thetwofundamentaluse-casesthatarehandledbytheparserareextractionandtransformation(thesynthesesuse-case,whereHTMLpagesarecreatedfromscratch,isbetterhandledbyothertoolsclosertothesourceofdata).Whilepriorversionsconcentratedondataextractionfromwebpages,Version1.4oftheHTMLParserhassubstantialimprovementsintheareaoftransformingwebpages,withsimplifiedtagcreationandediting,andverbatimtoHtml()methodoutput. *采用Visitor方式HtmlWU\Parserparser=RIZ NodeVisitorvisitor=RIZNodeVisitor()TXFPMGYSMHvisitTag(Tagtag)logger.fatal(”testVisitorAll()Tagnameis +tag.getTagName()+”\nClassis + 16. *采用Filter方式html20.WU\NodeFilterfilter=RIZParserparser=RIZ NodeListlist=LinkTagnode=(LinkTag)logger.fatal(”testLinkTag()Linkis:”+ 33. *采用org.htmlparser.beans 另外htmlparserorg.htmlparser.beansLinkBeanlinkBean=RIZ URL[]urls=linkBean.getLinks();URLurl=logger.fatal(”testLinkBean()-urlis:”+48. . htmlparser其实代码并不多,好好研究一下其代码,弥补文档不足的问题。同时htmlparser的代码注释和单元测试用例还是很齐全的,也有助于了解htmlparser的用法。56.3.1、 Parser.createParser(Stringhtml,StringcharsetParserParser(Lexerlexer,ParserFeedbackfb)、Parser(URLConnectionconnection,ParserFeedbackfb)Parser(Stringresource,ParserFeedbackfeedback)、Parser(String Parserparser=RIZParser JSU tori=parser.elements();i.hasMoreElements();processMyNodes(i.nextNode());*parse(NodeFilterfilter):通过NodeFilter*visitAllNodesWith(NodeVisitorvisitor):通过Nodevisitor*extractAllNodesThatMatchNodeFilterfilter):通过NodeFilter方式76.3.2、. 对Vir和lter的方法进行了封装,定义了针对一些常用html元素操作的bean,简化对常用元素的提取操作。 定义了htmlparser所提供的各种filter,主要通过extractAllNodesThatMatch(NodeFilterfilter)来HasAttributeFilter、HasChildFilter、HasParentFilter、HasSiblingFilter、IsEqualFilter、LinkRegexFilter、LinkStringFilter、NodeClassFilter、NotFilter、OrFilter、RegexFilter、 定义了htmlparser所提供的各种visitor,主要通过visitAllNodesWithNodeVisitorvisitor)来对ObjectFindingVisitor、StringFindingVisitor、TagFindingVisitor、TextExtractingVisitor、 定义了一些实用的工具,包括LinkExtractor、iteCapturr、StringExtrator、WiiCapturr,这几个类也可以作为htmlparsr使用样例。MQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUWMQTSUW MQTSUWMQTSUWMQTSUWMQTSUW TUMYEWIVWEWMGJMREPLoggerlogger=Logger.getLogger(ParserTestCase.GPEVV); *ObjectFindVisitorTXFPMGYSMHtestImageVisitor()WU\ImageTagObjectFindingVisitorvisitor=RIZParserparser=RIZ Node[]nodes=imgLink=(ImageTag)logger.fatal(”testImageVisitor()ImageURL= + logger.fatal(”testImageVisitor()ImageLocation= + logger.fatal(”testImageVisitor()SRC= + GEWGL(Exceptione) *测试TagNameFilterTXFPMGYSMHtestNodeFilter()WU\NodeFilterfilter=RIZParserparser=RIZ NodeListlist=logger.fatal(”testNodeFilter()”+ *测试NodeClassFilterTXFPMGYSMHtestLinkTag()WU\NodeFilterfilter=RIZParserparser=RIZ NodeListlist=LinkTagnode=(LinkTag)logger.fatal(”testLinkTag()Linkis:”+ *<linkhref=”text=’text/css’rel=’stylesheetTXFPMGYSMHtestLinkCSS()WU\Parserparser=RIZ +“<linkhref=’/test01/css.css’text=’text/css’rel=’stylesheet’ +“<linkhref=’/test02/css.css’text=’text/css’rel=’stylesheet’ +“</head>”+JSU tore=parser.elements();e.hasMoreNodes();)Nodenode=.fatal(”testLinkCSS()”+ + *测试OrFilterTXFPMGYSMHtestOrFilter()NodeFilterinputFilter=RIZNodeFilterselectFilter=RIZParserWU\Parserparser=RIZ +“<linkhref=’/test01/css.css’text=’text/css’rel=’stylesheet’ +“<linkhref=’/test02/css.css’text=’text/css’rel=’stylesheet’ + + +“<inputtype=’text’value=’text1′ +“<inputtype=’text’value=’text2′ +“<select><optionid=’1′>1</option><option +“<a +OrFilterlastFilter=RIZlastFilter.setPredicates(RIZNodeFilter[]{inputFilternodeList=MJ(nodeList.elementAt(i)MRVWERGISJInputTag)InputTa

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论