时候编辑器传到后台的内容是带Html标签的,或者有时候需要形成一个完整的Html文档,也或者需要解析其中的文字(text()),Java后台处理用Jsoup非常方便,也可以用选择器快速获取元素,类似于jQuery。获取到文档对此之后对其处理与JS处理DOM一样方便,选取元素也类似于JS,也有类似于jQuery的语法,官方的解释
1.最基本的解析Html字符串
@Test public void testHtmlToString2() { String html = "<p>这是一个段落<img src=\"test.img\"/>内容;</p>"; Document doc = Jsoup.parse(html); System.out.println(doc); // 输出带标签的html文档 System.out.println("---------------------\n"+doc.text()); // 输出内容 Elements element = doc.getElementsByTag("p"); System.out.println("---------------------\n"+element.get(0).html()); }
结果:
<html> <head></head> <body> <p>这是一个段落<img src="test.img">内容;</p> </body> </html> --------------------- 这是一个段落内容; --------------------- 这是一个段落<img src="test.img">内容;
2.解析字符串
// 解析html字符串 @Test public void testHtmlToString() { String html = "<html><head><title>First parse</title></head>" + "<body><p style='center'>Parsed HTML into a doc.</p></body></html>"; Document doc = Jsoup.parse(html); System.out.println(doc); // 输出带标签的html文档 System.out.println("---------------------\n"+doc.text()); // 输出内容 }
结果:
<html>
<head>
<title>First parse</title>
</head>
<body>
<p style="center">Parsed HTML into a doc.</p>
</body>
</html>
---------------------
First parse Parsed HTML into a doc.
3.// 解析body片段
@Test public void test2() { String html = "<div><p>Lorem ipsum.</p>"; Document doc = Jsoup.parseBodyFragment(html); System.out.println(doc); System.out.println(doc.text()); }
结果:
<html>
<head></head>
<body>
<div>
<p>Lorem ipsum.</p>
</div>
</body>
</html>
Lorem ipsum.
4.// 解析一个url与用选择器选择元素(相当于查看源码)
@Test public void test4() throws IOException { Document doc = Jsoup.connect("http://qiaoliqiang.cn:8080/").get(); String title = doc.title();// 获取title System.out.println(title); System.out.println("---------------------\n"+doc.toString()+"---------------------\n");// 输出文档全部 Elements links = doc.getElementsByTag("a"); for (Element ele : links) { System.out.println(ele.toString()); } }
Apache Tomcat/7.0.72
---------------------
<!doctype html>
<html lang="en">
<head>
<title>Apache Tomcat/7.0.72</title>
<link href="favicon.ico" rel="icon" type="image/x-icon">
<link href="favicon.ico" rel="shortcut icon" type="image/x-icon">
..........
5.选择器解析HTML并且提取input的value值:(获取元素的属性)
/** * <span class="bigNum">二</span>、 * <span><input class="el_modifiedTitle" value="多选题" type="text"> </span> * <span>(每到题 <input class="el_modifiedGrade" value="2" type="text"> </span> * <span> 分;共</span><span class="numTotal">4分/</span> * <span class="numQues">2题)</span> * * @param html * @return */ // 去掉大题的标签 public static String removeBigQues(String html) { StringBuffer sb = new StringBuffer(); Document doc = Jsoup.parse(html); System.out.println(doc); System.out.println(doc.text()); sb.append(doc.select(".bigNum").get(0).text() + ". "); sb.append(doc.select(".el_modifiedTitle").get(0).attr("value")); sb.append(doc.select("span").get(2).text() + doc.select(".el_modifiedGrade").get(0).attr("value")); sb.append(doc.select("span").get(3).text()); sb.append(doc.select("span").get(4).text()); sb.append(doc.select("span").get(5).text()); System.out.println(sb.toString()); return sb.toString(); }
补充:今天发现Jsoup竟然没有解析元素style的方法,所以只能自己手写
先获取到style属性,再对style属性进行处理,例如:
String style = "position: absolute; width: 500px; height: 552px;"; String extract = "width"; if (style.contains(extract)) { style = style.substring(style.indexOf(extract)); System.out.println(style); style = style.substring(0, style.indexOf(";")); System.out.println(style); String attr = style.substring(style.indexOf(":") + 2); System.out.println(attr.substring(0, attr.indexOf("px"))); }
补充:元素的html()与outerHtml()的区别
html()会返回包括子元素的内容以及标签,不包括自己
outerHtml()会返回包括自己在内的元素。
在jQuery中如果返回子元素的内容也是html(),如果返回包括自己的内容需要用$("#chartdiv").prop("outerHTML");//会返回包括自己在内的内容
soup简介
jsoup 是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
官网地址:
http://jsoup.org/
在官网中下载 jsou-1.8.3.jar
文件,添加到自己项目的lib库中,便可使用Jsoup提供的api,官网中也提供了一套使用指南(Cookbook),便于开发者借鉴。
Jsoup解析HTML得到一个Document对象,通过操作Document的属性来获取HTML页面内容,所以,在开始之前,先介绍一下XML中Node、Element、Document等这些相关概念的区别,防止因概念混淆而导致乱用错用。
相关概念
Jsoup中的继承关系
public abstract class Node implements Cloneable
public class Element extends Node
public class Document extends Element
从Jsoup源码对三者的定义可以看出如下一个树形继承关系:
Node(节点)
从上述继承关系上可以明确一点,文档中的所有内容都可以看做是一个节点。节点有很多种类型:属性节点(Attribute)、注释节点(Note)、文本节点(Text)、元素节点(Element)等,通常所说的节点是这些多种节点的统称。
Element(元素)
相比节点而言,元素则是一个更小范围的定义。元素继承于节点,是节点的子集,所以一个元素也是一个节点,节点拥有的公有属性和方法在元素中也能使用。
Document(文档)
文档继承于元素,指整个HTML文档的源码内容,通过 System.out.println(document.toString());
即可在控制台打印出网页源码内容。
相互转换
基于Node、Element和Document之间的“缠绵”关系,可以利用各个类中提供的方法适当转换获取所需对象,以供使用。
使用案例
Jsoup解析Html获取Document对象的方式分为三类:在线Url、Html文本字符串、文件,对应API如下
connect(String url)
parse(String html)
parse(File in, String charsetName)
在获取到Document对象之后,可以结合HTML源码,利用Jsoup提供的api通过class、tag、id、attribute等相关属性获取对应Element,进而得到所需要的网页内容。
下面以Jsoup的官网Cookbook页面为例,解析并获取页面目录内容。
网页内容:
网页源码:
<!DOCTYPE html> <!-- saved from url=(0031)http://www.open-open.com/jsoup/ --> <html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>jsoup开发指南,jsoup中文使用手册,jsoup中文文档</title> <meta name="keywords" content="jsoup开发指南,jsoup中文使用手册,jsoup中文文档,jsoup java html解析器"> <meta name="description" content="jsoup Cookbook中文版 - 由http://www.open-open.com翻译整理"><link rel="stylesheet" type="text/css" href="./jsoup开发指南,jsoup中文使用手册,jsoup中文文档_files/style.css"> </head><body class="n1-cookbook"> <div class="wrap"> <div class="header"> <div class="nav-sections"> <ul> <li class="n1-home"> <h4><a href="http://jsoup.org/">jsoup</a></h4></li> <li class="n1-news"><a href="http://jsoup.org/news/">新闻</a></li> <li class="n1-bugs"><a href="http://jsoup.org/bugs">bugs</a></li> <li class="n1-discussion"><a href="http://jsoup.org/discussion">讨论</a></li> <li class="n1-download"><a href="http://jsoup.org/download">下载</a></li> <li class="n1-api"><a href="http://jsoup.org/apidocs/">api参考</a></li> <li class="n1-cookbook"><a href="http://jsoup.org/cookbook/">Cookbook</a></li></ul> </div></div> <div class="breadcrumb"><a href="http://jsoup.org/">jsoup</a> <span class="seperator">»</span> cookbook </div> <div class="content"> <div class="col1"> <h1>jsoup Cookbook(中文版)</h1> <div class="toc"> <h3>入门</h3> <ol start="1"> <li><a href="http://www.open-open.com/jsoup/parsing-a-document.htm">解析和遍历一个html文档</a></li> </ol> <h3>输入</h3> <ol start="2"> <li><a href="http://www.open-open.com/jsoup/parse-document-from-string.htm">解析一个html字符串</a></li> <li><a href="http://www.open-open.com/jsoup/parse-body-fragment.htm">解析一个body片断</a></li> <li><a href="http://www.open-open.com/jsoup/load-document-from-url.htm">根据一个url加载Document对象</a></li> <li><a href="http://www.open-open.com/jsoup/load-document-from-file.htm">根据一个文件加载Document对象</a></li> </ol> <h3>数据抽取</h3> <ol start="6"> <li><a href="http://www.open-open.com/jsoup/dom-navigation.htm">使用dom方法来遍历一个Document对象</a></li> <li><a href="http://www.open-open.com/jsoup/selector-syntax.htm">使用选择器语法来查找元素</a></li> <li><a href="http://www.open-open.com/jsoup/attributes-text-html.htm">从元素集合抽取属性、文本和html内容</a></li> <li><a href="http://www.open-open.com/jsoup/working-with-urls.htm">URL处理</a></li> <li><a href="http://www.open-open.com/jsoup/example-list-links.htm">程序示例:获取所有链接</a></li> </ol> <h3>数据修改</h3> <ol start="11"> <li><a href="http://www.open-open.com/jsoup/set-attributes.htm">设置属性值</a></li> <li><a href="http://www.open-open.com/jsoup/set-html.htm">设置元素的html内容</a></li> <li><a href="http://www.open-open.com/jsoup/set-text.htm">设置元素的文本内容</a></li> </ol> <h3> html清理</h3> <ol start="14"> <li><a href="http://www.open-open.com/jsoup/whitelist-sanitizer.htm">消除不受信任的html (来防止xss攻击)</a></li> </ol><script src="./jsoup开发指南,jsoup中文使用手册,jsoup中文文档_files/ca-pub-7963911354665843.js"></script><script type="text/javascript"><!-- google_ad_client = "pub-7963911354665843"; /* 728x90, 创建于 11-1-27 */ google_ad_slot = "5890482646"; google_ad_width = 728; google_ad_height = 90; //--> </script> <script type="text/javascript" src="./jsoup开发指南,jsoup中文使用手册,jsoup中文文档_files/show_ads.js"> </script><ins id="aswift_0_expand" style="display:inline-table;border:none;height:90px;margin:0;padding:0;position:relative;visibility:visible;width:728px;background-color:transparent"><ins id="aswift_0_anchor" style="display:block;border:none;height:90px;margin:0;padding:0;position:relative;visibility:visible;width:728px;background-color:transparent"><iframe width="728" height="90" frameborder="0" marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no" allowfullscreen="true" onload="var i=this.id,s=window.google_iframe_oncopy,H=s&&s.handlers,h=H&&H[i],w=this.contentWindow,d;try{d=w.document}catch(e){}if(h&&d&&(!d.body||!d.body.firstChild)){if(h.call){setTimeout(h,0)}else if(h.match){try{h=s.upd(h,i)}catch(e){}w.location.replace(h)}}" id="aswift_0" name="aswift_0" style="left:0;position:absolute;top:0;"></iframe></ins></ins></div></div> <div class="col2"></div></div> <div class="footer"><b>jsoup</b> html parser: copyright © 2009 - 2011 <a href="http://www.open-open.com/" rel="me"><b>jonathan hedley</b></a> </div></div> </body></html>Jsoup解析:
import java.io.IOException; import java.text.ParseException; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; /** * @author 亦枫 * @created_time 2016年1月5日 * @file_user_todo Java测试类 * @blog http://www.jianshu.com/users/1c40186e3248/latest_articles */ public class JavaTest { /** * 入口函数 * @param args * @throws ParseException */ public static void main(String[] args) throws ParseException { try { //解析Url获取Document对象 Document document = Jsoup.connect("http://www.open-open.com/jsoup/").get(); //获取网页源码文本内容 System.out.println(document.toString()); //获取指定class的内容指定tag的元素 Elements liElements = document.getElementsByClass("content").get(0).getElementsByTag("li"); for (int i = 0; i < liElements.size(); i++) { System.out.println(i + ". " + liElements.get(i).text()); } } catch (IOException e) { System.out.println("解析出错!"); e.printStackTrace(); } } }解析结果:
soup是一款Java的HTML解析器,主要用来对HTML解析。
在爬虫的时候,当我们用HttpClient之类的框架,获取到网页源码之后,需要从网页源码中取出我们想要的内容,
就可以使用jsoup这类HTML解析器了。可以非常轻松的实现。
虽然jsoup也支持从某个地址直接去爬取网页源码,但是只支持HTTP,HTTPS协议,支持不够丰富。
所以,主要还是用来对HTML进行解析。
其中,要被解析的HTML可以是一个HTML的字符串,可以是一个URL,可以是一个文件。
org.jsoup.Jsoup把输入的HTML转换成一个org.jsoup.nodes.Document对象,然后从Document对象中取出想要的元素。
org.jsoup.nodes.Document继承了org.jsoup.nodes.Element,Element又继承了org.jsoup.nodes.Node类。里面提供了丰富的方法来获取HTML的元素。
从URL获取HTML来解析
Document doc = Jsoup.connect("http://www.baidu.com/").get();
String title = doc.title();
其中Jsoup.connect("xxx")方法返回一个org.jsoup.Connection对象。
在Connection对象中,我们可以执行get或者post来执行请求。但是在执行请求之前,
我们可以使用Connection对象来设置一些请求信息。比如:头信息,cookie,请求等待时间,代理等等来模拟浏览器的行为。
Document doc = Jsoup.connect("http://example.com")
.data("query", "Java")
.userAgent("Mozilla")
.cookie("auth", "token")
.timeout(3000)
.post();
获得Document对象后,接下来就是解析Document对象,并从中获取我们想要的元素了。
Document中提供了丰富的方法来获取指定元素。
使用DOM的方式来取得
getElementById(String id):通过id来获取
getElementsByTag(String tagName):通过标签名字来获取
getElementsByClass(String className):通过类名来获取
getElementsByAttribute(String key):通过属性名字来获取
getElementsByAttributeValue(String key, String value):通过指定的属性名字,属性值来获取
getAllElements():获取所有元素
通过类似于css或jQuery的选择器来查找元素
使用的是Element类的下记方法:
public Elements select(String cssQuery)
通过传入一个类似于CSS或jQuery的选择器字符串,来查找指定元素。
例子:
File input = new File("/tmp/input.html");
Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
Elements links = doc.select("a[href]"); //带有href属性的a元素
Elements pngs = doc.select("img[src$=.png]");
//扩展名为.png的图片
Element masthead = doc.select("div.masthead").first();
//class等于masthead的div标签
Elements resultLinks = doc.select("h3.r > a"); //在h3元素之后的a元素
选择器的更多语法(可以在org.jsoup.select.Selector中查看到更多关于选择器的语法):
tagname: 通过标签查找元素,比如:a
ns|tag: 通过标签在命名空间查找元素,比如:可以用 fb|name 语法来查找 <fb:name> 元素
#id: 通过ID查找元素,比如:#logo
.class: 通过class名称查找元素,比如:.masthead
[attribute]: 利用属性查找元素,比如:[href]
[^attr]: 利用属性名前缀来查找元素,比如:可以用[^data-] 来查找带有HTML5 Dataset属性的元素
[attr=value]: 利用属性值来查找元素,比如:[width=500]
[attr^=value], [attr$=value], [attr=value]: 利用匹配属性值开头、结尾或包含属性值来查找元素,比如:[href=/path/]
[attr~=regex]: 利用属性值匹配正则表达式来查找元素,比如: img[src~=(?i).(png|jpe?g)]
*: 这个符号将匹配所有元素
Selector选择器组合使用
el#id: 元素+ID,比如: div#logo
el.class: 元素+class,比如: div.masthead
el[attr]: 元素+class,比如: a[href]
任意组合,比如:a[href].highlight
ancestor child: 查找某个元素下子元素,比如:可以用.body p 查找在"body"元素下的所有 p元素
parent > child: 查找某个父元素下的直接子元素,比如:可以用div.content > p 查找 p 元素,也可以用body > * 查找body标签下所有直接子元素
siblingA + siblingB: 查找在A元素之前第一个同级元素B,比如:div.head + div
siblingA ~ siblingX: 查找A元素之前的同级X元素,比如:h1 ~ p
el, el, el:多个选择器组合,查找匹配任一选择器的唯一元素,例如:div.masthead, div.logo
伪选择器selectors
:lt(n): 查找哪些元素的同级索引值(它的位置在DOM树中是相对于它的父节点)小于n,比如:td:lt(3) 表示小于三列的元素
:gt(n):查找哪些元素的同级索引值大于n,比如: div p:gt(2)表示哪些div中有包含2个以上的p元素
:eq(n): 查找哪些元素的同级索引值与n相等,比如:form input:eq(1)表示包含一个input标签的Form元素
:has(seletor): 查找匹配选择器包含元素的元素,比如:div:has(p)表示哪些div包含了p元素
:not(selector): 查找与选择器不匹配的元素,比如: div:not(.logo) 表示不包含 class="logo" 元素的所有 div 列表
:contains(text): 查找包含给定文本的元素,搜索不区分大不写,比如: p:contains(jsoup)
:containsOwn(text): 查找直接包含给定文本的元素
:matches(regex): 查找哪些元素的文本匹配指定的正则表达式,比如:div:matches((?i)login)
:matchesOwn(regex): 查找自身包含文本匹配指定正则表达式的元素
注意 :上述伪选择器索引是从0开始的,也就是说第一个元素索引值为0,第二个元素index为1等
通过上面的选择器,我们可以取得一个Elements对象,它继承了ArrayList对象,里面放的全是Element对象。
接下来我们要做的就是从Element对象中,取出我们真正需要的内容。
通常有下面几种方法:
Element.text()
这个方法用来取得一个元素中的文本。
Element.html()或Node.outerHtml()
这个方法用来取得一个元素中的html内容
Node.attr(String key)
获得一个属性的值,例如取得超链接<a href="">中href的值
为了让大家更快速高效的学习,我整理了一份 Java 全能资料包含(高可用、高并发、高性能及分布式、 Jvm 性能调优、 Spring 源码, MyBatis , Netty , Redis , Kafka , Mysql , Zookeeper , Tomcat , Docker , Dubbo , Nginx ,架构,面试等等…)
*请认真填写需求信息,我们会在24小时内与您取得联系。