스트링부트 웹 크롤링 하는 방법[Jsoup]
Jsoup 사용하는 방법
Jsoup는 자바 언어로 HTML을 쉽게 파싱할 수 있게 도와주는 라이브러리이다.
1.Maven 저장소에서 Jsoup 코드를 복사해서 pom.xml 파일에 붙여넣기 한다.
<dependencies>
<!-- 추가한 라이브러리 시작 -->
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.13.1</version>
</dependency>
<!-- 추가한 라이브러리 끝 -->
<!-- 중략 -->
</dependencies>
의존성 관리 도구 Maven 저장소 활용하는 방법Maven이란 공통 레퍼지토리로 보통 라이브러리가 서로 연관성이 있는 경우, 연관되어 있는 라이브러리를 모두 다운 받아야하는데, 이 저장소를 활용하면 상위 라이브러리만 가져오면 하위 라이브러리도 자동으로 가져오게 된다....
Jsoup 라이브러리가 먹히지 않을 경우 STS를 다시 시작해 보세요.
2.url에서 HTML 문서 가져온다.
Document doc = Jsoup.connect(url).get();
3.HTML에서 원하는 요소를 가져온다.
Elements elem = doc.select("#articleTitle");
네이버 뉴스 기사 웹 크롤링하기
HTTP 서버와 통신하는 방법
RestTemplate는 spring 3.0부터 지원하는 HTTP 서버와 통신하는 방법 중 하나로 기계적이고 반복적인 코드를 최대한 줄여주며 json, xml 응답에 적합하다. 그 외에도 HTTP 서버와 통신하는 방법으로 자바에서는 HttpUrlConnection, okHttp, RestTemplate, Retrofit2 등을 사용할 수 있다. (파이썬에서는 requests 사용).
Jsoup만 사용해서 통신을 할 수 있으나 여기서는 RestTemplate 사용법을 익히고자 두 가지 방법을 모두 사용한 방법을 소개한다.
네이버 뉴스 기사 HTML 분석하기
정치 카테고리에 있는 뉴스 기사 제목과 기사 발행일을 크롤링하려고 합니다. 여기서 뉴스 기사 제목과 기사 발행일을 추출하기 위한 id/class 값을 분석합니다. 뉴스 기사 제목은 유일한 값인 id값 ‘articleTitle’을 사용하면 되고, 기사 발행일은 class값으로 ‘.t11’이 주어져 있는데 다른 곳에서 사용하고 있는지 document.querySelect()를 사용해서 확인해 봅니다. 여기서는 ‘.t11’가 두 군데 사용되고 있어서 [0]번째를 사용하기로 합니다.
크롤링 정보를 한번에 담을 객체 생성
package com.cos.newssave.batch; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @Builder @AllArgsConstructor @Data public class NewsTest { private String title; private String time; }
RestTemplate 사용
package com.cos.newssave.batch; import java.util.ArrayList; import java.util.List; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; public class NaverCrawTest { int aidNum = 1; @Test public void test3() { RestTemplate rt = new RestTemplate(); //RestTemplate 객체 생성 List<NewsTest> nts = new ArrayList<>(); //수집한 collections를 담기 위한 리스트 for(int i = 1; i < 11; i++) { String aid = String.format("%010d", aidNum); //10자리 숫자를 만들기 위한 문자열 포맷 String url = "https://news.naver.com/main/read.naver?mode=LSD&mid=shm&sid1=100&oid=003&aid="+aid; //사용할 네이버 뉴스 기사 주소 String html = rt.getForObject(url, String.class);//해당 주소에서 html을 담아준다. Document doc = Jsoup.parse(html);//html 문서를 Jsoup 도큐먼트에 담아준다. Element titleElement = doc.selectFirst("#articleTitle"); //뉴스 기사 제목 요소를 가지고 온다. Element timeElement = doc.selectFirst(".t11"); //기사 발행일 요소를 가지고 온다. String title = titleElement.text(); //html 태그를 제거하고 텍스트만 가지고 온다. String time = timeElement.text(); System.out.println(title); System.out.println(time); NewsTest nt = NewsTest.builder() //크롤링 정보를 담아줄 객체를 만든다. .title(title) .time(time) .build(); nts.add(nt); //리스트에 객체를 더해준다. aidNum++; //반복문을 돌 때마다 기사 아이디를 더해준다. } //System.out.println(nts.size()); //assertTrue(nts.size() == 11); JUnit으로 테스트 통과하는지 알 수 있다. } }
<결과 화면>
RestTemplate 미사용
package com.cos.newssave.batch; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; public class NaverCrawTest { int aidNum = 1; @Test public void test4() { RestTemplate rt = new RestTemplate(); List<NewsTest> nts = new ArrayList<>(); // collections for (int i = 1; i < 11; i++) { String aid = String.format("%010d", aidNum); String url = "https://news.naver.com/main/read.naver?mode=LSD&mid=shm&sid1=100&oid=003&aid=" + aid; try { Document doc = Jsoup.connect(url).get(); Element titleElement = doc.selectFirst("#articleTitle"); Element timeElement = doc.selectFirst(".t11"); String title = titleElement.text(); String time = timeElement.text(); System.out.println(title); System.out.println(time); NewsTest nt = NewsTest.builder().title(title).time(time).build(); nts.add(nt); aidNum++; } catch (IOException e) { e.printStackTrace(); } } System.out.println(nts.size()); } }