[java] 백준 크롤링 + 파일 입출력 자동화 코드

김민주·2022년 9월 16일
0

Git에 푼 문제들 하나씩 올리다 보니
문제와 예제를 일일이 쓰는 것이 귀찮아져서
문제 이름 + 번호 + 입출력 + 예제입출력 을 적어주는

자동화 코드 를 만들었다.





1. 기본파일 생성


먼저 마크다운 파일을 생성 후 "문제 번호 " 이름으로 저장 후
  • 내가 생성한 기본 골격
# TIL

<br>

풀이
```java
이곳에 나의 코드를
적는다```

푼 문제를 풀이 안에 직접 넣고,
자동화 코드를 돌리면 된다!



2. F12


개발자 도구에서 태그들을 미리 살펴보고

select 메소드를 이용하면

class는 .
id는 #

을 통해 접근하여 원하는 값을 추출하였다.



3. JSOUP 라이브러리


JSOUP 다운 후 프로젝트에 추가한 후

파일 명의 문제 번호를 가지고 파일을 재 생성하였다.



4. html파싱 및 파일입출력 코드 작성




code

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;


public class Main {

    /* 자동화시킬 기본 형태 (파일이름: 문제번호 )
    # TIL

    <br>

    풀이
    ```java
    여기는 내가 푼 코드 직접 추가
    ```

     */


    static String title; // 문제번호 + 문제이름
    static String titleName; // 문제이름
    static String problem_text; //문제 내용
    static String input_text; // 문제 입력
    static String output_text; // 문제 출력
    static String sample_input_text; // 예제 입력 1
    static String sample_output_text; // 예제 출력 1


    public static void main(String[] args) throws Exception {

        String path = "C:\\2022\\TIL\\baekjoon\\Step\\파일경로";
 
        File folder = new File(path);
        Loop1:
        for (File file : folder.listFiles()) {
            boolean isModify = false;
            if (!file.isDirectory()) {
                String fileName = file.getName();
                BufferedReader br = new BufferedReader(new FileReader(path + "\\" + fileName));
                File newFile = new File(path + "\\" + fileName + ".md"); //일단 복사본 만들기위해 .md 추가해놓고 나중에 원래이름으로 덮어쓰기
                FileWriter fw = new FileWriter(newFile, true);

                fileName = fileName.split(" ")[0]; //문제번호만
                getDataFromUrl(fileName);

                String str;
                Loop2:
                while ((str = br.readLine()) != null) {

                    if (str.contains("# TIL")) {

                        Date date = new Date(); //파일 내용에 넣을 날짜
                        SimpleDateFormat formatter = new SimpleDateFormat("MMdd");

                        fw.write("# TIL" + "\r\n");
                        fw.write("\r\n" + "## " + formatter.format(date) + "\r\n");
                        //크롤링해온 data들 파일에 추가
                        fw.write("\r\n"+ "## " +"백준 " + title + "\r\n" + "<br><br>");
                        fw.write("\n" + "문제\n" + "```\n" + problem_text + "\n```");
                        fw.write("\n" + "입력\n" + "```\n" + input_text + "\n```");
                        fw.write("\n" + "출력\n" + "```\n" + output_text + "\n```" + "\n<br>\n");
                        fw.write("\n" + "예제 입력\n" + "```\n" + sample_input_text + "\n```");
                        fw.write("\n" + "예제 출력\n" + "```\n" + sample_output_text + "\n```" + "\n<br>\n");
                    } else if (str.contains("## ")) { //이미 수정된 파일이라면 건드리지 않는다
                        isModify = true;
                        fw.flush();
                        fw.close();
                        br.close();
                        newFile.delete();
                        break; //Loop2
                    } else fw.write(str + "\r\n");
                }

                if(!isModify) {
                    fw.flush();
                    fw.close();
                    br.close();

                    file.delete();//기존 파일 지우고 재생성
                    newFile.renameTo(new File(path + "\\" + fileName + " " + titleName + ".md"));
                }
            }
        }
    }
    private static void getDataFromUrl(String problemNum) throws Exception {

        //baekjoon 사이트 데이터 가져오기
        String URL = "https://www.acmicpc.net/problem/" + problemNum;

        // Document = jsoup으로 크롤링해온 HTML 문서
        Document doc = Jsoup.connect(URL).get();
        // Element = Document의 HTML 요소
        // Elements = element가 모인 자료형
        Elements titleElements = doc.select("div.col-md-12 > div.page-header");//2개의 div class 하위로 묶여짐

        title = titleElements.get(0).text(); // 번호 - 문제이름
        int target = title.indexOf("-");
        titleName = title.substring(target + 2); // 번호뺀 문제이름

        /*
        class 는 .으로 select, id는 #으로 select, >로 하위로 연결
        Elements problem = doc.select("div#problem-body > div:nth-child(1) > section#description > div#problem_description > p");
        */

        Elements problemElem = doc
                .select("div#problem-body")
                .select("div:nth-child(1)")
                .select("section#description")
                .select("div#problem_description > p");
        

        /*
        problem_text = problemElem.get(0).html()
        로 string 을 가져오게 되면
        <p> 한개만 가져와서 여러 개인 경우 젤 윗 문장만 가져오게 됨
        -> iterElement 함수 사용
        */
        
        problem_text = iterElement(problemElem);
        problem_text = replaceTag(problem_text);

        System.out.println(problem_text);
        Elements inputElem = doc.select("div#problem_input > p");
        input_text = iterElement(inputElem);
        //input_text = inputElem.get(0).html();
        input_text = replaceTag(input_text);

        Elements outputElem = doc.select("div#problem_output > p");
        output_text = iterElement(outputElem);
        //output_text = outputElem.get(0).html();
        output_text = replaceTag(output_text);

        Elements sampleInputElem = doc.select("pre#sample-input-1");
        sample_input_text = sampleInputElem.get(0).html();
        sample_input_text = replaceTag(sample_input_text);

        Elements sampleOutputElem = doc.select("pre#sample-output-1");
        sample_output_text = sampleOutputElem.get(0).html();
        sample_output_text = replaceTag(sample_output_text);

    }

    private static String iterElement(Elements elements){
        // 문제설명이 p 태그 여러개 있는 경우도 있음 -> itertor 순회하여 스트링빌더로 추가
        StringBuilder builder = new StringBuilder();
        for (Element row : elements) {
            Iterator<Element> iterElem = row.getElementsByTag("p").iterator();
            builder.append(iterElem.next().text() + "\n");
        }
        //마지막줄의 줄바꿈 지우기
        builder.deleteCharAt(builder.length()-1);
        System.out.println(builder.toString());
        return builder.toString();
    }
    
    private static String replaceTag(String txt) {
        String ret;
        //줄바꿈 치환
        ret = txt.replace("&nbsp;", "\r\n");
        //html태그들 치환
        ret = ret.replaceAll("<(/)?([a-zA-Z]*)(\\s[a-zA-Z]*=[^>]*)?(\\s)*(/)?>", "");
        return ret;

    }

}



결과

아래와 같은 형태의 파일이 만들어진다

이로써 편하게 이제 코드만 복붙하면 된다~~~!!
코드가 좀 지저분하긴 하지만 ...
귀찮아서 그냥 다 복붙했었는데 역시 만들고 나니 아주 편하다👍👍
소스가 있겠지만

파싱 & 파일 입출력 공부할 겸 만들어봤다😊

다시 열심히 문제 풀러 가자ㅏ~~

profile
𝐃𝐨𝐧'𝐭 𝐛𝐞 𝐚 𝐩𝐫𝐨𝐜𝐫𝐚𝐬𝐭𝐢𝐧𝐚𝐭𝐨𝐫💫

0개의 댓글