728x90
반응형

크롤링으로 본문을 수집할 때 순수한 본문 내용만을 수집하고자 하지만

포스팅되는 많은 글들은 내부 링크, 좋아요 또는 댓글, 광고 등 많은 것들이 붙어 있어

이것들을 제거해야할 필요가 있었다.

 

사실 이 글의 내용은 기존에 포스팅 한 Selenium의 연장선에서 작업한 내용이다.

기존 Selenium 포스팅은 아래 글 참조.

 

[java, selenium] web crawling (웹 크롤링)

최근 좀 길게 웹 크롤링에 대해 작업을 했다. 넓은 범위로 크롤링 중인지라 길어지게 되었고, 어느정도 정리가 되어가고 있어 내용을 정리해 보고자 한다. 참고로 나는 docker에 ubuntu + tomcat + seleni

deonggi.tistory.com

 

Selenium의 연장선이라면서 Jsoup을 쓰고 있는 이유가 있다.

1차 결과물을 수집해 보았더니 원하지 않는 내용들도 딸려 들어오고 있었다.

이런 것들을 제거하는 기능이 필요했으나 작업하던 당시

Selenium에서는 이런 레퍼런스를 찾을 수 없었기 때문에 Jsoup을 섞어서 쓰게 되었다.

 

이러한 결과로 만들어진 결과를 기록해 본다.

 

1. html에서 필요하지 않는 텍스트를 태그 단위로 제거한다.

내가 얻고자 했던 것은 본문 내용 부분이다.

하지만 본문 영역의 html에 대한 텍스트를 모두 가져온다면 필요하지 않은 텍스트들이 의외로 많이 가지고 있다.

그래서 나는 이런 것들의 제거가 필요하다고 생각했고 태그 단위로 제거하길 원했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * jsoup을 이용하여 element 제거
 * @param strHtml
* @param removeSelectorList 제거할 셀렉터 리스트
 * @return
 */
public static String removeElementByJsoup(String strHtml, List<String> removeSelectorList) {
    if (removeSelectorList != null && removeSelectorList.size() > 0) {
        // String 형태의 html 문서를 html로 변경한다.
        org.jsoup.nodes.Document html = org.jsoup.Jsoup.parseBodyFragment(strHtml);
        for (String selector : removeSelectorList) {
            // html에서 제거할 태그를 찾아 제거한다.
            org.jsoup.select.Elements els = html.select(selector);
            if (els != null && els.size() > 0) {
               for (org.jsoup.nodes.Element el : els) {
                   el.remove();
               }
           }
        }
        // 제거된 html을 스트링으로 리턴한다.
        return html.toString().trim();
    }        
    return strHtml.trim();
}
cs

위 소스에서 removeSelectorList에는 이러한 제거할 태그에 대한 셀렉터다.

(ex : 내부 글 링크, 구글 광고와 같은 것, SNS 공유 버튼 텍스트, 좋아요 댓글 버튼 텍스트 등)

이 메소드의 리턴 값은 html 태그를 가지고 있다.

그러므로 이제 html 태그를 제거하고 텍스트만 가져오면 된다.

 

2. html에서 태그를 제거하고 텍스트만 남긴다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
 * jsoup을 이용하여 태그를 제거한 text만 수집
 * @param strHtml
 * @return
 */
public static String getElementTextByJsoup(String strHtml) {
    if (!StringUtils.isBlank(strHtml)) {
        String REGEX_NEW_LINE = "(\r\n|\r|\n)";
        String NEW_LINE = System.getProperty("line.separator");
        /**
         * 1. p, br 태그와 텍스트를 남긴다. (이외 개행상태 유지)
         * 2. br 태그를 개행한다.
         * 3. 남은 태그를 제거한다.
         */
       String cleanText = org.jsoup.Jsoup.clean(
                   org.jsoup.Jsoup.clean(
                           strHtml.replace("&nbsp;"" ")            // 공백 태그 변경
                           , "", org.jsoup.safety.Whitelist.none().addTags("br""p")
                           , new org.jsoup.nodes.Document.OutputSettings().prettyPrint(true))            // 1. 
                   .replace("<br>", NEW_LINE)                                                        // 2.
                   , "", org.jsoup.safety.Whitelist.none(), new org.jsoup.nodes.Document.OutputSettings().prettyPrint(false));    // 3.
           
       // 개행문자 통일
        cleanText = cleanText.replaceAll(REGEX_NEW_LINE, NEW_LINE);
        return StringEscapeUtils.unescapeHtml4(cleanText.trim());        // html 특수문자 제거
    }
    return null;
}
cs

위 소스에서는 몇가지 포인트가 있다.

1) 개행문자가 os에 따라 다르므로 한가지로 변경하면 차후 작업에 유리하다.

2) br, p에 대한 태그는 개행으로 유지한다. 

3) html 특수문자는 &nbsp;는 공백으로 변경하고, 나머지는 제거한다.

 

 

자세한 설명은 부족하겠으나 많은 테스트 후 나온 결과물이다.

제거할 대상 태그들에 대한 셀렉터들은 다소 사전 조사가 필요하다.

눈에 보이는 것들도 있겠으나 눈에 보이지 않는 요소들도 상당히 많다.

그러므로 2번째 소스를 먼저 사용해서 정보를 수집하고 1번 소스를 사용하면 될 것 같다.

 

 

 

728x90
반응형

+ Recent posts