뉴닉 클론 코딩 중 크롤링으로 한겨레에 있는 기사들을 가져왔다.
기사 전체를 조회할 때 DB 에 저장되도록 구성했는데, (직접 저장)
scheduler 를 이용한다면 매번 직접 조회를 하면서 DB 에 저장할 필요 없이 자동적으로 데이터가 갱신된다 (한 번 직접 저장 후에는 계속 자동 갱신)
@EnableScheduling
@SpringBootApplication
public class SixneekApplication {
public static void main(String[] args) {
SpringApplication.run(SixneekApplication.class, args);
}
}
application 에서 @EnableScheduling
를 설정해줘야 한다.
스케줄링은 간단하다.
크롤링해오는 로직에 @Scheduled(cron = "0 0 /2 * *") 어노테이션만 추가되었을 뿐이다.
단, 기본적으로
void
반환 타입을 사용하며,매개변수가 없는
메서드이어야 한다.
@Service
@Slf4j(topic = "Scheduler")
@RequiredArgsConstructor
public class CrawlingArticle {
private final ArticleRepository articleRepository;
// 크롤링: 전체 기사 조회
@Scheduled(cron = "0 0 */2 * * *") // 2시간 마다 기사 업데이트
public List<ArticleListResponseDto> saveArticleList() throws IOException {
articleRepository.deleteAll();
List<ArticleListResponseDto> articleResponseDtoList = new ArrayList<>();
long currentId = 1;
for (int i = 1; i <= 10; i++) {
String Article_URL = "https://www.hani.co.kr/arti/list" + i + ".html";
articleResponseDtoList.addAll(processUrl(Article_URL, currentId));
currentId += 15;
}
log.info("뉴스 기사 크롤링 완료");
return articleResponseDtoList;
}
// Url 처리하기
private List<ArticleListResponseDto> processUrl(String url, long currentId) throws IOException {
Document document = Jsoup.connect(url).get();
Elements contentList = document.select("div div.section-list-area div.list");
List<ArticleListResponseDto> articleResponseDtoList = new ArrayList<>();
for (Element contents : contentList) {
String image = contents.select("a img").attr("abs:src"); // 이미지
String title = contents.select("h4 a").text(); // 제목
String date = contents.select("p span").text().substring(0, 10).replaceAll("-", "/"); // 날짜
String tag = contents.select("strong a").text(); // 섹션(태그)
String articleLink = contents.select("h4 a").attr("abs:href"); // 내용
Document articleDocument = Jsoup.connect(articleLink).get();
String content = articleDocument.select("div div.text").text();
Article article = Article.builder()
.id(currentId++)
.image(image)
.title(title)
.tag(tag)
.date(date)
.content(content)
.build();
articleRepository.save(article);
articleResponseDtoList.add(new ArticleListResponseDto(article));
}
return articleResponseDtoList;
}
...
}
@Slf4j
@Slf4j 를 사용한다면, log 인스턴스 를 사용할 수 있게 된다.
topic 은 로그 분류를 위해 사용된다.
@Scheduled(cron = "0 0 */2 * * *")
초, 분, 시, 일, 월, 주 순서
@Scheduled 공식문서 에서 업데이트 할 시간을 참고해서 설정할 수 있다.
@Slf4j(topic = "Scheduler")
@Service
@RequiredArgsConstructor
public class NotificationScheduler {
private final NotificationRepository notificationRepository;
// 6시간 마다 생성일 기준 2일 지난 알림 삭제
@Scheduled(cron = "0 0 */6 * * *")
public void deleteNotification() {
LocalDate twoDaysAgo = LocalDate.now().minusDays(2);
List<Notification> notificationsToDelete = notificationRepository.findByCreatedAtBefore(twoDaysAgo);
notificationRepository.deleteAll(notificationsToDelete);
log.info(notificationsToDelete.size() + "개 알림 삭제 완료");
}
}