프로젝트를 만들다가 데이터가 필요하면
첫 번째로 API를 찾아봐야 한다.
웹 크롤링을 방지하기 위해 네이버에서 제공해주는 API가 많이 있다.
다른 사이트에서도 API를 제공해주는 곳이 있기 때문에
첫 번째로는 API를 찾아봐야 한다.
API가 없다면 실제 사이트에 검색을 해서 데이터를 찾아본다.
최초 URL 주소에는 모든 데이터들이 다운로드 되어있지 않은 페이지가 있을 수 있다.
이런 페이지는 fetch로 다운 받아서 CSR 그림을 그린다.
내가 최초 URL로 데이터를 받으려고 하면
그 사이트가 fetch로 다운 받은 데이터까지 나오지 않는 것이다.
이때 CSR로 그려진 데이터까지 다운 받기 위해서는 두 가지 방법이 있다.
첫째. wait 사용
해당 사이트가 fetch 다운로드가 다 끝나지 않았기 때문에 완성되지 않은 그림이 받아진 것이니까
요청한 후 5초 정도 wait를 걸어두었다가 다운 받으면 데이터까지 받을 수 있다.
둘째로 wait보다 더 간편한 방법이 있다.
어차피 내부적으로 fetch를 할 거니까
F12를 눌러서 네트워크를 보면 무조건 다 나와있다.
네트워크 창에서 Ctrl + R 해서 보면 모든 요청 데이터들이 있는데
보통 쿼리 스트링으로 요청하니까 쿼리 스트링을 사용한 요청을 살펴보자.
얘를 인터넷 주소창에 검색해보면
주소에 제주시 식당이 찍힌 것만 봐도 fetch로 데이터를 다 받아온 것을 확인할 수 있다.
api를 제공해주진 않지만 얘들도 내부적으로 fetch 해서 json으로 받은 데이터이기 때문에
다 긁어올 수 있다.
RestTemplate는 httpURLConnection보다 쉽게 바로 다운 받을 수 있다.
이렇게 쉽게!
RestTemplate rt = new RestTemplate( );
String body = rt.getForObject("다운받을 주소", String.class);
이 주소를 rt.getForObject의 주소 자리에 넣어주면
데이터를 다운 받을 수 있다.
주소를 넣어줄 때 query의 밸류 값이 인코딩 되어 들어가는 부분에
내가 원하는 검색어를 넣어주면 된다.
잘 받아진다.
RestTemplate에 파싱 할 오브젝트 타입(String.class)을 걸어주기만 하면
RestTemplate가 다 파싱 해준다.
내가 날씨가 궁금하면 데이터를 어디서 받아와야 할까?
날씨 데이터는 공공데이터로 받아와도 되지만
크롤링해오면 빠르겠다.
날씨 검색을 해보면 주소창에 get요청 주소가 남아있다.
이 주소를 getForObject에 넣어줘 보자.
데이터를 잘 다운 받아오긴 했지만
다운 받은 데이터는 json이 아닌데 어떻게 파싱 할까?
애초에 json으로 내부적으로 통신하는 애들은 파싱 하기 쉬운데
html을 그대로 주면 더 힘들다.
내가 필요한 건 6도라는 숫자인데 브라우저에서
숫자 위에 우클릭하여 검사해보면
딱 얘만 필요하다.
얘는 documentQuerySelector로 찾을 수 있겠다.
자바에서는 이게 안되니까 jsoup라는 라이브러리를 다운로드하여준다.
jsoup는 자바로 html을 파싱 하는 라이브러리이다.
https://mvnrepository.com/artifact/org.jsoup/jsoup/1.14.3
Gradle을 복사해서 build.gradle 파일의 dependencies 안에 추가해주기만 하면 된다.
추가해주고 오른쪽 아래 다운로드가 끝나면 이제 jsoup를 사용해보자.
jsoup를 쓰면 좋은 게 RestTemplate를 사용하지 않고
Jsoup.connect("주소").get( )으로 바로 다운로드할 수 있다.
사용해보자.
@Test
public void 크롤() {
try {
Document doc = Jsoup
.connect("https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=날씨")
.get();
System.out.println(doc);
} catch (IOException e) {
e.printStackTrace();
}
}
doc를 출력해보니 html을 받아왔다.
다운 받은 데이터를 Document객체에 넣으면 이제 파싱이 가능하다.
아까 날씨 숫자 근처에 있던 클래스 이름으로 파싱 해주자.
doc.select의 리턴 타입이 Elements이다.
파싱 된 결과가 하나일 수도 있고 여러개일 수도 있기 때문이다.
Elements arr = doc.select(".temperature_text");
이 arr에 어떤 값이 저장되었는지 for each문을 돌며 콘솔에 찍어보자.
Elements는 Element들의 모임이다.
for (Element e : arr) {
System.out.println(e);
}
여러 개의 데이터가 나온다.
찾았으니까 이제 얘들이 들고 있는 텍스트를 출력하면 끝이다.
for (Element e : arr) {
System.out.println(e.text());
}
내가 html을 다운받으려면? Jsoup 사용
html을 다운받고 보니 데이터가 없다?
-> 내부적으로 fetch 요청 일어난 것
-> 이거 파싱 하는 게 더 쉽다
[출처]
https://cafe.naver.com/metacoding
메타 코딩 유튜브
https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9