관리 메뉴

miinsun

[Spring] 네이버 블로그 검색 API 사용하기 본문

WebApp/Spring

[Spring] 네이버 블로그 검색 API 사용하기

miinsun 2022. 2. 18. 03:36

 

네이버 블로그 검색 결과를 프로젝트에 사용하기 위해서 네이버 open api를 이용해보았다.

Naver Developers의 공식문서를 많이 참고해가면서 나름대로 활용했다.
이것보다 효율적으로 사용할 수 있는 방법도 있을것 같으니 시간이 되면 한번 찾아봐야겠다.

 

 

1. 클라이언트 키 발급

 

애플리케이션 - NAVER Developers

 

developers.naver.com

먼저 위 사이트에 접속해서 클라이언트 키를 발급받자

  • 애플리케이션 이름: 프로젝트, 서비스를 대표하는 이름
  • 사용 API: 블로그 검색 같은 경우 데이터랩(검색어트렌드)를 선택하면 된다.
  • 웹 서비스 URL: 로컬 환경에서 개발하는 경우, 'http://127.0.0.1:포트번호' 를 입력해주면 된다.

 

2. API 관리

 

[Spring] API 키 관리하는 방법

지금 만들고 있는 프로젝트에서 카카오, 네이버와 같은 여러 외부 API를 사용해야 되서 따로 API KEY를 관리 할 필요를 느꼈다. 나는 properties 파일을 이용해 API KEY를 숨겨보았다. 빌드 툴은 Maven을

miinsun.tistory.com

Api Key를 숨겨 보관하기 위해서는 위 게시글을 참고해서 Key 세팅을 해주자.

로컬 개발인 경우에는 이 과정을 생략해도 상관없다.

 

3. NaverBlogSearchApi.java 파일 생성

//네이버 검색 API - blog 검색
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class NaverBlogSearchApi {
	@Value("${NAVER-CLIENT}")
	String clientId;
	@Value("${NAVER-KEY}")
    String clientSecret;
	
	public String search(String query) {
		try { // 검색어 인코딩
			query = URLEncoder.encode(query, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("검색어 인코딩 실패",e);
        }
		
        // URL 세팅
		String apiURL = "https://openapi.naver.com/v1/search/blog?query=" + query; 
		
		Map<String, String> requestHeaders = new HashMap<>();
        requestHeaders.put("X-Naver-Client-Id", clientId);
        requestHeaders.put("X-Naver-Client-Secret", clientSecret);
        String responseBody = get(apiURL,requestHeaders);
        System.out.println(responseBody);
        
        return responseBody;
	}
	
	private String get(String apiUrl, Map<String, String> requestHeaders){ // Get 호출
        HttpURLConnection con = connect(apiUrl);
        try {
            con.setRequestMethod("GET");
            for(Map.Entry<String, String> header :requestHeaders.entrySet()) {
                con.setRequestProperty(header.getKey(), header.getValue());
            }

            int responseCode = con.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) { // 정상 호출
                return readBody(con.getInputStream());
            } else { // 에러 발생
                return readBody(con.getErrorStream());
            }
        } catch (IOException e) {
            throw new RuntimeException("API 요청과 응답 실패", e);
        } finally {
            con.disconnect();
        }
    }
	
	 private HttpURLConnection connect(String apiUrl){ // HTTP 연결
	        try {
	            URL url = new URL(apiUrl);
	            return (HttpURLConnection)url.openConnection();
	        } catch (MalformedURLException e) {
	            throw new RuntimeException("API URL이 잘못되었습니다. : " + apiUrl, e);
	        } catch (IOException e) {
	            throw new RuntimeException("연결이 실패했습니다. : " + apiUrl, e);
	        }
    }
	 
	 private String readBody(InputStream body){ // 응답 결과 가공
	        InputStreamReader streamReader = new InputStreamReader(body);

	        try (BufferedReader lineReader = new BufferedReader(streamReader)) {
	            StringBuilder responseBody = new StringBuilder();
	            
	            String line;
	            while ((line = lineReader.readLine()) != null) {
	                responseBody.append(line);
	            }

	            return responseBody.toString();
	        } catch (IOException e) {
	            throw new RuntimeException("API 응답을 읽는데 실패했습니다.", e);
	        }
	    }
}

 

4. 컨트롤러 생성

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;


import com.dalc.one.openapi.NaverBlogSearchApi;
import com.dalc.one.service.LehgoFacade;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@RestController
@RequestMapping("/open")
public class OpenApiController{
	@Autowired
	NaverBlogSearchApi naver = new NaverBlogSearchApi();
	
	@ResponseBody
	@GetMapping("naver/blog")
	public ResponseEntity<JSONObject> getPlace(@RequestParam("query") String query) throws Exception {
		JSONParser parser = new JSONParser();
		Object obj = parser.parse( naver.search(query) );
		JSONObject jsonObj = (JSONObject) obj;
		return ResponseEntity.ok(jsonObj);
	}
}
  • String으로 전달받는 Naver Search API 결과를 다시 JSON 객체로 바꾼다.
  • 127.0.0.1:8080/open/naver/blog?query='만두'를 입력하면.
  • 만두와 관련된 블로그 포스팅을 JSON 객체로 리턴해준다.

 

5. 정리

API TEST를 했을 때, 아래와 같이 올바르게 결과가 나왔다.

내가 만든 방식은 JSON타입을 String으로 바꾸고, 다시 JSON으로 재변환을 해서 전송하는 거라 효율성이 많이 떨어진다고 생각한다.

Naver Open API에 JSON을 요청해 NaverBlogResponseDTO(JSON)로 변환해서 한번에 전송할 수 있는 방법을 더 알아봐야 할 것 같다.

{
"total": 4677014,
"lastBuildDate": "Fri, 18 Feb 2022 02:52:40 +0900",
"display": 10,
"start": 1,
"items": [
  {
"link": "https://blog.naver.com/partyar?Redirect=Log&logNo=222649126865",
"postdate": "20220216",
"description": "깡통<b>만두</b> 테이블링이란 어플을 이용해 대기를 걸어둘 수 있다하여 시도해보고, 안되면 근처에서 간단히... 깡통<b>만두</b> 대기 예약을 버튼을 눌렀더랬다. 중요한 건 테이블링 어플로 미리 예약을 해도, 이렇게... ",
"title": "[깡통<b>만두</b> / 티카페 델픽] 테이블링 어플덕에 웨이팅 없이... ",
"bloggerlink": "https://blog.naver.com/partyar",
"bloggername": "옥수슈블로그 ღ’ᴗ’ღ"
},
  {
"link": "https://blog.naver.com/sniper98?Redirect=Log&logNo=222643339670",
"postdate": "20220214",
"description": "연말특집 SBS생활의달인 2021년 10대 맛의 달인에 소개된 영천 북경<b>만두</b>. 4년째 심사위원으로 참여한... 영천 맛집하면 육회로 유명한 편대장영화식당과 거지짬뽕이란 별칭을 가진 광명반점, 한때 <b>만두</b>맛집으로... ",
"title": "2021년 10대 맛의 달인에 소개된 생활의달인 영천 북경<b>만두</b>",
"bloggerlink": "https://blog.naver.com/sniper98",
"bloggername": "대구맛집블로거 맛소클짱 혁이의 맛여행"
},
  {
"link": "https://blog.naver.com/iam_chew?Redirect=Log&logNo=222647815383",
"postdate": "20220215",
"description": "배민으로 김볶밥을 찾아 개금시장에서 <b>만두</b>로 이름을 떨친 양가손<b>만두</b>를 발견하고 사먹게되었다. 아~~~주 옛날에 내 블로그에 양가손<b>만두</b>를 포스팅한 적이 있었는데(나만알던 맛집이던 시절) 그때랑은 어떻게... ",
"title": "개금시장 맛집 양가손<b>만두</b> 맛은 괜찮은데",
"bloggerlink": "https://blog.naver.com/iam_chew",
"bloggername": "감칠맛 나는 송아담 세상"
},

 

Comments