在上一篇隨筆《Java爬蟲系列二:使用HttpClient抓取頁面HTML》中介紹了怎么使用HttpClient進行爬蟲的第一步--抓取頁面html俘侠,今天接著來看下爬蟲的第二步--解析抓取到的html彬向。
有請第二步的主角:Jsoup粉墨登場娃胆。
一、Jsoup自我介紹
大家好凿蒜,我是Jsoup废封。
我是一款Java 的HTML解析器丧蘸,可直接解析某個URL地址、HTML文本內(nèi)容刽漂。它提供了一套非常省力的API弟孟,可通過DOM拂募,CSS以及類似于jQuery的操作方法來取出和操作數(shù)據(jù)窟她,用Java寫爬蟲的同行們十之八九用過我震糖。為什么呢试伙?因為我在這個方面功能強大于样、使用方便穿剖。不信的話卦溢,可以繼續(xù)往下看糊余,代碼是不會騙人的。
二单寂、Jsoup解析html
上一篇中贬芥,HttpClient大哥已經(jīng)抓取到了博客園首頁的html,但是一堆的代碼宣决,不是程序員的人們怎么能看懂呢蘸劈?這個就需要html解析專家出場了。
下面通過案例展示如何使用Jsoup進行解析尊沸,案例中將獲取博客園首頁的標(biāo)題和第一頁的博客文章列表
請看代碼(在上一篇代碼的基礎(chǔ)上進行操作威沫,如果還不知道如何使用httpclient的朋友請?zhí)D(zhuǎn)頁面進行閱讀):
引入依賴
<dependency>
? ? <groupId>org.jsoup</groupId>
? ? <artifactId>jsoup</artifactId>
? ? <version>1.12.1</version>
</dependency>
實現(xiàn)代碼。實現(xiàn)代碼之前首先要分析下html結(jié)構(gòu)棒掠。標(biāo)題是<title>不用說了,那文章列表呢屁商?按下瀏覽器的F12烟很,查看頁面元素源碼,你會發(fā)現(xiàn)列表是一個大的div蜡镶,id="post_list",每篇文章是小的div,class="post_item"
接下來就可以開始代碼了雾袱,Jsoup核心代碼如下:
/**
? ? ? ? ? ? ? ? * 下面是Jsoup展現(xiàn)自我的平臺
? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? //6.Jsoup解析html
? ? ? ? ? ? ? ? Document document = Jsoup.parse(html);
? ? ? ? ? ? ? ? //像js一樣,通過標(biāo)簽獲取title
? ? ? ? ? ? ? ? System.out.println(document.getElementsByTag("title").first());
? ? ? ? ? ? ? ? //像js一樣帽哑,通過id 獲取文章列表元素對象
? ? ? ? ? ? ? ? Element postList = document.getElementById("post_list");
? ? ? ? ? ? ? ? //像js一樣谜酒,通過class 獲取列表下的所有博客
? ? ? ? ? ? ? ? Elements postItems = postList.getElementsByClass("post_item");
? ? ? ? ? ? ? ? //循環(huán)處理每篇博客
? ? ? ? ? ? ? ? for (Element postItem : postItems) {
? ? ? ? ? ? ? ? ? ? //像jquery選擇器一樣,獲取文章標(biāo)題元素
? ? ? ? ? ? ? ? ? ? Elements titleEle = postItem.select(".post_item_body a[class='titlelnk']");
? ? ? ? ? ? ? ? ? ? System.out.println("文章標(biāo)題:" + titleEle.text());;
? ? ? ? ? ? ? ? ? ? System.out.println("文章地址:" + titleEle.attr("href"));
? ? ? ? ? ? ? ? ? ? //像jquery選擇器一樣僻族,獲取文章作者元素
? ? ? ? ? ? ? ? ? ? Elements footEle = postItem.select(".post_item_foot a[class='lightblue']");
? ? ? ? ? ? ? ? ? ? System.out.println("文章作者:" + footEle.text());;
? ? ? ? ? ? ? ? ? ? System.out.println("作者主頁:" + footEle.attr("href"));
? ? ? ? ? ? ? ? ? ? System.out.println("*********************************");
? ? ? ? ? ? ? ? }
根據(jù)以上代碼你會發(fā)現(xiàn)述么,我通過Jsoup.parse(String html)方法對httpclient獲取到的html內(nèi)容進行解析獲取到Document度秘,然后document可以有兩種方式獲取其子元素:像js一樣 可以通過getElementXXXX的方式 和 像jquery 選擇器一樣通過select()方法。 無論哪種方法都可以唆貌,我個人推薦用select方法處理锨咙。對于元素中的屬性酪刀,比如超鏈接地址钮孵,可以使用element.attr(String)方法獲取巴席, 對于元素的文本內(nèi)容通過element.text()方法獲取情妖。
執(zhí)行代碼,查看結(jié)果(不得不感慨博客園的園友們真是太厲害了毡证,從上面分析首頁html結(jié)構(gòu)到Jsoup分析的代碼執(zhí)行完,這段時間首頁多了那么多文章)
三丐箩、Jsoup的其他用法
我恤煞,Jsoup,除了可以在httpclient大哥的工作成果上發(fā)揮作用概漱,我還能自己獨立干活喜喂,自己抓取頁面,然后自己分析腻异。分析的本領(lǐng)已經(jīng)在上面展示過了悔常,下面來展示自己抓取頁面机打,其實很簡單姐帚,所不同的是我直接獲取到的是document,不用再通過Jsoup.parse()方法進行解析了唯蝶。
除了能直接訪問網(wǎng)上的資源粘我,我還能解析本地資源:
代碼:
public static void main(String[] args) {
? ? ? ? try {
? ? ? ? ? ? Document document = Jsoup.parse(new File("d://1.html"), "utf-8");
? ? ? ? ? ? System.out.println(document);
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
四、Jsoup另一個值得一提的功能
你肯定有過這種經(jīng)歷痹换,在你的頁面文本框中征字,如果輸入html元素的話娇豫,保存后再查看很大概率會導(dǎo)致頁面排版亂七八糟,如果能對這些內(nèi)容進行過濾的話冯痢,就完美了氮昧。
剛好我Jsoup就能做到浦楣。
public static void main(String[] args) {
? ? ? ? String unsafe = "<p><a href='網(wǎng)址' onclick='stealCookies()'>博客園</a></p>";
? ? ? ? System.out.println("unsafe: " + unsafe);
? ? ? ? String safe = Jsoup.clean(unsafe, Whitelist.basic());
? ? ? ? System.out.println("safe: " + safe);
? ? }
通過Jsoup.clean方法袖肥,用一個白名單進行過濾。執(zhí)行結(jié)果:
unsafe: <p><a href='網(wǎng)址' onclick='stealCookies()'>博客園</a></p>
safe: <p><a rel="nofollow">博客園</a></p>
五振劳、結(jié)束語
不僅可以解析HttpClient抓取到的html元素,自己也能抓取頁面dom历恐,還能load并解析本地保存的html文件。
此外灵份,還能通過一個白名單對字符串進行過濾弦聂,篩掉一些不安全的字符氛什。
最最重要的,上面所有功能的API的調(diào)用都比較簡單捺檬。