토이 프로젝트/Spring&Java 갖고놀기

DataPlay project - 1 : word cloud 생성기 코드 정리

TerianP 2022. 5. 10.
728x90

이번 포스팅은 word cloud 를 만들기 위한 전체적인 코드와 찾아봤던 정보들을 정리하기 위한 글을 작성하도록 하겠다.

모든 코드는 git 에 올려두었고, 여기에는 크롤링 -> 데이터 파싱 -> Controller -> html 순으로 정리하도록 하겠다.

 

1. 크롤링 crewler

- 크롤링을 위한 코드는 네이버 블로그 검색 API 와 아래 블로그의 Steele 님의 코드를 약간 수정해서 사용하였다

(주소는 아래 참조에 달아두었습니다)

- 나름대로 로직을 이해하기 위해 주석을 달아서 정리하였으나, 보다 자세한 설명은 Steele 님의 글을 보는게 훨~~씬 도움이 되리라 생각한다.

package HJproject.DataMining;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;

public class NaverCrawler implements APIdata{ // 베이스 URL
    final String baseUrl = "https://openapi.naver.com/v1/search/blog.json?query=";


    public String Navercrawler(String word){
        String crawerString = null;

        try {


            // 매개변수 : 검색단어, 인코딩
            String url = URLEncoder.encode(word, "UTF-8");
            // crawler 의 search 메소드 사용
            // 이때 naverID 와 naverSecret 은 APIdata 안에 있는 내용 사용
            String response = search(naverID, naverSecret, url);

            // 필드값은 title 가 desc 2개!
            // 크롤링을 하게되면 field 가 여러개가 나오는데 이 중에서 title 와 desc 만 가져온다는 의미
            String[] fields = {"title","description"};

            // 결과를 Map 형태로 저장장
           Map<String, Object> result = getResult(response, fields);

            // 검색 결과가 1개 이상인 경우 result 값을 출력
            if (result.size() > 0) {
                System.out.println("total -> " + result.get("total"));
            }

//            System.out.println("result : "+result);

            // 검색 결과를 다시 List 형태로 저장
            List<Map<String, Object>> items = (List<Map<String, Object>>) result.get("result");

            //
            for (Map<String, Object> item : items) {
                crawerString += item.get("title");
                crawerString += item.get("description");
            }


            return crawerString;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    // 여기는 네이버 검색 API
    public String search(String clientId, String secret, String _url) {
        HttpURLConnection con = null;
        String result = "";
        try {
            URL url = new URL(baseUrl + _url +"&display=50");
            con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("GET");
            con.setRequestProperty("X-Naver-Client-Id", clientId);
            con.setRequestProperty("X-Naver-Client-Secret", secret);
            int responseCode = con.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) result = readBody(con.getInputStream());
            else result = readBody(con.getErrorStream());
        } catch (Exception e) {
            System.out.println("연결 오류 : " + e);
        } finally {
            con.disconnect();
        }
        return result;
    }


    public String readBody(InputStream body) {
        InputStreamReader streamReader = new InputStreamReader(body);
        try (BufferedReader lineReader = new BufferedReader(streamReader)) {
            StringBuilder responseBody = new StringBuilder();
            String line;
            while ((line = lineReader.readLine()) != null) {
                responseBody.append(line);
            }
            return responseBody.toString();
        } catch (IOException e) {
            throw new RuntimeException("API 응답을 읽는데 실패했습니다.", e);
        }
    }


    public Map<String, Object> getResult(String response, String[] fields) {
        Map<String, Object> rtnObj = new HashMap<>();
        try {
            JSONParser parser = new JSONParser();
            JSONObject result = (JSONObject) parser.parse(response);
            rtnObj.put("total", (long) result.get("total"));
            JSONArray items = (JSONArray) result.get("items");
            List<Map<String, Object>> itemList = new ArrayList<>();
            for (int i = 0; i < items.size(); i++) {
                JSONObject item = (JSONObject) items.get(i);
                Map<String, Object> itemMap = new HashMap<>();
                for (String field : fields) {
                    itemMap.put(field, item.get(field));
                }
                itemList.add(itemMap);
            }
            rtnObj.put("result", itemList);
        } catch (Exception e) {
            System.out.println("getResult error -> " + "파싱 실패, " + e.getMessage());
        }
        return rtnObj;
    }

}

2. 파싱 Parsing

- 데이터를 파싱하기 위한 코드로 userDic 를 가져온 뒤 설정해두고, Komoran 객체를 생성한다. 그 후 Navercrawler.crawler 메소드 결과를 dataString 에 저장한 후 komoran 객체의 메서드를 사용해 전체 테이터를 파싱한다.

- 이때 komoran 의 getMorphesByTags 메소드를 사용하는데 "NNP", "NNG", "NNB", "NP" 등은 komoran 에서 제공하는 품사표를 활용한 것이다. 이후 메소드의 결과는 String 타입의 List 인 analyzeList 로 저장한다.

- 여기서부터는 아주 중요하다!! analyzeList 의 결과에 대해서 특정 단어가 몇번이나 중복되는지 확인해서 저장해야 하기 때문이다. 따라서 List 로 된 결과를 HashMap 으로 바꿔서 중복된 '단어' 는 삭제하고, 대신 몇번이나 중복되었는지 횟수를 기록한다. 즉 HashMap 에서 key : 단어, value : 중복 횟수 형태로 저장해야 하는 것이다.

- 말이 어렵지 코드로하면 사실 간단한데, 중복 횟수를 확인하는 것은 Collection 의 frequency 메소드를 사용하면 된다. 즉 List 의 단어를 하나하나 꺼내온 뒤 Collections.frequency(전체 List, 값) 을 넣어주면 해당 '값' 이 전체 List 에서 몇번이나 반복되었는지를 int 타입으로 반환한다.

package HJproject.DataMining;

import kr.co.shineware.nlp.komoran.constant.DEFAULT_MODEL;
import kr.co.shineware.nlp.komoran.core.Komoran;
import kr.co.shineware.nlp.komoran.model.KomoranResult;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import java.util.*;


public class NaverParsing implements APIdata {


    public HashMap<String, Integer> parsingData(String word) {

        // System.getProperty 를 사용해서 파일이 실행되는 현재 위치 가져오기
        // iDE 환경에서는 워크스페이스 경로를 가져오고, jar 파일의 경우 jar 파일 실행 경로를 가져옴
        String path = System.getProperty("user.dir");
//            System.out.println(path);

        // Komoran 사용을 위한 초기화 && 선언
        Komoran komoran = new Komoran(DEFAULT_MODEL.FULL);
        // user Dictionary 사용을 위한 위치 경로 정의
        komoran.setUserDic(path + "/userDictionary/koreanDic.user");

        // NaverCrawler 클래스의 crawlerData 메소드를 사용해서 크롤링한 STring 을 얻어오기
        String dataString = new NaverCrawler().crawler(word);

        // 가져온 String을 komoran analyze 메소드에 넣기
        KomoranResult komoranResult = komoran.analyze(dataString);

        // 여기서 getMorphesByTags 사용하면 내가원하는 형태소만 뽑아낼 수 있음
        List<String> analyzeList = komoranResult.getMorphesByTags("NNP", "NNG", "NNB", "NP");

        // list 파일로 떨어진 analyzeList 를 HashMap 에 넣어서 중복된 데이터를 삭제하고
        // Conllections.frequency 를 사용해서 몇 번이나 중복되었는지 분석하여 저장한다.
        // 최종적으로 listHash 에는 단어=중복횟수 로 저장된다.
        // Collections.frequency(Collections객체, 값)
        HashMap<String, Integer> listHash = new HashMap<>();
        for (String l : analyzeList) {
            int num = Collections.frequency(analyzeList, l);
            listHash.put(l, num);
        }

        // 데이터 정렬을 위한 코드
//            List<Map.Entry<String, Integer>> list_entries = new ArrayList<Map.Entry<String, Integer>>(listHash.entrySet());
//            Collections.sort(list_entries, new Comparator<Map.Entry<String, Integer>>() {
//                @Override
//                public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
//                    return o2.getValue().compareTo(o1.getValue());
//                }
//            });
//            for(Map.Entry<String, Integer> l : list_entries){
//                System.out.println(l);
//            }


        return listHash;

    }

// 여기서부터는 단순 출력 확인용 코드입니다 안써도 무방해용
//    public static void main(String[] args) {
//
//        String path = System.getProperty("user.dir");
////        System.out.println(path);
//
//        Komoran komoran = new Komoran(DEFAULT_MODEL.FULL);
//        komoran.setUserDic(path+"/userDictionary/koreanDic.user");
//
//
//        HashMap<String, Integer> crawlerData = new NaverParsing().parsingData("엘든링");
//        JSONArray jsonArray = new JSONArray();
//
//        for(String list : crawlerData.keySet()){
//            System.out.println("key : "+list +"\t"+"value : "+crawlerData.get(list));
//            JSONObject informationObject = new JSONObject();
//            informationObject.put("text", list);
//            informationObject.put("weight", crawlerData.get(list));
//
//            jsonArray.add(informationObject);
//        }
//
//
//
//
//        System.out.println(jsonArray.toJSONString());
//
//    }

}

 

3. DataController

- DataController 클래스는 전체적인 http 요청을 처리하기 위한 controller 클래스이다. MVC 에서 그 C 맞다.

- home 메소드는 말 그대로 home 으로 보내는 메소드이고, sendData 가 메인인 클래스이다. 

- sendData 는 wordcloud 에서 단어를 가져오고 해당 단어로 크롤링하고 파싱을 하고 결과를 hashMap 로 반환한다. 이때 wordcloud 에서 받아오는 word 는 ajax 스타일로 가져온다.

- 이후 html 로 JSON 데이터를 보내는데 JSON 형태로 데이터를 보내기 위해 JSONArray 와 JSONObject 를 각각 선언하여, HashMap 으로부터 key 를 꺼내와서 {x : HashMap 의 key 값, value : HashMap의 key에 대한 value 값} 형태의 json 으로 저장한다. 이후 해당 json 객체를 다시 jsonArray 에 저장한다. 

  • x, value 인 이유는 anychart 가 이러한 x 와 value 형태를 사용하기 때문이다.
  • [{"x":"저","value":7},{"x":"적","value":2},{"x":"다운로드","value":1}] 형태로 저장된다.

- 마지막으로 json 객체가 넣어진 jsonArray 를 wordcloud 에 ajax 스타일로 전달한다.

package HJproject.Hellospring.Controller;

import HJproject.DataMining.NaverParsing;
import lombok.RequiredArgsConstructor;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

@Controller
@RequiredArgsConstructor
public class DataController {
    @GetMapping("/")
    public String home(){
        return "thymeleaf/dataplay/wordcloud";
    }


    @RequestMapping(value = "/getData", method = RequestMethod.GET)
    public void sendData(HttpServletResponse res, HttpServletRequest req) throws IOException {

        // 웹에서 get으로 요청할때 보내온 파라미터 중 word 파라미터를 가져옴
       String word = req.getParameter("word");

        // NaverParsing 클래스의 parsingData 를 실행하고 겨과를 HashMap 로 저장함
        // 이때 파라미터로 웽에서 가져온 word 를 사용
        HashMap<String, Integer> crawlerData = new NaverParsing().parsingData(word);

        // 데이터 저장을 위한 json array
        JSONArray jsonArray = new JSONArray();

        for(String list : crawlerData.keySet()){
            JSONObject informationObject = new JSONObject();
            // JsonArray 에 저장하기 위해서 값을 하나씩 json 형태로 가져와서 x 에 key를 담고 , value  에는 value을 저장함
            // 이때 anychart 의 경우 x 와 value 를 사용하지만
            // JQcloud 의 경우 text 와 weight 를 사용한다.

            // 이후 다시 array 에 담기
            informationObject.put("x", list);
            informationObject.put("value", crawlerData.get(list));

            jsonArray.add(informationObject);
        }

        // 전달하는 값의 타입을 application/json;charset=utf-8 로 하고(한글을 정상적으로 출력하기 위함)
        // printwriter 과 prrint 를 사용하여 값을 response 로 값을 전달함
        // 이때 toJSONString 로 전당하는데 이는 추후 Jsonparsing 을 원활하게 하기 위해서
        // pw 로 값을 전달하면 값이 response body 에 들어가서 보내짐
        res.setContentType("application/json;charset=utf-8");
        PrintWriter pw = res.getWriter();
        pw.print(jsonArray.toJSONString());
        //System.out.println(jsonArray.toJSONString());

    }
}

 

4. WordCloud

- 오늘의, 이번 글의 메인!! word Cloud html 입니다.

- 전체적인 코드는 비교적 간단합니다. css, script, html 모두 고루고루 섞여 있습니다.

- wordcloud 를 만들기 위해서 사용하는 JS 라이브러리는 anychart, JQcloud 로 크게 2가지 입니다. 저는 이 중에서 anychart 를 사용해서 만들도록 하겠습니다. 기능도 그렇고, anychart 가 더 이뻐요ㅠ

- 이제 중요한 JS 와 ajax 부분에 대한 설명을 하겠습니다.

  • 먼저 사이트 로딩시에는 #container 을 숨겨서 보이지 않도록 만듭니다. 처음부터 보이면 되게 이상해요ㅠ
  • 다음으로 버튼을 검색 버튼을 클릭하면 search 함수가 실행되도록 합니다. search 함수는 본인이 입력한 단어 - word - 를 가져와서 ajax 로 서버에 보내줍니다. 
    • 가장 중요한 부분은 ajax 결과에 따른 함수 실행입니다. 서버에서 돌아오는 결과에 따라서 success 와 error 로 나눠집니다. success 는 서버에서 정상적인 결과 - json - 이 return 되었을 때 실행되고, error 은 말 그대로 ajax 로 보냈던 값이 뭔가 에러가 생겨서 서버에서 제대로된 값을 전달해주지 못할 경우 실행됩니다.
    • 이때 서버에서 보내주는 결과란 success 와 error function 의 매개변수인 result 입니다. 즉 서버에서 보내주는 json 은 result 에 담아진다고 생각하면 됩니다.
    • 이외 주의 깊게 보아야하는 부분은 flag 입니다. 이 부분은 검색이 2번 이상 되는 경우 기존에 검색되었던 내용은 삭제하고, 새로운 단어에 대한 검색 결과만 보여줄 수 있도록 합니다.
워드 클라우드 표현 방법!!!
워드 클라우드의 표현은 의외로 간단합니다. 바로 반복 횟수가 곧 글자의 크기가 되는 방식입니다.
예를 들어 {엘든링 : 52}, {PS5:40} 이라는 json 이 넘어왔다면 엘든링은 50px 의 글자 크기가 되고, PS5 는 40px 의 글자 크기가 됩니다. 따라서 굳이 크기 내림차순으로 json 을 따로 정리할 필요는 없고, 그저 어떤 글자가 몇번이나 반복되었는지가 명확하면 됩니다.
  • 마지막으로 nychart 와 jqcloud 에 대한 내용은 해당 사이트와 제가 적어둔 주석들을 참고부탁드립니다
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

    <!--    d3 -->
<!--
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <script src="https://rawgit.com/jasondavies/d3-cloud/master/build/d3.layout.cloud.js" type="text/JavaScript"></script>
-->
    <!--    JQCloud -->
    <!--    <script src="https://cdnjs.cloudflare.com/ajax/libs/jqcloud/1.0.3/jqcloud.min.js" integrity="sha512-gZUG2nobmGEaF3G67OVAmD0lQGbkzN5t9tuiOndqzVNiWBLkCo4o6UBkBLkvKfTPWlVBJPI8dvkLJTwcJbKwvw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>-->
    <!--    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqcloud/1.0.3/jqcloud.css" integrity="sha512-WrGUNi0fHDkVluVxLEbsjpuzBTCiUyTJAFi20txqcKH4V8uEOaRQ+G8LnNMTuvmauaY5J05DzNayZ6RmUMy9FA==" crossorigin="anonymous" referrerpolicy="no-referrer" />-->

    <!--    anyChart -->
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-core.min.js"></script>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-tag-cloud.min.js"></script>


    <style>
        #container {
            width: 800px;
            height: 800px;
            margin: 0;
            padding: 0;
            position: center;
        }

        #img {
            margin-top: 50px;
        }

        .w-btn-outline {
            /*width: 100px;*/
            /*height: 30px;*/
            position: relative;
            padding: 15px 30px;
            border-radius: 15px;
            font-family: "paybooc-Light", sans-serif;
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
            text-decoration: none;
            font-weight: 600;
            transition: 0.25s;
        }

        .w-btn-red-outline {
            border: 3px solid #ff5f2e;
            color: #6e6e6e;
        }

        .w-btn-red-outline:hover {
            background-color: #ff5f2e;
            color: #e1eef6;
            cursor: pointer;
        }

        #txt {
            width: 200px;
            height: 32px;
            font-size: 15px;
            border: 0;
            border-radius: 15px;
            outline: none;
            padding-left: 10px;
            background-color: rgb(233, 233, 233);
        }


    </style>

    <script>
        // 검색 버튼을 총 몇번 클릭했는지 확인하기 위한 변수
        // 1번 이상 검색 시 true 로 변경
        var flag = false;

        $(function () {
            // 사이트 첫 로딩 후 container 감추기
            $("#container").hide();

            // 버튼을 클릭하면 search 함수 실행
            $("#search").on("click", search);

            // 엔터 누르면 search 함수 실행
            $(document).on("keydown", function(e){
                if(e.keyCode == 13){
                    search();
                }
            })

        })

        function search() {

            // 첫번째 검색시에는 flag 가 false 이나 1번 클릭한 후에는 flag 가 true 로 변경 후 아래 코드 실행
            if (flag) {
                // container 에 남아잇는 data 를 전부 지우고 감추기
                $("#container")
                    .empty()
                    .hide();
                console.log(flag)
            }

            flag = true;

            console.log(flag);
            // 검색어가 없으면 얼럿창
            if ($("#txt").val() == "") {
                alert("검색어를 정확히 넣어주세요")
                return;
            }

            // serarch 버튼 누를 시 img 를 loading 로 변경
            $("#img")
                .attr("src", "/wordcloudImg/loading.gif")
                .animate({
                    width: 300,
                    height: 300,
                })
                .css({
                    margin: 250
                })

            // text 태그에 넣은 값을 가져와서 word 에 json 형태로 저장
            var word = {
                word: $("#txt").val()
            }

            // ajax 방식으로 서버에 던짐
            $.ajax({
                url: "/getData", // 보내는 url
                type: "get", // 보내는 방식 post
                data: word, // 보내는 데이터 word 라는 json 형태
                dataType: 'json', <!--서버로부터 받는 값의 데이터 형식-->
                contentType: "application/json;charset=utf-8", // 서버로부터 받는 값의 콘텐츠 형태(인코딩형태?)

                // ajax 로 성공적으로 데이터를 받는 경우 해당 데이터는 success 에 있는 function 을 타게 됨
                // 이때 매개변수로 들어오는 값이 곧 서버에서 받은 값!!
                success: function (result) {
                    // 서버에서 값을 받았음으로 loading 이미지는 필요없기 때문에 감추기!
                    $("#img").hide();

                    // 값을 출력할 container 모습 보이게 하기
                    $("#container").show();

                    // 서버에서 받은 result 라는 데이터를 String 형태로 만든후
                    // 다시 json 형태로 파싱하여 data 라는 변수에 저장한다.
                    var data = JSON.parse(JSON.stringify(result));
                    // console.log(data);

                    // 1. JQCloud 사용 => text : weight
                    // $("#wordcloud").jQCloud(data, {
                    //     width : 800,
                    //     height : 600,
                    //     shape : 'rectangular',
                    //     autoResize: true,
                    //     classPattern: null,
                    //     colors: ["#800026", "#bd0026", "#e31a1c", "#fc4e2a", "#fd8d3c", "#feb24c", "#fed976", "#ffeda0", "#ffffcc"],
                    //     fontSize: {
                    //         from: 0.1,
                    //         to: 0.02
                    //     }
                    // });

                    // 2. anyChart 사용 => t : value
                    var chart = anychart.tagCloud(data);

                    chart.title("My Word Cloud");
                    chart.container("container");

                    chart.hovered().fill("#8711c3");
                    chart.mode("spiral");

                    // 글자 돌아가는거 막게
                    chart.angles([0]);

                    chart.draw();


                },
                // 에러가 발생하면 - 대체적으로 백엔드에서 null 값이 return 되는 경우 - 경고창
                error: function () {
                    alert("정상적이지 않은 요청입니다. 다시 시도해주세요")
                    location.reload();
                }



            })
        }
    </script>


</head>
<body>
<center>
    <div id="div">
        <img src="/wordcloudImg/search.jpg" id="img">
        <div id="container" align="center"></div>
    </div>

    <input type="text" name="" id="txt">
    <!--<input type="button" value="검색" id="search">-->
    <input type="button" class="w-btn-outline w-btn-red-outline" id="search" value="검색">
</center>


</body>
</html>

 


Reference

- 형태소 분석기 komoran : 너무나도 감사한 open API

https://komorandocs.readthedocs.io/ko/latest/index.html

 

KOMORAN 문서 — KOMORAN documentation

© Copyright 2019, shineware Revision 96fcc79c.

komorandocs.readthedocs.io

 

- 네이버 api 사용법 및 parsing : 어려웠던 검색 api 사용법 및 parsing 를 어떻게 해야하는지 방향을 잡을 수 있었던 글

https://needjarvis.tistory.com/658

 

[Java] 네이버 검색 API 등록 및 호출하기

네이버 검색 API 등록 모든 API가 그러하지만 네이버 검색도 사용하기 위해서는 우선적으로 API 등록해서 키를 발급받아야 한다. developers.naver.com/docs/search/blog/ 검색 API 블로그 검색 개발가이드 NAVER

needjarvis.tistory.com

 

- JQcloud

http://mistic100.github.io/jQCloud/index.html

 

jQCloud

Apply the plugin to a container (preferably a ) and provide at least a list of words (see Words options section). Container dimensions & position The cloud container must have defined dimensions, either via CSS or via th width and height options. Additiona

mistic100.github.io

 

- java JSON 다루기

https://ktko.tistory.com/entry/JAVA%EC%97%90%EC%84%9C-JSON-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0

 

JAVA에서 JSON 데이터 만들기

JAVA에서 JSON 데이터 만들기 먼저 JSON을 사용하기 위해 JSON에 필요한 라이브러리(jar)이 필요하다. 직접 다운받거나, Spring를 사용할 경우 Depencency를 추가하면 된다. JSON 다운로드 http://code.google.c..

ktko.tistory.com

 

- anychart

https://docs.anychart.com/Basic_Charts/Tag_Cloud

 

Tag Cloud | Basic Charts | AnyChart Documentation

A tag cloud, otherwise known as a word cloud or weighted list, is a visual representation of text data. This chart is typically used to show keyword (t

docs.anychart.com

 

- JSON, CSS , JS 설명

https://poiemaweb.com/

 

웹 프로그래밍 튜토리얼 | PoiemaWeb

Front-end Development Tutorial

poiemaweb.com

 

- java 크롤링 정리

https://coldmater.tistory.com/125?category=734491 

 

[SMHRD] [171016] JAVA 크롤러 만들기 2 - 리뷰 크롤링, 이미지 IO, 웹툰 크롤링

리뷰 수집 크롤러 JAVA 의 파일입출력기능(스트림)과 jsoup 라이브러리를 활용하여 리뷰를 수집하는 크롤러를 작성해보자. package com.company; import java.io.FileWriter; import java.io.IOException; import..

coldmater.tistory.com

 

댓글