본문 바로가기
코딩/JAVA

YOUTUBE DATA API 사용법/키워드 검색/크롤링

by 할맹 2019. 10. 3.

1. API 시작

https://developers.google.com/youtube/v3/getting-started

 

시작하기  |  YouTube Data API  |  Google Developers

소개 이 문서는 YouTube와 상호작용할 수 있는 애플리케이션을 개발하려는 개발자를 위해 작성되었습니다. 여기에서는 YouTube 및 API의 기본 개념에 대해 설명합니다. 또한 API가 지원하는 다양한 기능에 대한 개요를 제공합니다. 시작하기 전에 Google API 콘솔에 액세스하고 API 키를 요청하며 애플리케이션을 등록하려면 Google 계정이 필요합니다. API 요청을 제출할 수 있도록 Google에 애플리케이션을 등록합니다. 애플리케이션을 등

developers.google.com

Key를 발급받아 API 등록하는 과정은 위 링크에서 "시작하기 전에" 파트를 따라하면 된다.

구글 API를 사용하는 데에 있어 키 발급은 피할 수가 없다.

 

 

2. dependency 추가

1
2
compile group: 'com.google.apis', name: 'google-api-services-youtube', version: 'v3-rev205-1.25.0'
compile group: 'com.google.api-client', name: 'google-api-client', version: '1.25.0'
cs

나의 경우 Spring 프레임워크로 프로젝트를 진행했는데,

java config (필요한 개발 설정들을 xml이 아닌 java로 셋팅하는 환경) 기반이어서 다음과 같이 추가했다.

https://mvnrepository.com/이 사이트에서 원하는 라이브러리 이름을 검색하여 컴파일에 필요한 기입 정보를 알 수 있다.

 

 

3-1. API 사용 코드 구현- 공식 문서에 나와있는 속성

나는 특정 키워드별 YOUTUBE 게시물을 크롤링해 데이터베이스에 저장하는 기능이 필요했는데

마침 공식 문서에 있는 기능별 샘플 코드에 있길래 가져왔다. ("키워드별 검색" 항목 코드를 참고)

다른 언어, 다른 기능도 해당되는 샘플 코드가 있으니 참조하면 좋겠다.

 

샘플 코드를 백퍼센트 이해한 것은 아니지만, 친절한 변수명 덕에 작동 방식에 대해서는 전반적으로 이해할 수 있었다.

1
2
3
4
5
private static String PROPERTIES_FILENAME = "youtube.properties";
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
private static final long NUMBER_OF_VIDEOS_RETURNED = 25;
private static YouTube youtube;
cs

API 사용자가 입맛에 맞게 사용하기 위해 파악해야 될 변수는 다음과 같다.

* PROPERTIES_FILENAME

     : ".properties" 속성자의 파일 명을 가리키는 변수 (default명: youtube)

*NUMBER_OF_VIDEOS_RETURNED

     : 키워드를 검색어로 썼을 때 나오는 게시물들 중 가져올 게시물 개수 (default: 25개)

1
2
3
4
5
private static String getInputQuery() {
    String inputQuery = "";
    ...
    return inputQuery;
}
cs

키워드를 입력받는 데에 사용되는 함수이다.

inputQuery가 키워드를 받는 변수이구요.

1
2
3
4
5
6
7
8
9
10
private static void prettyPrint(Iterator<SearchResult> iteratorSearchResults, String query) {
    while (iteratorSearchResults.hasNext()) {
        SearchResult singleVideo = iteratorSearchResults.next();
        ResourceId rId = singleVideo.getId();
        
        if (rId.getKind().equals("youtube#video")) {
            Thumbnail thumbnail = singleVideo.getSnippet().getThumbnails().get("default");
        }
    }
}
cs

iteratorSearchResults라는 변수로 API가 가져온 결과 데이터의 JSON List를 다루는 함수이다.

singleVideo 변수가 영상 데이터를 하나씩 받아서, 멤버 함수를 통해 속성을 분리시켜 가져올 수 있게 한다.

공식 문서에서는 가져온 결과를 화면에 찍어주는 용도의 함수지만, 입맛에 맞게 바꿔서 사용하면 된다.

나는 iteratorSearchResults 변수로부터 결과 데이터의 속성들을 하나씩 분리 → DB에 저장 하는 방식으로 사용했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
while (iteratorSearchResults.hasNext()) {
    SearchResult singleVideo = iteratorSearchResults.next();
    ResourceId rId = singleVideo.getId();
    
    long publishedDateTemp = singleVideo.getSnippet().getPublishedAt().getValue();
 
    if (rId.getKind().equals("youtube#video")) {
        String thumbnailURL = "http://img.youtube.com/vi/" + rId.getVideoId() + "/hqdefault.jpg";
        String videoLink = "https://www.youtube.com/watch?v=" + rId.getVideoId();
 
        if (isFoodVideo == 1) {
            food.setTitle(singleVideo.getSnippet().getTitle());
            food.setCreator(singleVideo.getSnippet().getChannelTitle());
            food.setThumbnailURL(thumbnailURL);
            food.setVideoLink(videoLink);
            ...
        }
    }
}
cs

"singleVideo.getSnippet().get~()" 로 적혀있는 부분들이 공식적으로 YOUTUBE API가 제공하는 메소드들이다.

어느 속성이 공식적인 get메소드를 갖는지는 공식문서 내에 이 페이지를 참고하면 된다.

이렇게 쓴 이유는 일부 속성은 지정된 get메소드가 없기 때문이다.

 

위 페이지에 들어가서 "리소스 표현" 항목을 보면 API가 반환하는 JSON의 형태를 볼 수 있는데, 예시로 내가 사용한 'snippet' 부분만 떼서 보면 다음과 같다.

{
     ...
     "snippet": {
          "publishedAt": datetime, (=영상 게시 날짜)
          "channelId": string,
          "title": string, (=영상 제목)
          "description": string, (=영상 설명란)
          "thumbnails": { (=영상 썸네일)
          ...
          },
          "channelTitle": string, (=크리에이터명)
          ...
     },
     ...
}

내가 얻고자 했던 정보는 빨간색으로 표기된 프로퍼티들이다.

위 JSON 형식을 참고하여 내가 얻고 싶은 속성이 어느 프로퍼티에 들어있는지를 파악한 뒤, API의 멤버 함수에 해당 프로퍼티와 관련된 함수가 있는지 찾아봤다. 직접 짠 것이 아니다보니 일일히 찾아보는 수 밖에 없다.

관련 함수가 없다면 직접 함수를 만들어서 사용해야 한다.

 

3-2. API 사용 코드 구현- 공식 문서에 나와있지 않은 속성

API 사용 과정 중에 2가지 문제가 있었다.

1.

위의 JSON 형태에서 'snippet' 프로퍼티 아래에

"statistics": {
"viewCount": unsigned long,
...
}

이런 속성이 있는데, 영상 조회수 데이터가 필요했기 때문에 위의 'viewcount'라는 속성을 가져와야 했다.

하지만 순조로웠던 'snippet'과 다르게 'statistics'는 멤버 함수로 가져올 수 없는 속성..

2.

위의 'snippet' 속성에서 'description' 속성 값을 가져오는 함수가 원하는 방식으로 작동하지 않았다.

영상설명란 내용을 모두 가져오길 바랐지만, 멤버 함수를 사용할 경우 100자의 제한된 길이로 가져오는 것이었다.

 

구글링을 통해 찾아본 결과,

직접 HTTP GET 요청을 날려 JSON 데이터를 받아온 뒤, 여기서 원하는 속성 값을 분리해야 함을 알게 됨

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private long getViewCountFromVideo(String apikey, String videoId) throws IOException, JSONException {
    long viewCount = 0;
 
    String url = "https://www.googleapis.com/youtube/v3/videos?part=statistics&id="+videoId+"&key="+apikey;
    JSONObject json = readJsonFromUrl(url);
    String parentKey = json.getString("items");
    parentKey = parentKey.substring(1, parentKey.length() - 1);
    
    JSONObject parentKeyJson = new JSONObject(parentKey);
    String statistics = parentKeyJson.getString("statistics");
    JSONObject statisticsJson = new JSONObject(statistics);
    Iterator iterator = statisticsJson.keys();
 
    while (iterator.hasNext()) {
        String key = iterator.next().toString();
        if (key.contains("viewCount")) {
            viewCount = statisticsJson.getLong(key);
            break;
        }
    }
    return viewCount;
}
cs
1
2
3
4
5
6
7
8
9
10
11
    private static JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
        InputStream inputStream = new URL(url).openStream();
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String jsonText = readAll(bufferedReader);
            JSONObject json = new JSONObject(jsonText);
            return json;
        } finally {
            inputStream.close();
        }
    }
cs

다음은 임의로 짠 영상 조회수를 받아오는 함수이다.

 

1) 매개변수인 videoid에 singleVideo.getId().getVideoId()의 값을 넘겨주고, (3-1단계의 샘플 코드 속 singleVideo 변수)

     apikey에는 처음에 발급받은 Key값을 넘겨준다. (→ videoid를 통해 원하는 영상 데이터로 접근한다.)

2) 'url' 변수에 저장된 URL값은 매개변수에 따라 해당하는 영상의 JSON 데이터를 받아 화면에 뿌리게 된다. 'json' 변수가 해당 URL에 뿌려져 있는 JSON 값을 가져온다. (readJsonFrimUrl 함수)

3) String 객체(parentKey)가 JSON 객체의 가장 상위 프로퍼티부터 가져오고,

4) JSONObject 객체가 String 객체가 가져온 프로퍼티를 parsing하여 내부에 있는 'statistics' 프로퍼티까지 접근한다.

5) while문에서 'statistics' 프로퍼티의 배열 원소들을 하나씩 확인하면서 'viewCount' 프로퍼티에 접근한다.

 

'코딩 > JAVA' 카테고리의 다른 글

토너먼트 방식으로 2번째로 작은 수 찾기  (0) 2020.01.08