時候編輯器傳到后臺的內容是帶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 >jsoup</a></h4></li> <li class="n1-news"><a >新聞</a></li> <li class="n1-bugs"><a >bugs</a></li> <li class="n1-discussion"><a >討論</a></li> <li class="n1-download"><a >下載</a></li> <li class="n1-api"><a >api參考</a></li> <li class="n1-cookbook"><a >Cookbook</a></li></ul> </div></div> <div class="breadcrumb"><a >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 >解析和遍歷一個html文檔</a></li> </ol> <h3>輸入</h3> <ol start="2"> <li><a >解析一個html字符串</a></li> <li><a >解析一個body片斷</a></li> <li><a >根據一個url加載Document對象</a></li> <li><a >根據一個文件加載Document對象</a></li> </ol> <h3>數據抽取</h3> <ol start="6"> <li><a >使用dom方法來遍歷一個Document對象</a></li> <li><a >使用選擇器語法來查找元素</a></li> <li><a >從元素集合抽取屬性、文本和html內容</a></li> <li><a >URL處理</a></li> <li><a >程序示例:獲取所有鏈接</a></li> </ol> <h3>數據修改</h3> <ol start="11"> <li><a >設置屬性值</a></li> <li><a >設置元素的html內容</a></li> <li><a >設置元素的文本內容</a></li> </ol> <h3> html清理</h3> <ol start="14"> <li><a >消除不受信任的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 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小時內與您取得聯系。