都知道爬蟲用python盗蟆,Java 爬蟲你會嗎?

在這篇文章中舒裤,將詳細(xì)介紹 Jsoup 的相關(guān)知識喳资,包括其功能與特點(diǎn)、基本用法腾供、高級應(yīng)用仆邓、原理分析、相關(guān)工具及框架等方面伴鳖。

一节值、功能與特點(diǎn)

Jsoup 是一個用于解析 HTML 的 Java 庫,提供了一組易于使用的 API 和方法榜聂,能夠方便地從網(wǎng)頁中提取出所需數(shù)據(jù)搞疗,以便于 Web 抓取和數(shù)據(jù)挖掘等領(lǐng)域的應(yīng)用。其主要功能如下:

  1. 解析 HTML:Jsoup 可以將 HTML 文檔解析成一個 DOM 樹须肆,便于后續(xù)操作匿乃。

  2. 查找元素:Jsoup 提供了多種查找元素的方法桩皿,包括根據(jù)標(biāo)簽名、屬性名幢炸、類名泄隔、ID 等查找方式。

  3. 獲取元素信息:Jsoup 可以獲取元素的屬性和文本內(nèi)容宛徊。

  4. 操作 DOM 樹:Jsoup 可以對 DOM 樹進(jìn)行添加佛嬉、刪除、修改節(jié)點(diǎn)等操作闸天。

  5. 支持 CSS 選擇器:Jsoup 可以使用 CSS 選擇器語法查找元素暖呕。

  6. 支持鏈?zhǔn)秸{(diào)用:Jsoup 的 API 設(shè)計(jì)簡單易用,支持鏈?zhǔn)秸{(diào)用号枕,代碼清晰簡潔缰揪。

  7. 支持 UTF-8 編碼:Jsoup 默認(rèn)采用 UTF-8 編碼處理文本,能夠處理中文等特殊字符葱淳。

二钝腺、基本用法

  1. 導(dǎo)入 Jsoup

在 Java 代碼中使用 Jsoup 需要先導(dǎo)入 Jsoup 相關(guān)的依賴庫,可以通過 Maven 或手動安裝兩種方式來實(shí)現(xiàn)赞厕。例如使用 Maven 導(dǎo)入 Jsoup:

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>x.x.x</version>
</dependency>

其中 x.x.x 表示需要使用的 Jsoup 版本號艳狐。

  1. 連接 URL

Jsoup.connect(String url) 方法用于連接指定 URL,并返回一個 Connection 對象皿桑,其后可以鏈?zhǔn)秸{(diào)用其他參數(shù)設(shè)置方法進(jìn)行個性化定制毫目。例如:

Connection conn = Jsoup.connect("http://example.com/")
                     .userAgent("Mozilla")
                     .timeout(5000)
                     .referrer("http://google.com")
                     .header("Accept-Language", "en-US");

常用參數(shù)設(shè)置方法如下:

  • userAgent(String userAgent):設(shè)置用戶代理
  • timeout(int milliseconds):設(shè)置連接超時(shí)時(shí)間
  • ignoreHttpErrors(boolean ignore):是否忽略 HTTP 錯誤(404、500 等)
  • ignoreContentType(boolean ignore):是否忽略內(nèi)容類型
  • referrer(String referrer):設(shè)置 Referrer
  • headers(Map<String, String> headers):設(shè)置請求頭
  1. 獲取HTML內(nèi)容

Connection.get() 方法用于獲取與此連接對應(yīng)的 HTML 文檔诲侮,并返回一個 Document 對象镀虐。例如:

Document doc = Jsoup.connect("http://example.com/").get();

如果需要使用 POST 請求模聋,則可以使用 Connection.post() 方法:

Document doc = Jsoup.connect("http://example.com/login")
                     .data("username", "admin")
                     .data("password", "123456")
                     .post();

需要注意的是叮盘,如果提交表單時(shí)需要使用 enctype=”multipart/form-data” 類型耿战,則不能使用 Connection.data() 方法衅谷。

  1. 解析HTML內(nèi)容

Jsoup 提供了許多方法和工具來解析 HTML 內(nèi)容,例如根據(jù)標(biāo)簽名/屬性名/類名查找元素矿微、遍歷 DOM 樹座慰、獲取元素的屬性和文本內(nèi)容等仑氛。

  • 解析 HTML 字符串:parse(String html) 方法可用于解析一個 HTML 字符串坝疼,并將其轉(zhuǎn)換為 Document 對象搜贤。例如:

    String html = "<html><head><title>Jsoup Example</title></head><body><p>Hello World!</p></body></html>";
    Document doc = Jsoup.parse(html);
    
  • 查找元素:

    • Document.select(String cssQuery) 方法可以根據(jù) CSS 選擇器選取元素,返回一個 Elements 對象钝凶。例如:

      Elements links = doc.select("a[href]");
      
    • Element.getElementsByTag(String tag) 方法可用于根據(jù)標(biāo)簽名選取元素仪芒,返回一個 Elements 對象。例如:

      Elements paragraphs = doc.getElementsByTag("p");
      
    • Element.getElementsByAttribute(String key) 方法可用于根據(jù)屬性名選取元素,返回一個 Elements 對象桌硫。例如:

      Elements links = doc.getElementsByAttribute("href");
      
    • Element.getElementsByAttributeValue(String key, String value) 方法可用于根據(jù)屬性名和屬性值選取元素夭咬,返回一個 Elements 對象。例如:

      Elements links = doc.getElementsByAttributeValue("rel", "nofollow");
      
    • Element.getElementsByClass(String className) 方法可用于根據(jù)類名選取元素铆隘,返回一個 Elements 對象。例如:

      Elements images = doc.getElementsByClass("image");
      
  • 獲取元素信息:

    • Element.attr(String attributeKey) 方法可用于獲取元素的屬性值南用。例如:

      String href = link.attr("href");
      
    • Element.text() 方法可用于獲取元素的文本內(nèi)容膀钠。例如:

      String text = paragraph.text();
      
  • 迭代元素:

    • Elements.eachText() 方法將返回所有元素的文本內(nèi)容,以字符串形式返回裹虫。例如:

      String allText = doc.select("body").eachText().toString();
      
    • Elements.iterator() 方法返回一個迭代器肿嘲,用于遍歷元素集合。例如:

      Iterator<Element> iter = doc.select("a[href]").iterator();
      while (iter.hasNext()) {
          Element link = iter.next();
          String href = link.attr("href");
          System.out.println(href);
      }
      
  1. 操作DOM樹

Jsoup 提供了許多方法和工具來操作 DOM 樹筑公,例如添加雳窟、刪除、修改節(jié)點(diǎn)等操作匣屡。

  • 添加節(jié)點(diǎn):

    • Element.append(String html) 方法可用于向元素的末尾添加子元素封救。例如:

      Element div = doc.select("div").first();
      div.append("<p>Hello Jsoup</p>");
      
    • Element.prepend(String html) 方法可用于向元素的開頭添加子元素。例如:

      Element div = doc.select("div").first();
      div.prepend("<p>Hello Jsoup</p>");
      
    • Element.html(String html) 方法可用于替換元素內(nèi)部的 HTML 內(nèi)容捣作。例如:

      Element div = doc.select("div").first();
      div.html("<p>Hello Jsoup</p>");
      
    • Element.text(String text) 方法可用于替換元素內(nèi)部的文本內(nèi)容誉结。例如:

      Element div = doc.select("div").first();
      div.text("Hello Jsoup");
      
  • 刪除節(jié)點(diǎn):

    • Element.empty() 方法可用于刪除元素內(nèi)部的所有子元素。例如:

      Element div = doc.select("div").first();
      div.empty();
      
    • Element.remove() 方法可用于刪除元素本身券躁。例如:

      Element div = doc.select("div").first();
      div.remove();
      
  • 修改節(jié)點(diǎn):

    • Element.attr(String attributeKey, String attributeValue) 方法可用于修改元素的屬性值惩坑。例如:

      Element link = doc.select("a[href]").first();
      link.attr("href", "http://example.com");
      
    • Element.addClass(String className) 方法可用于向元素添加類名。例如:

      Element div = doc.select("div").first();
      div.addClass("highlight");
      
    • Element.removeClass(String className) 方法可用于刪除元素的類名也拜。例如:

      Element div = doc.select("div").first();
      div.removeClass("highlight");
      

三以舒、高級應(yīng)用

  1. 處理錯誤和異常

在解析 HTML 時(shí),有可能會出現(xiàn)各種錯誤和異常慢哈,例如網(wǎng)絡(luò)超時(shí)蔓钟、HTTP 錯誤、HTML 解析錯誤等岸军。為了保證程序的健壯性和穩(wěn)定性奋刽,需要對這些錯誤進(jìn)行處理。

可以使用 try-catch 塊來捕獲異常艰赞,并采取相應(yīng)的措施進(jìn)行處理佣谐。例如:

try {
    Document doc = Jsoup.connect("http://example.com/").get();
} catch (IOException e) {
    System.err.println("IO Exception: " + e.getMessage());
} catch (IllegalArgumentException e) {
    System.err.println("Illegal Argument Exception: " + e.getMessage());
}
  1. 使用代理服務(wù)器

在實(shí)際應(yīng)用中,有時(shí)需要使用代理服務(wù)器來訪問互聯(lián)網(wǎng)方妖,以便實(shí)現(xiàn)一些特殊需求狭魂,例如爬蟲、數(shù)據(jù)挖掘等〈瞥危可以使用 Proxy 類來設(shè)置代理服務(wù)器斋泄。

String proxyHost = "proxy.example.com";
int proxyPort = 8080;
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
Document doc = Jsoup.connect("http://example.com/").proxy(proxy).get();
  1. 加載本地 HTML 文件

除了從 URL 加載 HTML 文檔外,還可以從本地文件系統(tǒng)加載 HTML 文件镐牺,以便進(jìn)行離線處理炫掐。可以使用 File 類來指定本地文件路徑睬涧,并使用 Jsoup.parse(File in, String charsetName) 方法來解析文件募胃。

File input = new File("input.html");
Document doc = Jsoup.parse(input, "UTF-8");
  1. 處理 AJAX 網(wǎng)頁

在一些新型的網(wǎng)站中,由于采用了 AJAX 技術(shù)畦浓,頁面內(nèi)容可能會動態(tài)生成痹束,而不是直接從服務(wù)器端加載。這時(shí)候讶请,需要使用一些高級技巧來處理 AJAX 網(wǎng)頁祷嘶,例如 PhantomJS、Selenium 等技術(shù)夺溢。

四论巍、原理分析

Jsoup 的內(nèi)部實(shí)現(xiàn)原理比較復(fù)雜,主要涉及到 HTML 解析器企垦、DOM 樹構(gòu)建器环壤、字符編碼處理器等組件。其中钞诡,HTML 解析器是核心組件之一郑现,實(shí)現(xiàn)了對 HTML 語法的解析和分詞,將 HTML 文檔轉(zhuǎn)換成一個 DOM 樹荧降。

具體而言接箫,HTML 解析器采用了一種基于狀態(tài)轉(zhuǎn)移的解析算法,即根據(jù)當(dāng)前狀態(tài)和輸入字符朵诫,確定下一步的狀態(tài)和動作辛友,并將解析過程記錄在一個狀態(tài)棧中。當(dāng)解析完成后剪返,棧中保存的狀態(tài)信息即為最終的 DOM 樹結(jié)構(gòu)废累。

DOM 樹構(gòu)建器則負(fù)責(zé)將解析完成的狀態(tài)棧轉(zhuǎn)換成一個 DOM 樹對象,以方便后續(xù)操作脱盲。字符編碼處理器則負(fù)責(zé)將 HTML 文檔中的特殊字符(例如中文邑滨、符號等)進(jìn)行編碼和解碼,以保證在解析過程中不會出現(xiàn)亂碼或錯誤钱反。

五掖看、相關(guān)工具及框架

除了 Jsoup 之外匣距,還有許多其他的 HTML 解析工具和框架可供選擇,具體如下:

  • Jsoup:一款輕量級的 Java HTML 解析器
  • NekoHTML:一款基于 Xerces 的輕量級 HTML 解析器哎壳,支持 SAX 和 DOM 模式
  • HTML Parser:一款基于 Java 的 HTML 解析器毅待,支持 SAX 和 DOM 模式
  • Jericho HTML Parser:一款開源的 HTML 解析器,可以解析標(biāo)準(zhǔn) HTML归榕、XHTML尸红、XML 等格式
  • TagSoup:一款開源的 HTML/XML 解析器,可以處理 HTML5蹲坷、XML 等格式
  • Selenium:一款自動化測試工具驶乾,可以模擬瀏覽器行為,支持處理 AJAX 和 JavaScript 網(wǎng)頁
  • PhantomJS:一種無界面的 WebKit 瀏覽器循签,支持處理 AJAX 和 JavaScript 網(wǎng)頁,可以嵌入到 Java 程序中進(jìn)行使用
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疙咸,一起剝皮案震驚了整個濱河市县匠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撒轮,老刑警劉巖乞旦,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異题山,居然都是意外死亡兰粉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門顶瞳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玖姑,“玉大人,你說我怎么就攤上這事慨菱⊙媛纾” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵符喝,是天一觀的道長闪彼。 經(jīng)常有香客問我,道長协饲,這世上最難降的妖魔是什么畏腕? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮茉稠,結(jié)果婚禮上描馅,老公的妹妹穿的比我還像新娘。我一直安慰自己战惊,他們只是感情好流昏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布扎即。 她就那樣靜靜地躺著,像睡著了一般况凉。 火紅的嫁衣襯著肌膚如雪谚鄙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天刁绒,我揣著相機(jī)與錄音闷营,去河邊找鬼。 笑死知市,一個胖子當(dāng)著我的面吹牛傻盟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嫂丙,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼娘赴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了跟啤?” 一聲冷哼從身側(cè)響起诽表,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎隅肥,沒想到半個月后竿奏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腥放,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年泛啸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秃症。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡候址,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伍纫,到底是詐尸還是另有隱情宗雇,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布莹规,位于F島的核電站赔蒲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏良漱。R本人自食惡果不足惜舞虱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望母市。 院中可真熱鬧矾兜,春花似錦、人聲如沸患久。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至返帕,卻和暖如春桐玻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背荆萤。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工镊靴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人链韭。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓偏竟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敞峭。 傳聞我的和親對象是個殘疾皇子踊谋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容