HTML Parser - jsoup JAVA 공부!!


HTML(Hyper Text Markup Language) parser library - jsoup

소개 및 API document
maven URL

특정 양식으로 고정되어 출력되는 HTML 파일을 파싱할 일이 생겼는데 jsoup을 써보라는 권유가 있었다.
써본 적은 없으나 XML 파싱은 해본 적이 있으니 비슷하겠다 싶었다.

급하게 parsing해서 각 항목별 데이터를 확인하기 위해
우선 C#으로 코딩을 하고 (C# 에서는 HtmlAgilityPack 이라는 libarary 사용),
parsing 해보니 특정 data 빼고는 다 맞게 나오는걸 확인했다.

API 문서를 먼저 훑어 봤다.
API 문서에 selector 라는 class를 보니 아주 낯이 익은 문법들이 보인다.
jQuery 에서 아주 많이 쓰는 selector들!!
#id, .class, [attr=val], :gt(n), :lt(n), :eq(n) 심지어 contains(text) 까지!
(** gt = Greater Than, lt = Less Than, eq = Equal, ne = Not Equal **)

그럼 parsing 함 해볼까나~

우선 파일로 부터 HTML 내용을 읽어들인다.
파일 외에 String, InputStream, URL 을 통해서도 HTML 내용을 읽어들일 수 있다.

// 1. parse(File in, String charsetName)
Document document = Jsoup.parse(new File(filePath), "UTF-8");
// 2. parse(String html, String charsetName)
// Document document = Jsoup.parse(htmlContent, "UTF-8");

/* 이 외에도 parse 함수가 더 있음 */
// parse(InputStream in, String charsetName, String baseUri)
// parse(URL url, int timeoutMillis)

내가 필요한건 파일로부터 읽는 것이니...
1번과 같이 파일 내용을 모두 가져오도록 하면,
document 에는 HTML 파일의 내용 전부가 들어가 있다.

<html>
<head>
<title>테스트 HTML 페이지</title>
</head>
<body>
<table id="table1">
<tr>
<th>이름</th>
<th>성별</th>
<th>나이</th>
<th>점수</th>
</tr>
<tr>
<td>홍길동</td>
<td>남자</td>
<td>57세</td>
<td>80점</td>
</tr>
<tr>
<td>고길동</td>
<td>남자</td>
<td>47세</td>
<td>90점</td>
</tr>
<tr>
<td>박길동</td>
<td>남자</td>
<td>25세</td>
<td>35점</td>
</tr>
</table>
</body>
</html>

위와 같은 HTML 문서가 document에 담겼다고 가정하고...

나는! "table1" 이라는 id를 가진 table 안에 내용만 필요해!

Elements tableList = document.select("#table1");
// select 인자 값으로 아래와 같이 사용 가능
// Elements tableList = document.select("table#table1");

여기서 잠깐...! 엥?
변수 명이 tableList ??? 변수 타입이 Elements ???
HTML 안에서 id는 고유한 녀석이라 어차피 하나밖에 안나올텐데??
이러한 생각이 들었으나... 역시 궁금할때는 찾아봐야지!

API 문서를 뒤지다보니
Document class는 select 라는 함수가...........없네?

다시다시 찾아보니....

Document class는 Element class를 상속받고 있다.
그럼 Element class는 select라는 함수가..........


찾았다 요놈!

Element class의 select 함수는 return type이 Elements다!
Elements class는 또 보면
public class Elements extends ArrayList<Element>
이렇게 선언되어 있다.
결국 원하는 selector 결과가 하나든 둘이든 ArrayList로 떨어진다고 보면 되는 것이다.

Elements class의 정체를 알았으니 이제 본격적으로 parsing을 해봐야겠다.


Document document = Jsoup.parse(new File(filePath), "UTF-8");
Elements tableList = document.select("table#table1");
for(Element table : tableList) {
// table 안에 tr들 중 index가 0인 tr은 단순 title row 이므로 index가 0보다 큰 tr만 select
Elements rowList = table.select("tr:gt(0)");
for(Element row : rowList) {
// tr 내에 있는 td 들을 select
Elements cellList = row.select("td");
String name = cellList.get(0).text();
String gender = cellList.get(1).text();
String age = cellList.get(2).text();
String score = cellList.get(3).text();

System.out.println("이름 : " + name);
System.out.println("성별 : " + gender);
System.out.println("나이 : " + age);
System.out.println("점수 : " + score);
}
}


위 코드를 더 간단하게 줄일 수 있겠다!


Document document = Jsoup.parse(new File(filePath), "UTF-8");

// #table1 안에 tr들 중 index가 0인 tr은 단순 title row 이므로 index가 0보다 큰 tr만 select
Elements rowList = document.select("table#table1 tr:gt(0)");
for(Element row : rowList) {
Elements cellList = row.select("td");
String name = cellList.get(0).text();
String gender = cellList.get(1).text();
String age = cellList.get(2).text();
String score = cellList.get(3).text();

System.out.println("이름 : " + name);
System.out.println("성별 : " + gender);
System.out.println("나이 : " + age);
System.out.println("점수 : " + score);
}

select 함수 내에서 selector 만 잘 다뤄주면 코드 양이 꽤 줄어들 수 있겠다.
실제로 parsing 기능을 적용 하다 보니 아래와 같은 selector를 쓰기도 했다.

// table 안에 tr들 중 index가 0보다는 크면서 10보다는 작은 tr만 select
table.select("tr:gt(0):lt(10)");


언제나 그렇듯 분명히 더 효율적인 방법도 있을테지...
혹시나 누군가에게 도움이 될까 싶어 예제 소스 파일을 첨부하고...

첨부 : ParsingHTML.zip

그럼 이만.!

1 2 3 4 5 6 7 8 9 10 다음