1、解析和遍历一个H T MLH H H文档如何解析一个H T MLH H H文档:S t r i n g h t ml = “ F i r s t p ars e “+ “ P ars e d H T MLH H H i n t o a d oc . “ ;D ocu m e n t d oc = Js oup . p ars e ( h t ml ) ;(更详细内容可查看解析一个H T MLH H H字符串. )其解析器能够尽最大可能从你提供的H T MLH H H文档来创见一个干净的解析结果,无论H T MH H H L的格式是否完整。比如它可以处理:没有关闭的标签(比如: L ore m
2、I p s u m p ar s e s t o L ore m I p s u m )隐式标签(比如.它可以自动将 Tabl e d at a包装成 ?)创建可靠的文档结构(h t m l标签包含h e ad和b ody,在h e ad只出现恰当的元素)一个文档的对象模型文档由多个E l e m e n t s和Te xt Node s组成(以及其它辅助n ode s:详细可查看:n ode s p ack aget r e e ) .其继承结构如下:D ocu m e n t继承E l e m e n t继承Node . Te xt Node继承N ode .一个E l e me n t包
3、含一个子节点集合,并拥有一个父E l e m e n t。他们还提供了一个唯一的子元素过滤列表。解析一个H T MLH H H字符串存在问题来自用户输入,一个文件或一个网站的H T MLH H H字符串,你可能需要对它进行解析并取其内容,或校验其格式是否完整,或想修改它。怎么办?j s onu能够帮你轻松解决这些问题解决方法使用静态Js oup . p ars e ( S t r i n g h t m l )方法或Js oup . p ars e ( S t r i n g h t m l , S t r i n g b as e Ur i )示例代码:S t r i n g h t ml
4、= “ F i r s t p ars e “+ “ P ars e d H T MLH H H i n t o a d oc . “ ;D ocu m e n t d oc = Js oup . p ars e ( h t ml ) ;描述p ar s e ( S t r i n g h t m l , S t r i n g b as e U r i )这方法能够将输入的H T MLH H H解析为一个新的文档( D ocu m e n t),参数b as e Ur i是用来将相对U R L转成绝对U R L,并指定从哪个网站获取文档。如这个方法不适用,你可以使用p ars e ( S t
5、 r i n g h t m l )方法来解析成H T MLH H H字符串如上面的示例。.只要解析的不是空字符串,就能返回一个结构合理的文档,其中包含(至少)一个h e ad和一个b ody元素。解析一个b ody片断问题假如你有一个H T MH H H L片断(比如.一个d i v包含一对p标签;一个不完整的H T MH H H L文档)想对它进行解析。这个H T MLH H H片断可以是用户提交的一条评论或在一个C MS页面中编辑b ody部分。办法使用Js oup . p ar s e B odyFr agme n t ( S t r i n g h t m l )方法.S t r i
6、 n g h t ml = “ L ore m i p s u m . “ ;D ocu m e n t d oc = Js oup . p ars e B odyFr agme n t ( h t m l ) ;E l e m e n t b ody = d oc. b ody( ) ;说明p ar s e B odyFr agme n t方法创建一个空壳的文档,并插入解析过的H T MLH H H到b ody元素中。假如你使用正常的Js oup . p ars e ( S t r i n g h t ml )方法,通常你也可以得到相同的结果,但是明确将用户输入作为b ody片段处理,以确保
7、用户所提供的任何糟糕的H T MLH H H都将被解析成b ody元素。D ocu m e n t . b ody( )方法能够取得文档b ody元素的所有子元素,与d oc . get El e m e n t s B yTag(“ b ody“)相同。保证安全S t ay s afe假如你可以让用户输入H T MLH H H内容,那么要小心避免跨站脚本攻击。利用基于Whi t e l i s t的清除器和c l e an( S t r i n g b odyH t m l , Whi t e l i s t w h i t e l i s t )方法来清除用户输入的恶意内容。一旦拥有了一个
8、D ocu m e n t,你就可以使用D ocu m e n t中适当的方法或它父类E l e m e n t和N ode中的方法来取得相关数据。从一个UR L加载一个D ocu m e n t存在问题你需要从一个网站获取和解析一个H T MLH H H文档,并查找其中的相关数据。你可以使用下面解决方法:解决方法使用Js oup . c onn e c t ( S t r i n g u r l )方法:D ocu m e n t d oc = Js oup . c onn e c t ( “ h t t p : / / e xamp l e . c om/ “ ) . get ( ) ;S
9、 t r i n g t i t l e = d oc . t i t l e ( ) ;说明c onn e c t ( S t r i n g u r l )方法创建一个新的C onn e c t i on,和ge t ( )取得和解析一个H T MLH H H文件。如果从该UR L获取H T MLH H H时发生错误,便会抛出I O Exce p t i onO O O,应适当处理。C onn e c t i on接口还提供一个方法链来解决特殊请求,具体如下:D ocu m e n t d oc = Js oup . c onn e c t ( “ h t t p : / / e xamp
10、 l e . c om“ ). d at a( “ q u e r y“, “ Java“). u s e r A ge n t ( “ Mozi l l a“). c ooki e ( “ aut h “ , “ t oke n “ ). t i me out ( 3000). p os t ( ) ;这个方法只支持Web U R L s ( h t t p和h t t p s协议) ;假如你需要从一个文件加载,可以使用p ar s e ( F i l e i n , S t r i n g c h ars e t Name )代替。从一个文件加载一个文档问题在本机硬盘上有一个H T MLH
11、 H H文件,需要对它进行解析从中抽取数据或进行修改。办法可以使用静态Js oup . p ars e ( F i l e i n , S t r i n g c h ars e t Name , S t r i n g b as e Ur i )方法:F i l e i n p u t = n e w F i l e ( “ / t mp / i n p u t . h t ml “ ) ;D ocu m e n t d oc = Js oup . p ars e ( i n p u t , “ UT F - 8“, “ h t t p : / / e xamp l e . c om/ “
12、) ;说明p ar s e ( F i l e i n , S t r i n g c h ars e t Name , S t r i n g b as e Ur i )这个方法用来加载和解析一个H T MH H H L文件。如在加载文件的时候发生错误,将抛出I O E xce p t i onO O O,应作适当处理。b as e Ur i参数用于解决文件中U R L s是相对路径的问题。如果不需要可以传入一个空的字符串。另外还有一个方法p ar s e ( F i l e i n , S t r i n g c h ars e t Name ),它使用文件的路径做为b as e Ur i
13、。这个方法适用于如果被解析文件位于网站的本地文件系统,且相关链接也指向该文件系统。使用D O M方法来遍历一个文档问题你有一个H T ML文档要从中提取数据,并了解这个H T ML文档的结构。方法将H T ML解析成一个D oc um e nt之后,就可以使用类似于D O M的方法进行操作。示例代码:F i l e i nput = new F i l e ( “ / t m p/ i nput. ht m l “ ) ;D oc um e nt doc= J s oup.par s e ( i nput, “ U T F - 8“, “ ht t p: / / e xam pl e . c
14、om / “ ) ;E l e m e nt c onte nt = doc. get E l e m e nt B yI d( “ c onte nt “ ) ;E l e m e nt s l i nks = c onte nt . get E l e m e nt s ByTa g( “ a “ ) ;f or ( E l e m e nt l i nk : l i nks) S t r i ng l i nkHr e f = l i nk.a t t r ( “ hr e f “ ) ;S t r i ng l i nkTe xt = l i nk.t e xt ( ) ;说明E l
15、e m e nt s这个对象提供了一系列类似于D O M的方法来查找元素,抽取并处理其中的数据。具体如下:查找元素get E l e m e nt B y I d( S t r i ng i d)get E l e m e nt s B yTa g(S t r i ng t a g)get E l e m e nt s B yCl a s s ( S t r i ng c l a s s N a m e )get E l e m e nt s B yAt t r i bute ( S t r i ng key) ( a nd r e l a t e d m e t hods)E l e m e
16、 nt s i bl i ngs: s i bl i ngEl e m e nt s ( ) , f i r s t E l e m e nt S i bl i ng() , l a s t E l e m e nt S i bl i ng() ;next E l e m e nt S i bl i ng() , pr e viousE l e m e nt S i bl i ng()G r a ph: par e nt ( ) , c hil dr e n( ) , c hil d( i nt i ndex)元素数据a t t r ( S t r i ng key)获取属性a t t r (
17、 S t r i ng key, S t r i ng val ue)设置属性a t t r i bute s ( )获取所有属性i d( ) , c l a s s N a m e ( ) a nd c l a s s N a m e s ( )t e xt ( )获取文本内容t e xt ( S t r i ng val ue)设置文本内容ht m l ( )获取元素内H T ML ht m l ( S t r i ng val ue)设置元素内的HT ML内容oute r Ht m l ( )获取元素外H T ML内容dat a ( )获取数据内容(例如:s c r i pt和s t y
18、le标签)t a g( ) a nd t a gNa m e ( )操作H T ML和文本a ppend(S t r i ng ht m l ) , pr e pend(S t r i ng ht m l )a ppendTe xt ( S t r i ng t e xt ) , pr e pendTe xt ( S t r i ng t e xt )a ppendEl e m e nt ( S t r i ng t a gNa m e ) , pr e pendEl e m e nt ( S t r i ng t a gNa m e )ht m l ( S t r i ng val ue)使
19、用选择器语法来查找元素问题你想使用类似于C S S或j Q uer y的语法来查找和操作元素。方法可以使用E l e m e nt . s e l e c t ( S t r i ng s e l e c t or )和E l e m e nt s . s e l e c t ( S t r i ng s e l e c t or )方法实现:F i l e i nput = new F i l e ( “ / t m p/ i nput. ht m l “ ) ;D oc um e nt doc= J s oup.par s e ( i nput, “ U T F - 8“, “ ht t
20、p: / / e xam pl e . c om / “ ) ;E l e m e nt s l i nks = doc. s e l e c t ( “ a hr e f “ ) ; / /带有hr e f属性的a元素E l e m e nt s pngs= doc. s e l e c t ( “ i m g s r c $=. png“ ) ;/ /扩展名为. png的图片E l e m e nt m a s t hea d = doc. s e l e c t ( “ div. m a s t hea d“) . f i r s t ( ) ;/ / c l a s s等于m a s
21、t hea d的div标签E l e m e nt s r e s ult L i nks = doc. s e l e c t ( “ h3.r a “ ) ; / /在h3元素之后的a元素说明j s oup e l e m e nt s对象支持类似于C S S (或j quer y)的选择器语法,来实现非常强大和灵活的查找功能。.这个s e l e c t方法在D oc um e nt , E l e m e nt ,或E l e m e nt s对象中都可以使用。且是上下文相关的,因此可实现指定元素的过滤,或者链式选择访问。S e l e c t方法将返回一个E l e m e nt s
22、集合,并提供一组方法来抽取和处理结果。S e l e c t or选择器概述t a gnam e :通过标签查找元素,比如:ans | t a g:通过标签在命名空间查找元素,比如:可以用f b| nam e语法来查找元素#id:通过I D查找元素,比如:#logo. c l a s s :通过c l a s s名称查找元素,比如:. m a s t hea d a t t r i bute :利用属性查找元素,比如: hr e f a t t r :利用属性名前缀来查找元素,比如:可以用 dat a - 来查找带有H T ML 5 D a t a s e t属性的元素 a t t r = v
23、al ue :利用属性值来查找元素,比如: w i dt h=500 a t t r = val ue , a t t r $=val ue , a t t r *=val ue :利用匹配属性值开头、结尾或包含属性值来查找元素,比如: hr e f *=/ pat h/ a t t r = r e gex :利用属性值匹配正则表达式来查找元素,比如:i m g s r c = ( ? i ) . ( png|j pe? g) * :这个符号将匹配所有元素S e l e c t or选择器组合使用e l #id:元素+ I D,比如:div#logoe l . c l a s s :元素+ c
24、 l a s s,比如:div. m a s t hea de l a t t r :元素+ c l a s s,比如:a hr e f 任意组合,比如:a hr e f . highli ghta nc e s t or c hil d:查找某个元素下子元素,比如:可以用. bodyp查找在“ body“元素下的所有p元素par e nt c hil d:查找某个父元素下的直接子元素,比如:可以用div. c onte nt p查找p元素,也可以用body *查找body标签下所有直接子元素s i bl i ngA+ s i bl i ngB:查找在A元素之前第一个同级元素B,比如:div.
25、 hea d + divs i bl i ngA s i bl i ngX:查找A元素之前的同级X元素,比如:h1 pe l , e l , e l :多个选择器组合,查找匹配任一选择器的唯一元素,例如:div. m a s t hea d, div. l ogo伪选择器s e l e c t or s: l t ( n) :查找哪些元素的同级索引值(它的位置在D O M树中是相对于它的父节点)小于n,比如:t d:l t ( 3)表示小于三列的元素: gt ( n) :查找哪些元素的同级索引值大于n,比如:div p:gt ( 2)表示哪些div中有包含2个以上的p元素: e q( n) :
26、查找哪些元素的同级索引值与n相等,比如:f or m i nput: e q( 1)表示包含一个i nput标签的F or m元素: ha s ( s e l e t or ) :查找匹配选择器包含元素的元素,比如:div: has ( p)表示哪些div包含了p元素: not( s e l e c t or) :查找与选择器不匹配的元素,比如:div: not( . l ogo)表示不包含c l a s s = l ogo元素的所有div列表: c onta i ns ( t e xt ) :查找包含给定文本的元素,搜索不区分大不写,比如:p:c onta i ns ( j s oup):
27、c onta i ns O w n( t e xt ) :查找直接包含给定文本的元素: m a t c hes ( r e gex) :查找哪些元素的文本匹配指定的正则表达式,比如:div: m a t c hes ( ( ? i ) l ogin): m a t c hes O w n( r e gex) :查找自身包含文本匹配指定正则表达式的元素注意:上述伪选择器索引是从0开始的,也就是说第一个元素索引值为0,第二个元素i ndex为1等可以查看S e l e c t or A P I参考来了解更详细的内容从元素抽取属性,文本和H T ML问题在解析获得一个D oc um e nt实例对象
28、,并查找到一些元素之后,你希望取得在这些元素中的数据。方法要取得一个属性的值,可以使用N ode. a t t r ( S t r i ng key)方法对于一个元素中的文本,可以使用E l e m e nt . t e xt ( )方法对于要取得元素或属性中的H T ML内容,可以使用E l e m e nt . ht m l ( ) ,或N ode. oute r Ht m l ( )方法示例:S t r i ng ht m l = “ A n e xam ple l i nk.“ ;D oc um e nt doc= J s oup.par s e ( ht m l ) ; / /解析H
29、 T ML字符串返回一个D ocum e nt实现E l e m e nt l i nk = doc. s e l e c t ( “ a “ ) . f i r s t ( ) ; / /查找第一个a元素S t r i ng t e xt = doc. body() . t e xt ( ) ; / / “ A n e xam pl e l i nk“/ /取得字符串中的文本S t r i ng l i nkHr e f = l i nk.a t t r ( “ hr e f “ ) ; / / “ ht t p: / / e xam pl e . c om / “ / /取得链接地址S t
30、 r i ng l i nkTe xt = l i nk.t e xt ( ) ; / / “ e xa m ple “ “ / /取得链接地址中的文本S t r i ng l i nkOut e r H = l i nk.oute r H t m l ( ) ;/ / “ e xam ple “S t r i ng l i nkInner H = l i nk.ht m l ( ) ; / / “ e xam pl e “ / /取得链接内的ht m l内容说明上述方法是元素数据访问的核心办法。此外还其它一些方法可以使用:E l e m e nt . i d( )E l e m e nt .
31、 t a gNa m e ( )E l e m e nt . c l a s s N a m e ( ) a nd E l e m e nt . has C l a s s ( S t r i ng c l a s s N a m e )这些访问器方法都有相应的s e t t e r方法来更改数据.处理U R L s问题你有一个包含相对UR L s路径的H T ML文档,需要将这些相对路径转换成绝对路径的U R L s。方法在你解析文档时确保有指定bas e UR I,然后使用a bs :属性前缀来取得包含bas e U R I的绝对路径。代码如下:D oc um e nt doc= J s
32、oup.c onnec t ( “ ht t p:/ / w w w . open- open. c om “ ) . get ( ) ;E l e m e nt l i nk = doc. s e l e c t ( “ a “ ) . f i r s t ( ) ;S t r i ng r e l H r e f = l i nk.a t t r ( “ hr e f “ ) ; / / = = “ / “S t r i ng a bs Hr e f = l i nk.a t t r ( “ a bs : hr e f “ ) ; / / “ ht t p: / / w w w . ope
33、n-open. c om / “说明在H T ML元素中,U R L s经常写成相对于文档位置的相对路径: . . . .当你使用N ode. a t t r ( S t r i ng key)方法来取得a元素的hr e f属性时,它将直接返回在HT ML源码中指定定的值。假如你需要取得一个绝对路径,需要在属性名前加a bs :前缀。这样就可以返回包含根路径的U R L地址a t t r ( “ a bs : hr e f “ )因此,在解析H T ML文档时,定义bas e UR I非常重要。如果你不想使用a bs :前缀,还有一个方法能够实现同样的功能N ode. a bs Ur l (
34、S t r i ng key)。设置属性的值问题在你解析一个D oc um e nt之后可能想修改其中的某些属性值,然后再保存到磁盘或都输出到前台页面。方法可以使用属性设置方法E l e m e nt . a t t r ( S t r i ng key, S t r i ng val ue) ,和E l e m e nt s . a t t r ( S t r i ng key,S t r i ng val ue) .假如你需要修改一个元素的c l a s s属性,可以使用E l e m e nt . a ddCl a s s ( S t r i ng c l a s s N a m e )
35、和E l e m e nt . r e m oveC l a s s ( S t r i ng c l a s s N a m e )方法。E l e m e nt s提供了批量操作元素属性和c l a s s的方法,比如:要为div中的每一个a元素都添加一个r e l = “ nofoll ow“可以使用如下方法:doc. s e l e c t ( “ div. c om m e nt s a “ ) . a t t r ( “ r e l “ , “ nofol l ow“ ) ;说明与E l e m e nt中的其它方法一样,a t t r方法也是返回当E l e m e nt (或在
36、使用选择器是返回E l e m e nt s集合)。这样能够很方便使用方法连用的书写方式。比如:doc. s e l e c t ( “ div. m a s t hea d“) . a t t r ( “ t i t l e “ , “ j s oup“) . a ddCl a s s ( “ r ound-box“) ;设置一个元素的H T ML内容问题你需要一个元素中的H T ML内容方法可以使用E l e m e nt中的H T ML设置方法具体如下:E l e m e nt div = doc. s e l e c t ( “ div“) . f i r s t ( ) ; / /
37、div. ht m l ( “ l or e m i ps um “ ) ; / / l or e m i ps um div. pr e pend(“ F i r s t “ ) ; / /在div前添加ht m l内容div. a ppend(“ L a s t “ ) ; / /在div之后添加ht m l内容/ /添完后的结果: F i r s t l or e m i ps um L a s t E l e m e nt s pan = doc. s e l e c t ( “ s pan“) . f i r s t ( ) ; / / O nes pan. w r a p( “ “
38、 ) ;/ /添完后的结果: O ne 说明E l e m e nt . ht m l ( S t r i ng ht m l )这个方法将先清除元素中的H T ML内容,然后用传入的HT ML代替。E l e m e nt . pr e pend(S t r i ng f i r s t )和E l e m e nt . a ppend(S t r i ng l a s t )方法用于在分别在元素内部H T ML的前面和后面添加HT ML内容E l e m e nt . w r a p( S t r i ng a r ound)对元素包裹一个外部HT ML内容。设置元素的文本内容问题你需要修
39、改一个H T ML文档中的文本内容方法可以使用E l e m e nt的设置方法::E l e m e nt div = doc. s e l e c t ( “ div“) . f i r s t ( ) ; / / div. t e xt ( “ f i ve f our“ ) ; / / f i ve f ourdiv. pr e pend(“ F i r s t “ ) ;div. a ppend(“ L a s t “ ) ;/ / now: F i r s t f i ve f our L a s t 说明文本设置方法与H T ML s e t t e r方法一样:E l e m
40、e nt . t e xt ( S t r i ng t e xt )将清除一个元素中的内部HT ML内容,然后提供的文本进行代替E l e m e nt . pr e pend(S t r i ng f i r s t )和E l e m e nt . a ppend(S t r i ng l a s t )将分别在元素的内部ht m l前后添加文本节点。对于传入的文本如果含有像等这样的字符,将以文本处理,而非H T ML。消除不受信任的H T ML (来防止X S S攻击)问题在做网站的时候,经常会提供用户评论的功能。有些不怀好意的用户,会搞一些脚本到评论内容中,而这些脚本可能会破坏整个页
41、面的行为,更严重的是获取一些机要信息,此时需要清理该H T ML,以避免跨站脚本c r oss - s i t e s c r i pt i ng攻击(X S S)。方法使用j s oup H T ML C l e a ner方法进行清除,但需要指定一个可配置的Whi t e l i s t。S t r i ng unsa f e =“ L i nk “ ;S t r i ng s a f e = J s oup.c l e a n( unsa f e , Whi t e l i s t . bas i c ( ) ) ;/ / now: L i nk 说明X S S又叫C S S ( C r
42、 os s S i t e S c r i pt ),跨站脚本攻击。它指的是恶意攻击者往We b页面里插入恶意ht m l代码,当用户浏览该页之时,嵌入其中We b里面的ht m l代码会被执行,从而达到恶意攻击用户的特殊目的。X S S属于被动式的攻击,因为其被动且不好利用,所以许多人常忽略其危害性。所以我们经常只让用户输入纯文本的内容,但这样用户体验就比较差了。一个更好的解决方法就是使用一个富文本编辑器WY S I WY G如C K E di t or和T i nyMC E。这些可以输出H T ML并能够让用户可视化编辑。虽然他们可以在客户端进行校验,但是这样还不够安全,需要在服务器端进行校验并清除有害的H T ML代码,这样才能确保输入到你网站的H T ML是安全的。否则,攻击者能够绕过客户端的J a vas c r i pt验证,并注入不安全的H MT L直接进入您的网站。j s oup的w hit e l i s t清理器能够在服务器端对用户输入的HT ML进行过滤,只输出一些安全的标签和属性。j s oup提供了一系列的Whi t e l i s t基本配置,能够满足大多数要求;但如有必要,也可以进行修改,不过要小心。这个c l e a ner非常好用不仅可以避免X S S攻击,还可以限制用户可以输入的标签范围。