jsoup : ÀÚ¹Ù HTML Æļ(Java HTML Parser)
CKEditor, Smart Editor °°Àº HTML ¿¡µðÅÍ·Î ±ÛÀ» ÀÛ¼ºÇÏ´Â »çÀÌÆ®ÀÇ °æ¿ì ÀÛ¼ºµÈ ±Û¿¡¼ html ű×(tag)¸¦ Á¦°ÅÇÑ ¼ø¼öÇÑ ÅؽºÆ®¸¸À» ÃßÃâÇϰųª, img ű׸¸À» ÃßÃâÇÏ¿© ½æ³×ÀÏ(Thumbnail)À» ¸¸°Å³ª ÇÏ´Â ÀÏÀÌ Á¾Á¾ ÀÖ½À´Ï´Ù.
ÀÌ·¯ÇÑ ±â´ÉÀ» Á¤±Ô½Ä(Regular Expression)À» »ç¿ëÇÏ¿© Á÷Á¢ ¸¸µé¾î ¾²±âµµ Çϴµ¥, ±× ±â´É¿¡´Â Á¦ÇÑÀÌ ÀÖÀ» ¼ö¹Û¿¡ ¾ø½À´Ï´Ù.
À̹ø¿¡ ¼Ò°³ÇÏ´Â jsoupÀº ÀÚ¹Ù(Java)·Î ¸¸µé¾îÁø HTML Æļ(Parser) ÀÔ´Ï´Ù. jsoupÀº ÀÚ¹Ù ¾ð¾î·Î HTMLÀ» ´Ù·ç´Â ½±°í, °·ÂÇÑ ±â´ÉÀ» Á¦°øÇÕ´Ï´Ù. jsoup·Î ´ÙÀ½°ú °°Àº ÀÛ¾÷À» ÇÒ ¼ö ÀÖ½À´Ï´Ù.
* URL, ÆÄÀÏ, ¹®ÀÚ¿À» ¼Ò½º·Î ÇÏ¿© HTMLÀ» ÆĽÌÇÒ ¼ö ÀÖ½À´Ï´Ù.
* DOM ±¸Á¶¸¦ ÃßÀûÇϰųª Àͼ÷ÇÑ CSS ¼±ÅÃÀÚ¸¦ »ç¿ëÇÏ¿© µ¥ÀÌÅ͸¦ ã¾Æ ÃßÃâÇÒ ¼ö ÀÖ½À´Ï´Ù.
* ¹®¼³»ÀÇ HTML ¿ä¼Ò, ¼Ó¼º, ÅؽºÆ®¸¦ Á¶ÀÛÇÒ ¼ö ÀÖ½À´Ï´Ù.
* »ç¿ëÀÚ°¡ ÀÔ·ÂÇÑ µ¥ÀÌÅͷκÎÅÍ XSS(Cross-Site Script) °ø°ÝÀ» ¹æÁöÇϱâ À§Çؼ ¾ÈÀüÇÑ ÈÀÌÆ® ¸®½ºÆ® ¹æ½ÄÀ¸·Î ÁöÁ¤µÈ ű׸¸ ³²±â°í ³ª¸ÓÁö´Â Á¦°ÅÇÒ ¼ö ÀÖ½À´Ï´Ù.
* ±ò²ûÇÑ ÇüÅÂÀÇ html À» Ãâ·ÂÇÒ ¼ö ÀÖ½À´Ï´Ù.
jsoup´Â ¿ÀÇ ¼Ò½º ÇÁ·ÎÁ§Æ®·Î Á¦°øµË´Ï´Ù. ¶óÀ̼¾½º´Â MIT ÀÔ´Ï´Ù. ´ÙÀ½ »çÀÌÆ®¿¡¼ ´Ù¿î·Îµå ¹× ÇÊ¿äÇÑ Á¤º¸¸¦ ¾òÀ» ¼ö ÀÖ½À´Ï´Ù.
jar ÆÄÀÏÀ» ´Ù¿î·Îµå ¹Þ¾Æ¼ Ŭ·¡½º Æнº¿¡ Ãß°¡Çؼ »ç¿ëÇصµ µÇ°í, ¸ÞÀ̺ìÀ» »ç¿ëÁßÀ̶ó¸é ´ÙÀ½ ÀÇÁ¸¼ºÀ» Ãß°¡ÇÏ¸é »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù.
<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.10.3</version> </dependency>
ÀÌÁ¦ °£´ÜÇÑ »ç¿ë¹ýÀ» ¾Ë¾Æ º¸°Ú½À´Ï´Ù.
1. ¹®¼ÀÇ ÆĽÌ
¹®¼´Â URL, ÆÄÀÏ, ¹®ÀÚ¿·Î ºÎÅÍ ÆĽÌÇÒ ¼ö ÀÖ½À´Ï´Ù.
1.1. ¹®¼Àüü¸¦ °¡Áö°í ÀÖ´Â ¹®ÀÚ¿·ÎºÎÅÍ ÆĽÌÇÏ´Â ¿¹ÀÔ´Ï´Ù.
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; ... String html = "<title>First parse</title>" + "<p>Parsed HTML into a doc.</p>"; Document doc = Jsoup.parse(html);
¹®¼·ÎºÎÅÍ html tag ¸¦ ¸ðµÎ Á¦°Å ÇÏ°í ¼ø¼ö ¹®ÀÚ¿¸¸ ¾ò°íÀÚ ÇÒ ¶§´Â String text = doc.text(); ¸¦ »ç¿ëÇÕ´Ï´Ù.
1.2. ¹®¼ÀÇ body ÀϺκÐÀ» °¡Áö°í ÀÖ´Â ¹®ÀÚ¿·ÎºÎÅÍ ÆĽÌÇÕ´Ï´Ù.
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; ... String html = "<div><p>Lorem ipsum.</p>"; Document doc = Jsoup.parseBodyFragment(html); Element body = doc.body();
doc.body() ¸Þ¼Òµå´Â ¹®¼ÀÇ body ¿ä¼Ò¸¦ ÃßÃâÇÕ´Ï´Ù. doc.getElementByTag("body") ¿Í µ¿ÀÏÇÕ´Ï´Ù.
»ç¿ëÀÚ°¡ À¥ÆäÀÌÁöÀÇ ÆûÀ¸·Î ºÎÅÍ ÀÔ·ÂÇÑ html ű׸¦ Æ÷ÇÔÇÑ ÀÔ·Â ³»¿ë¿¡¼ cross-site scripting °ø°ÝÀ» ÇÇÇϱâ À§Çؼ ÈÀÌÆ® ¸®½ºÆ® ±â¹ÝÀÇ tag Á¦°Å ±â´ÉÀ» »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù.
Jsop.clean(String bodyHtml, Whitelist whitelist);
Çã¿ëÇÏ´Â tag ¸¦ ÁöÁ¤ÇÏ´Â Whitelist Ŭ·¡½º¿¡ ´ëÇؼ´Â API ¹®¼¸¦ ÂüÁ¶ Çϼ¼¿ä.
1.3. URL·ÎºÎÅÍ ¹®¼¸¦ ÆĽÌÇÏ´Â ¹æ¹ý ÀÔ´Ï´Ù. GET ¹æ½ÄÀÇ È£ÃâÀ» ÇÕ´Ï´Ù.
Document doc = Jsoup.connect("http://example.com/").get(); String title = doc.title();
POST ¹æ½ÄÀ¸·Î »ç¿ëÇÒ ¼öµµ ÀÖ½À´Ï´Ù.
Document doc = Jsoup.connect("http://example.com") .data("query", "Java") .userAgent("Mozilla") .cookie("auth", "token") .timeout(3000) .post();
jsoup´Â http ¿Í https ¸¸À» Áö¿øÇÕ´Ï´Ù.
1.4. ÆÄÀϷκÎÅÍ ÆĽÌÇÏ´Â ¹æ¹ý ÀÔ´Ï´Ù.
File input = new File("/tmp/input.html"); Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
parse ¸Þ¼ÒµåÀÇ Ã¹ ¹ø° ÀÎÀÚ´Â ÆĽÌÇÒ ÆÄÀÏÀÇ File °´Ã¼ÀÔ´Ï´Ù. µÎ ¹ø° ÀÎÀÚ´Â ÆÄÀÏÀÇ Ä³¸¯ÅͼÂÀÔ´Ï´Ù. ¼¼ ¹ø° ÀÎÀÚ´Â ÆÄÀϳ»ÀÇ a, img ÅÂ±× µîÀÇ base url ÀÔ´Ï´Ù. base url ÀÌ ¾ø´Â ¿À¹ö·Îµå µÈ ¸Þ¼Òµåµµ ÀÖ½À´Ï´Ù.(Jsoup.parse(input, "UTF-8");)
2. ¹®¼ÀÇ ³»ºÎ µ¹¾Æ´Ù´Ï±â
ÆĽÌÀ» Çؼ Document °´Ã¼°¡ ¸¸µé¾îÁö¸é Document³»¿¡¼ ¿øÇÏ´Â µ¥ÀÌÅ͸¦ ÃßÃâÇϰųª Á¶ÀÛÀ» ÇÒ ¼ö ÀÖ½À´Ï´Ù.
2.1. ¸ÕÀú ÇÊ¿äÇÑ ¿ä¼Ò¸¦ ã½À´Ï´Ù.
* getElementById(String id) : Element °´Ã¼¸¦ ¹ÝȯÇÕ´Ï´Ù. Çϳª¸¦ ¹ÝȯÇÕ´Ï´Ù. ¾øÀ¸¸é null À» ¹ÝȯÇÕ´Ï´Ù.
* getElementsByTag(String tag) : Elements °´Ã¼¸¦ ¹ÝȯÇÕ´Ï´Ù. ¾øÀ¸¸é size() °¡ 0 ÀÔ´Ï´Ù.
* getElementsByClass(String className) : Elements °´Ã¼¸¦ ¹ÝȯÇÕ´Ï´Ù. ¾øÀ¸¸é size() °¡ 0 ÀÔ´Ï´Ù.
ÀÌ ÀÌ¿Ü¿¡µµ ¸¹Àº ¸Þ¼ÒµåµéÀÌ ÀÖ½À´Ï´Ù. API¸¦ ÂüÁ¶ Çϼ¼¿ä.
Elements °´Ã¼·Î ¹ÝȯÇÏ´Â °ÍÀº ¼±ÅÃÀÌ µÇ¾ú´ÂÁö È®ÀÎÇϱâ À§Çؼ size() ¸¦ üũÇÕ´Ï´Ù. Element °´Ã¼¸¦ ¹ÝȯÇϴ°ÍÀº ¼±ÅÃÀÎ µÇÁö ¾ÊÀ¸¸é null À» ¹ÝȯÇϹǷÎ, null üũ¸¦ ÇØ¾ß NullpointerException À» ¿¹¹æÇÒ ¼ö ÀÖ½À´Ï´Ù.
2.2. Element °´Ã¼°¡ ÇÒ ¼ö ÀÖ´Â ÀÛ¾÷ ÀÔ´Ï´Ù.
* attr(String key) ·Î ¼Ó¼ºÀÇ °ªÀ» ¾ò½À´Ï´Ù. attr(String key, String value)·Î ¼Ó¼ºÀÇ °¢À» ¼³Á¤ÇÒ ¼ö ÀÖ½À´Ï´Ù.
* id(), className() Àº id¿Í class¼Ó¼ºÀÇ °ªÀ» °¡Á®¿É´Ï´Ù. class´Â ¿©·¯°³ ÁöÁ¤µÇ¸é ÇϳªÀÇ ¹®ÀÚ¿·Î ¹ÝȯµË´Ï´Ù. ¿¹·Î ¿ä¼Ò°¡ <div class="center red"> ¶ó¸é className() Àº "center red" ¸¦ ¹ÝȯÇÕ´Ï´Ù. Çϳª¾¿ ±¸Çϱâ À§Çؼ´Â classNames() ¸Þ¼Òµå¸¦ »ç¿ëÇÕ´Ï´Ù. Set<String> ŸÀÔÀ¸·Î ¹ÝȯÇÕ´Ï´Ù.
* text()·Î ¼ø¼ö ÅؽºÆ®¸¸ ±¸ÇÕ´Ï´Ù. text(String value)·Î ¿ä¼ÒÀÇ ÅؽºÆ®¸¦ ¼³Á¤ÇÒ ¼ö ÀÖ½À´Ï´Ù.
* html()·Î html ¹®ÀÚ¿À» ±¸ÇÕ´Ï´Ù. html(String value) ¸Þ¼Òµå·Î inner HTML À» ¼³Á¤ÇÕ´Ï´Ù.
* outerHtml() ¿ä¼ÒÀÇ outer htmlÀ» ¹ÝȯÇÕ´Ï´Ù.
inner HTML Àº ¿ä¼Ò°¡ Æ÷ÇÔÇÏ´Â htmlÀ» ³ªÅ¸³»°í, outer html Àº ¿ä¼Ò ÀÚü űױîÁö Æ÷ÇÔÇÏ´Â °ÍÀÔ´Ï´Ù.
¡Ø ¹®¼³»ÀÇ ¸ðµç <img> ű׵éÁß Ã¹ ¹ø° img ¿ä¼ÒÀÇ src ¼Ó¼º °ªÀ» ±¸ÇÏ·Á¸é ´ÙÀ½°ú °°ÀÌ ÇÒ ¼ö ÀÖ½À´Ï´Ù .
Elements imgs = doc.getElementByTag("img"); if(imgs.size() > 0) { String src = imgs.get(0).attr("src'); }
Elements °´Ã¼´Â ArrayList¸¦ »ó¼ÓÇؼ ¸¸µé¾îÁ³½À´Ï´Ù. ±×·¯¹Ç·Î ³»ºÎÀÇ Element µéÀ» ´Ù·ç±â À§Çؼ ArrayList¿Í µ¿ÀÏÇÑ ¹æ¹ýÀ» »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù.
´ÙÀ½ ó·³ »ç¿ëÇÒ ¼öµµ ÀÖ½À´Ï´Ù.
Element img = doc.getElementByTag("img").first(); if(img != null) { String src = img.attr("src"); }
2.3. HTML °ú text Á¶ÀÛÇϱâ
* append(String html), prepend(String html) : ¼±ÅÃµÈ ¿ä¼ÒÀÇ µÚ(append)¿Í ¾Õ(prepend)¿¡ html À» Ãß°¡ÇÕ´Ï´Ù.
* appendText(String text), prependText(String text) : ¼±ÅÃµÈ ¿ä¼ÒÀÇ µÚ(append)¿Í ¾Õ(prepend)¿¡ text¸¦ Ãß°¡ÇÕ´Ï´Ù.
* appendElement(String tagName), prependElement(String tagName) : ¼±ÅÃµÈ ¿ä¼ÒÀÇ µÚ(append)¿Í ¾Õ(prepend)¿¡ Element¸¦ Ãß°¡ÇÕ´Ï´Ù.
* html(String value) : ¼±ÅÃµÈ ¿ä¼Ò¿¡ inner html À» ¼³Á¤ ÇÕ´Ï´Ù.
3. CSS ½ºÅ¸ÀÏ·Î ¿ä¼Ò¸¦ ¼±ÅÃÇϱâ
jsoupÀº CSS ½ºÅ¸ÀÏÀÇ ¼±Åà ±â´ÉÀ» Á¦°øÇÕ´Ï´Ù. ÀÌ ±â´ÉÀ» Document, Elements, Element°¡ °¡Áö°í ÀÖ´Â select¸Þ¼Òµå¸¦ ¼öÇàÇÕ´Ï´Ù.
* doc.select("a") : <a> ¿ä¼Ò¸¦ ¸ðµÎ ¼±ÅÃÇÕ´Ï´Ù.
* doc.select("#logo") : id="logo" ÀÎ ¿ä¼Ò¸¦ ¼±ÅÃÇÕ´Ï´Ù.
* doc.select(".head") : class="head"ÀÎ ¿ä¼ÒµéÀ» ¼±ÅÃÇÕ´Ï´Ù.
* doc.select("[href]") : href ¼Ó¼ºÀ» °¡Áø ¿ä¼ÒµéÀ» ¼±ÅÃÇÕ´Ï´Ù.
* doc.select("[width=500]") : width ¼Ó¼ºÀÇ °ªÀÌ 500ÀÎ ¸ðµç ¿ä¼ÒµéÀ» ¼±ÅÃÇÕ´Ï´Ù.
´ÙÀ½ ó·³µµ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù.
doc.select("div").select(".head").select("[width=500]");
´ÜÀÏ Element°¡ ¹ÝȯµÇ´Â °æ¿ì¿¡ ÀÌ·± Ç¥Çö½ÄÀ» ¾²¸é ¾ÈµË´Ï´Ù. NullpointerException ÀÌ ¹ß»ýÇÒ ¼ö ÀÖ½À´Ï´Ù.
´ÙÀ½Àº div ¿ä¼ÒµéÁß¿¡¼ class°¡ "logo" °¡ ¾Æ´Ñ°Íµé À» ¼±ÅÃÇÕ´Ï´Ù.
Elements divs = doc.select("div").not(".logo");
´õ ¸¹Àº ±â´ÉµéÀº API ¹®¼¸¦ ÂüÁ¶Çϼ¼¿ä.
ÀÌ ¶óÀ̺귯¸®¸¦ Àß ÀÌ¿ëÇϸé ÀÚ¹Ù·Î Å©·Ñ·¯µµ ¼Õ½±°Ô ¸¸µé ¼ö ÀÖÀ»°Í °°½À´Ï´Ù.
Ãâó: http://pentode.tistory.com/170 [½¬°í ½ÍÀº °³¹ßÀÚ]