영화 데이터 접근 방식의 변화를 가져온 네이버 영화 API의 서비스 종료에 대응하기 위해, CGV 웹사이트에서 직접 데이터를 크롤링하는 방안이 필요하게 되었다. 이 글에서는 데이터 수집을 목표로, Quartz 스케줄링 라이브러리를 사용하여 특정 시각에 자동화된 크롤링을 실행하는 시스템을 구축하고자 한다.
Quartz 라이브러리 통합
스케줄러 구성 및 초기화
StdSchedulerFactory
를 통해 인스턴스화되며, 스케줄러의 기본 설정을 로드하여 작업 스케줄링 환경을 구축한다. 스케줄러는 시스템의 중앙에서 모든 작업을 관리하며, 정해진 시간에 작업을 실행한다.Job 클래스의 구현
Job
인터페이스를 구현하여 MyJob
클래스를 정의한다. 이 클래스 내에서는 실제 크롤링 로직이 포함되어 있으며, execute
메소드는 스케줄된 시간에 자동으로 호출된다. 이 메소드는 CGV 웹사이트에 접근하여 필요한 영화 데이터를 추출하고 처리하는 역할을 한다.트리거 설정 및 작업 등록
SimpleTrigger
와 CronTrigger
를 사용한다.작업 실행 및 모니터링
MyJob
의 execute
메소드가 호출된다. 크롤링 로직이 실행되며, 실행 과정 중 발생할 수 있는 예외를 적절히 처리하고, 실행 상태와 결과를 로깅한다.<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzSchedulerExample {
public static void main(String[] args) {
try {
// 스케줄러 팩토리에서 스케줄러 가져오기
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 스케줄러 시작
scheduler.start();
// JobDetail 생성
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
// Trigger 생성 (매일 자정에 실행)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(0, 0))
.build();
// JobDetail과 Trigger를 스케줄러에 등록
scheduler.scheduleJob(job, trigger);
} catch (SchedulerException se) {
se.printStackTrace();
}
}
}
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 크롤링 작업 로직 구현
System.out.println("Executing job at " + context.getFireTime());
// 예: 크롤링 및 데이터 저장 로직
crawlAndSaveMovies();
}
private void crawlAndSaveMovies() {
// 크롤링 및 DB 저장 로직 구현
System.out.println("Crawling and saving movies...");
}
}
간단한 반복 트리거 (SimpleTrigger):
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("simpleTrigger", "group1")
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10) // 10초마다 실행
.repeatForever())
.build();
크론 트리거 (CronTrigger):
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("cronTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 * * ?")) // 매일 자정에 실행
.build();
Quartz는 작업 및 트리거의 상태를 모니터링하기 위해 리스너를 제공한다. 예를 들어, 작업이 시작되거나 완료될 때 특정 작업을 수행할 수 있다.
JobListener 구현:
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.listeners.JobListenerSupport;
public class MyJobListener extends JobListenerSupport {
@Override
public String getName() {
return "MyJobListener";
}
@Override
public void jobToBeExecuted(JobExecutionContext context) {
System.out.println("Job is about to be executed: " + context.getJobDetail().getKey());
}
@Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
System.out.println("Job was executed: " + context.getJobDetail().getKey());
}
}
리스너 등록:
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.getListenerManager().addJobListener(new MyJobListener());
Quartz는 작업 및 트리거 정보를 저장하는 방법을 정의하는 여러 JobStore를 제공한다. 기본적으로 RAMJobStore가 사용되지만, 영구 저장을 위해 JDBCJobStore를 사용할 수 있다.
Quartz 프로퍼티 설정 (quartz.properties
):
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.dataSource.myDS.driver = com.mysql.cj.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz
org.quartz.dataSource.myDS.user = quartz
org.quartz.dataSource.myDS.password = password
org.quartz.dataSource.myDS.maxConnections = 5
데이터베이스 스키마 설정: Quartz가 사용할 테이블을 데이터베이스에 생성한다. Quartz의 스키마 파일을 사용하여 테이블을 생성할 수 있다.
StdSchedulerFactory
를 사용하여 스케줄러를 설정하고 시작한다.Job
인터페이스를 구현하여 작업을 정의한다.SimpleTrigger
또는 CronTrigger
를 사용하여 작업 실행 주기를 설정한다.JobListener
및 TriggerListener
를 사용하여 작업 및 트리거 상태를 모니터링한다.JobStore
를 설정한다.이와 같은 방식으로 Quartz를 사용하여 다양한 스케줄링 요구 사항을 충족할 수 있다. 필요에 따라 트리거를 조정하고, Job 클래스의 로직을 수정하여 다양한 작업을 수행할 수 있다.
이 프로젝트를 통해 구축된 자동화된 크롤링 시스템은 데이터의 신뢰성을 보장하고, 데이터 접근성을 대폭 향상시켰다. 또한, Quartz 스케줄러의 정밀한 작업 관리 기능은 작업 실행의 정확성을 보장하며, 다양한 작업 스케줄링 요구 사항에 유연하게 대응할 수 있도록 한다. 향후 이 시스템은 추가적인 데이터 소스 통합과 더욱 복잡한 스케줄링 요구 사항에 대응하기 위해 지속적으로 개선될 예정이다.