본문 바로가기
프로그래밍/Java

Java 매달, 첫번째 월요일 확인 예제

by Mr-후 2020. 6. 29.
반응형

매주 월요일, 특정 정보를 수집하도록 만들어진 크롤러가 있다. 이 크롤러는 특정 사이트의 링크정보를 조합, 동적 URL을 생성하고 해당 URL로 접속했을 때 나오는 데이터를 수집하는 기능이 있다. 

URL을 만드는데 소요되는 시간이 약 20분정도, 이 시간을 아껴보고자 CSV파일을 이용, 동적 URL에 들어가는 파라미터 정보를 사전에 수집, 파일로 생성한 다음 실제 크롤링을 할 때 생성되어 있는 파라미터정보(CSV파일)를 읽어서 사용하도록 했다. 

처음에는 상당한 시간을 단축할 수 있었다. 그런데 시간이 지나면서 조금씩 문제가 나타나기 시작했다 동적으로 생성한 URL의 파라미터 값들이 변경되는 즉, 메인 페이지의 링크정보가 변질 또는 없어지는 경우가 발생하면서 순차적인 리스팅 크롤링이 되지 않는 현상이 나타났는데 자주 발생하는 수준은 아니었고 3~4개월에 1~2회 정도 현상이 나타났다.

데이터베이스를 이용하면 컬럼 값을 변경함으로써 손쉽게 다시 생성할 수 있고 크롤링이 쉽게 컨트롤되지만 애초에 데이터베이스를 이용하지 않는 구조로 설계를 했기 때문에 현시점에서 해당 로직을 추가하고 싶지 않다. 

우선, 정책을 정의했다.

매달, 첫번째 월요일 크롤러가 실행될 때 기존에 만들어진 CSV파일의 동적 URL정보를 초기화(RESET)하고 다시 생성하는 것으로 정의하였다. 

따라서, Java 언의 날짜 핸들링 관련 함수들이 필요하게 되었고 서비스 로직에 맞는 함수를 몇 개 추가했다. 구글 검색을 통해 다양한 정보를 기반으로 내가 필요로 하는 부분만 취합하여 로직을 만들고 월과 요일을 바꿔가면서 테스트를 진행했다. 

각 달의 첫주는 지난달과 엮어 있을 수도 있고 없을 수도 있기 때문에 조금 주의가 필요한 부분도 있었다. 

먼저, 현재 년도와 월을 받아올 수 있는 static함수를 추가하였다. 

    /**
     * 주어진 타입에 따라 현재의 년, 월, 일을 리턴한다.
     * @param calendarType
     * @return
     */
    public static String getCurrentDate(int calendarType) {
        Calendar cal = Calendar.getInstance();
        if (calendarType == Calendar.YEAR) {
            return String.valueOf(cal.get(cal.YEAR));
        } else if(calendarType == Calendar.MONTH) {
            return String.valueOf(cal.get(cal.MONTH)+1);
        } else if (calendarType == Calendar.DAY_OF_MONTH) {
            return String.valueOf(cal.get(cal.DAY_OF_MONTH));
        }
        return "";
    }

다음은 주어진 년도와 월을 인자로 받아 해당 년/월의 첫번째 월요일의 날짜(일자)를 리턴하는 static함수를 추가하였다. 

    /**
     * 특정 년/월 의 첫번째 월요일 일자를 구한다.
     * @param year
     * @param month
     * @return
     */
    public static String getWeekInMonths(String year, String month) {
        Calendar cal = Calendar.getInstance();
        int intYear=Integer.parseInt(year);
        int intMonth=Integer.parseInt(month);

        cal.set(Calendar.YEAR, intYear);
        cal.set(Calendar.MONTH, intMonth);

        String findOfFirstMondayOfMonth = "";
        for (int week = 1; week < cal.getMaximum(Calendar.WEEK_OF_MONTH); week++) {
            cal.set(Calendar.WEEK_OF_MONTH, week);
            cal.set(Calendar.DAY_OF_WEEK, Calendar.MONTH);
            int startDay = cal.get(Calendar.DAY_OF_MONTH);
            int dayNum = cal.get(Calendar.DAY_OF_WEEK);

            if (dayNum == 2 && startDay < 8) {
                findOfFirstMondayOfMonth = String.valueOf(startDay);
                break;
            }
        }
        return findOfFirstMondayOfMonth;
    }

해당 년/월의 주를 구하고 그 주의 시작일자를 구한다. 다음 그 시작 요일이 월요일이면 탐색을 중지하고 시작일자를 리턴하도록 하였다. 

다음은 오늘이 그 년/월의 첫번째 월요일인지 체크한다. 

    /**
     * 오늘일자가 그 달의 첫번째 월요일인지 체크한다.
     * @return
     */
    public static boolean todayIsFirstMondayOfThisMonth() {
        String thisYear = TimeUtils.getCurrentDate(Calendar.YEAR);
        String thisMonth = TimeUtils.getCurrentDate(Calendar.MONTH);
        String today = TimeUtils.getCurrentDate(Calendar.DAY_OF_MONTH);

        String firstMondayOfMonth = getWeekInMonths(thisYear, thisMonth);
        return today.equals(firstMondayOfMonth);
    }

크롤러가 실행되는 날 만약, true가 리턴된다면 기존에 생성해둔 CSV파일의 데이터는 초기화되고 처음부터 다시 동적URL정보를 크롤링한다음 파일을 채워 나가고 크롤링이 시작되도록 하였다. 

 

 

반응형