ÃֽŠ°Ô½Ã±Û(JAVA)
2017.07.10 / 17:15

jsoup : ÀÚ¹Ù HTML Æļ­(Java HTML Parser)

XMaLL°ü¸®ÀÚ
Ãßõ ¼ö 296

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 ÀÔ´Ï´Ù. ´ÙÀ½ »çÀÌÆ®¿¡¼­ ´Ù¿î·Îµå ¹× ÇÊ¿äÇÑ Á¤º¸¸¦ ¾òÀ» ¼ö ÀÖ½À´Ï´Ù.


https://jsoup.org/




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 °´Ã¼ÀÔ´Ï´Ù. µÎ ¹ø° ÀÎÀÚ´Â ÆÄÀÏÀǠij¸¯ÅͼÂÀÔ´Ï´Ù. ¼¼ ¹ø° ÀÎÀÚ´Â ÆÄÀϳ»ÀÇ 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 [½¬°í ½ÍÀº °³¹ßÀÚ]