TMDB API로 정보 불러오기 上

부추·2022년 4월 11일
3

디즈니 플러스에서 제공하는 컨텐츠 데이터를 불러오기 위해서 TMDB에서 제공하는 오픈 API를 사용했다. 로컬 DB에 데이터를 저장하지 않고 데이터를 불러와서 바로 출력하는 방식은 처음이라 조금 헤맸었다.

1. TMDB API 사용법

가입과 API KEY발급 설명은 이 글을 참조해주세요.
가입과 KEY발급까지 끝났다면 https://developers.themoviedb.org/3/ < 여기로 이동해줍니다.
TMDB API는 URL을 통해서 데이터를 얻는 방식으로 사용이 가능한데, 친절하게도 사용자가 얻고자 하는 데이터에 따라서 탭을 분할해서 자세히 설명해주고 있다.

내가 만약 특정 회사에서 제공하는 컨텐츠(우리 프로젝트에 있어서는 디즈니 플러스가 되겠다)의 목록을 알고 싶다면 DISCOVER탭을 선택해서 진행할 수 있다.

해당 페이지로 이동해서 하단을 보면 이런 화면이 보인다. 원하는 데이터를 불러올 때 필요하고, 사용할 수 있는 parameter들을 확인할 수 있다.

사용할 조건들의 value값을 오른편의 입력칸에 입력해주면 정말 친절히도 TMDB측에서 알아서 쿼리 스트링으로 엮어서 url을 생성해준다.

이 때 적절한 parameter의 value값을 모르겠다면 헤더의 OAS버튼을 눌러보자.

json 형식으로 API의 스펙이 명시되어 있다. Ctrl+F로 검색해서 필요한 정보를 찾아내면 된다. 내가 사용할 정보는 디즈니 플러스에 해당하는 provider_id의 value값! 337이라고 명시되어있는 것을 알 수 있다.

2. 자바로 json 타입 데이터 파싱하기

위와 같은 방법을 통해 url을 완성시켜서 아무 웹 브라우저에서 실행시켜보자.
(예를 들어 디즈니 플러스에서 제공하는 컨텐츠 중 한국에서 이용할 수 있는 영화 목록을 불러오기 위한 url은 다음과 같다 : https://api.themoviedb.org/3/discover/movie?api_key=본인API KEY값&with_watch_providers=337&watch_region=KR&language=ko&page=)

위의 url을 실행하면 위와 같은 보자마자 정신이 아득해지는 결과물을 얻을 수 있다.

맨 첫줄부터 해석해보자면 "page" : 1의 의미는 총 검색 결과 중 첫 페이지를 출력하고 있으며, "results" : 의 의미는 해당 페이지의 검색 결과는 다음과 같다라는 의미다.

또한 대괄호로 크게 묶고 그 안에 또 다시 중괄호와 쉼표로 나열돼있는데 { }로 묶여져있는 텍스트들이 하나의 컨텐츠 정보가 담긴 하나의 객체라고 생각한다면 쉽다.

이해를 돕기 위한 이미지.. 이걸 조원들한테 이해시키느라 정말 힘들었다.
이제 또 하나의 컨텐츠 객체 안에서 내가 필요한 정보들만 적절히 뽑아내서 사용하면 된다!

프로젝트 시작 당시에는 파이썬을 배우지 않았어서 자바를 이용한 데이터 파싱 방식을 사용했다.
이 글을 참조해서 코드를 작성했다. 너무너무 감사하고 적게 일하고 많이 버시길..

public List<ContentsVO> getInfoList(String type) {
		int pages = getPages(type);

		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		String date = "0001-01-01";

		List<ContentsVO> infoList = null;
		List<Integer> genreList = null;
        
		try {

			infoList = new ArrayList<ContentsVO>();

			// 페이지 마다 루프를 돌며 값 추출 및 저장
			for (int i = 1; i <= pages; i++) {
				String apiURL = "https://api.themoviedb.org/3/discover/" + type + "?api_key=" + KEY
						+ "&with_watch_providers=337&watch_region=KR&language=ko&page=" + i;
				URL url = new URL(apiURL);

				BufferedReader bf;

				bf = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));

				result = bf.readLine();

				JSONParser jsonParser = new JSONParser();
				JSONObject jsonObject = (JSONObject) jsonParser.parse(result);
				JSONArray list = (JSONArray) jsonObject.get("results");

				for (int j = 0; j < list.size(); j++) {
					ContentsVO vo = new ContentsVO();
					JSONObject contents = (JSONObject) list.get(j);

					vo.setContents_num(Integer.parseInt(String.valueOf(contents.get("id"))));
					vo.setContents_type(type);
					vo.setOverview(contents.get("overview").toString());
					vo.setVote_average(Float.parseFloat(String.valueOf(contents.get("vote_average"))));
					vo.setPopularity(Float.parseFloat(String.valueOf(contents.get("popularity"))));
                    
					// 컨텐츠 타입(영화/시리즈)에 따라서 파싱 방법 다르게 설정
					if (type.equals("movie")) {
                    
						// 시리즈일 경우 release_date를 key로 데이터 파싱
						if (contents.get("release_date") == null || contents.get("release_date").equals("")) {
							vo.setRelease_date(dateFormat.parse(date));
						} else {
							Date release_date = dateFormat.parse((String) contents.get("release_date"));
							vo.setRelease_date(release_date);
						}
						vo.setTitle(contents.get("title").toString());
					} else if (type.equals("tv")) {
                    
						// 시리즈일 경우 first_air_date를 key로 데이터 파싱
						if (contents.get("first_air_date") == null || contents.get("first_air_date").equals("")) {
							vo.setRelease_date(dateFormat.parse(date));
						} else {
							Date first_air_date = dateFormat.parse((String) contents.get("first_air_date"));
							vo.setRelease_date(first_air_date);
						}
                        
						// 시리즈일 경우 title이 아닌 name을 key로 데이터 파싱
						vo.setTitle(contents.get("name").toString());
					}
					if (contents.get("poster_path") == null || contents.get("poster_path").toString().equals("")) {
						vo.setPoster_path("");
					} else {
						vo.setPoster_path(contents.get("poster_path").toString());
					}

					// 장르 id를 List<integer> 형태로 저장 → 장르 비교를 위한 작업
					JSONArray genre_list = (JSONArray) contents.get("genre_ids");
                    genreList = new ArrayList<Integer>();
					for (int k = 0; k < genre_list.size(); k++) {
						genreList.add(Integer.parseInt(String.valueOf(genre_list.get(k))));
					}
					vo.setGenres(genreList);
					infoList.add(vo);
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return infoList;
	}

배열 형태로 저장돼있는 각각의 객체들에서 해당 key 값에 해당하는 value 값을 추출해서 VO에 저장한다고 생각하면 간단하다!

...이어서

profile
부추가 좋아요

1개의 댓글

comment-user-thumbnail
2022년 11월 10일

안녕하세요 저도 지금 tmdb를 이용해 영화추천 사이트를 만들고 있는데 영화제목,상세설명등은 한국어로 나오는데 출연진은 영어로밖에 안되는거같은데 혹시 어떻게 하셨나요?

답글 달기