게임을 좋아하신다면 닌텐도 스위치를 한번 쯤은 들어보셨을 겁니다.
한때 구글에서 만든 카드보드 VR 이란 제품도 들어보셨을 거구요.
카드보드 VR은 발매 당시 스마트폰과 저렴한 VR 키트만 있으면 VR을 체험할 수 있었지만, 꾸준히 즐길만한 컨텐츠는 턱없이 부족했습니다.
PC와 연결해서 사용할 수 있는 VR 기기도 출시되었지만 비싼 가격과 복잡한 설치 방법, 걸리적 거리는 유선 연결, 설치하려면 넓은 공간이 필요하다는 이유 등으로 선호되지는 않았죠.
페이스북 산하에 있는 Oculus에서 2019년에 새로운 모바일 VR을 내놓았습니다. 오큘러스 퀘스트라는 제품입니다.
스마트폰에 들어가는 모바일 칩셋이 탑재되어 있어, 별도로 PC와 연결을 하지 않고도 VR 앱과 게임을 실행할 수 있습니다. 닌텐도 스위치처럼 기기와 컨트롤러만 있으면 독립적으로 동작하는 제품인 것이죠.
영상을 보는 것 외에도 게임을 플레이 하거나, 그림을 그리고 음악을 연주할 수 있는 등 다양한 VR 활동들을 할 수 있습니다. 최근에는 모니터를 대신해 VR을 착용하고, VR 내부에 가상 모니터 화면들을 띄워 코딩을 한다고 하여 굉장히 화제가 된 적이 있었죠.
: Immersed 앱을 사용하여 VR로 코딩을 하는 모습. 원문이 궁금하신 분은 이쪽으로
Working From Orbit - VR Productivity In (or Above) a WFA World
오큘러스 퀘스트는 현재 2 버전까지 나왔고, 국내에도 SKT, 11번가 등 판매처에서 판매를 시작하며 국내에서도 꽤나 많이 판매된 상태입니다.
유명한 게임들을 하려고 구매하기도 하고, 호기심에 구매하기도 하여 가장 먼저 찾아보는 곳이 바로 앱스토어 페이지 입니다.
다만, 오큘러스 퀘스트 앱스토어 페이지에 판매 중인 앱과 게임들은 카드형으로 작성되어 그 정보가 한눈에 들어오지 않아 굉장히 불편한 편입니다.
Oculus Quest 최다 판매 페이지 (2021년 12월 2일 기준)의 모습
오큘러스 퀘스트 앱스토어 페이지에 판매중인 앱들을, 위의 가격 정보 비교 사이트처럼 현재 판매되고 있는 제품들의 정보를 도표 형태로 한눈에 보고 싶었습니다.
현재 https://steamdb.info/sales/ 의 모습
레퍼런스로 위 사이트를 참고하였습니다.
서두가 많이 길었습니다. 이번에 3주간 진행한 웹개발 미니 프로젝트의 제목은 오큘러스 퀘스트 한국스토어 한눈에 보기 입니다.
현재 미니 프로젝트 구현 시점에서 구현을 시도한 것은 아래와 같습니다.
다만 한 번에 구현 가능한 부분은 제한적이기 때문에, 아래의 범위로 많이 좁혔습니다.
앱 목록 전체를 볼 수 있는 페이지가 있긴 하지만 다소 시간이 오래 소요될 것으로 보여 범위를 제한하였습니다.
주 언어는 Python으로 작성하고, 웹서버는 Flask에 외형은 Bootstrap 4.0을 사용하였으며, 데이터베이스는 MongoDB 입니다.
로직은 아래와 같이 아주 단순한 편입니다.
위와 같은 작업을 거친 후, Flask를 통해 사용자에게 웹페이지를 보여주게 됩니다.
하나씩 간단히 살펴보겠습니다.
최다 판매 페이지는 동적으로 앱 목록을 불러옵니다.
한번에 보여지는 앱 수는 24건이고, 스크롤 할 때마다 16개를 추가로 불러오며 가장 하단까지 스크롤 할 경우 최대 50건까지 보여집니다.
따라서 BeautifulSoup4 만으로 진행하려 했지만 Selenium 을 사용하여 페이지를 로딩한 후, 페이지를 하단으로 이동시켜 일정 시간 대기한 후 페이지 내용을 수집합니다.
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
chrome_service = Service('driver/chromedriver.exe')
driver = webdriver.Chrome(service=chrome_service)
driver.get(top_selling_url)
time.sleep(random.uniform(15, 20))
# 열려있는 웹페이지의 body 태그가 끝나는 부분까지 이동
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(random.uniform(10, 15))
약간의 시간을 대기한 후, BeautifulSoup4로 페이지 내 각 앱별 items 값을 담고있는 div를 선택한 후 a 태그로 묶여진 item들을 모두 raw_app_urls에 담아옵니다.
from bs4 import BeautifulSoup
app_html = driver.page_source
app_soup = BeautifulSoup(app_html, 'html.parser')
app_list = app_soup.select_one('#mount > div > div.section > div > div > div.section__items')
raw_app_urls = app_list.find_all('a')
div.section__items 값 내에 section__items-cell 들이 각 앱의 정보를 저장 중
raw_app_urls는 ResultSet 으로 저장되고, 각 item 내부에 href 값에 다행히 링크가 모두 저장되어 있습니다.
이 목록을 바탕으로 다시 각 앱 판매페이지를 순회하며 필요한 값들을 찾고, DB에 저장합니다.
앱의 이름, 별점, 가격, 언어 등 필요한 내용을 파싱한다.
raw_app_urls의 link들을 순회하며, 필요한 내용들을 파싱하여 저장하고 MongoDB에 Insert 또는 Update 합니다.
저장 시, Flask 에서 소개 페이지에 간단한 트레일러 동영상도 함께 보여주고 싶었습니다. YouTube Data API v3를 사용하여, DB 저장 시점에 "앱 제목 + vr trailer" 를 검색하여 가장 상단에 있는 동영상 id 값을 저장하도록 하였습니다.
# Youtube v3 API information
import googleapiclient.discovery
api_service_name = "youtube"
api_version = "v3"
DEVELOPER_KEY = YOUR_DEVELOPER_KEY
# Youtube API client
youtube = googleapiclient.discovery.build(
api_service_name, api_version, developerKey=DEVELOPER_KEY)
...
trailer_query = app_title.get_text() + ' vr trailer'
# "앱 이름 + ' vr trailer'" 로 검색한 최상단 Youtube 영상 id값 저장
request = youtube.search().list(
part="id,snippet",
type='video',
q=trailer_query,
maxResults=3,
fields="items(id(videoId))"
)
response = request.execute()
# trailer의 동영상 id 값 저장
trailer_url_id = response['items'][0]['id']['videoId']
대부분의 앱들의 트레일러는 잘 가져왔습니다. 다만, 이름이 흔하거나 공식 트레일러가 없는 경우 전혀 관련 없는 영상 id값이 들어가 있습니다. 주기적으로 확인하여 수동으로 해당 값을 바꿔주어 혼선이 없도록 해야겠습니다.
웹페이지는 아래와 같이 구성되어있습니다.
앱의 썸네일, 앱 이름, 평점, 가격과 장르, 용량, 그리고 한국인 사용자들에게 가장 중요한 한국어 지원 여부를 표기하였습니다. 기본 정렬은 화면에 보이지 않으나, 스토어 내 리뷰 수가 많은 순으로 정렬하였습니다.
앱을 선택하면 하단에 세부 페이지가 열리고, 좌측에 Youtube 관련 트레일러가 표시되며, 우측에는 앱 소개가 표시되어 있고 구매하러 가기 버튼을 누르면 실제 오큘러스 퀘스트 스토어 구매 페이지가 새 창에서 열립니다.
아마도 가장 많은 시행착오를 겪고 있지않나 싶습니다.
우선, 테스트 환경이 윈도우10 이었다가 Ubuntu 로 변경되므로 크게 두 가지 정도가 변경되었습니다.
MongoClient의 접속 주소를 EC2 내부 계정으로, Selenium driver를 Linux 버전으로 변경
AWS EC2의 Free tier Ubuntu 는 CLI 환경이므로, Selenium으로 페이지 스크롤 등의 동작을 하기 위해 표시되는 창이 없지만 실제로 존재하는 것처럼 가상 스크린을 그려주는 옵션 필요. chrome option으로 --headless 설정 필요함
# Linux 버전의 드라이버 경로로 설정
path = '/home/ubuntu/myoculusproject/driver/chromedriver'
# chrome 실행 옵션을 설정
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument("--single-process")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36")
driver = webdriver.Chrome(path, chrome_options=chrome_options)
위와 같은 작업을 마친 후 현재 가비아에서 구매한 도메인과 연결하여 정상적으로 외부 접속이 가능한 것을 확인했습니다.
이 미니 프로젝트의 대부분은 스파르타코딩클럽에서 수강한 웹개발 종합반의 수업 내용을 기반으로 작성하였습니다. 수강 기간은 8주로 어떻게 보면 짧다고 할 수 있지만, 필요한 내용이 꽤나 알차게 구성되어있어 강의를 듣는데 매우 감탄했습니다.
밑바닥부터 구현하려면 굉장히 오랜 시간이 걸리는 내용들이 군데군데 많았는데, 강의 내 코드스니펫을 이용하여 샘플 코드를 제공하거나, 즉시 활용할 수 있는 라이브러리들이 잘 배치되어 혼자 하다보면 며칠이고 꽉 막힐 수 있는 부분들을 좀 쾌적하게 넘어갈 수 있게 한 점이 굉장히 마음에 들었습니다. 만들고 싶은 것에 좀 더 집중할 수 있게 구성된 강의였다고 생각이 듭니다. AWS EC2로 내 프로젝트를 직접 배포하는 파트가 특히 기억에 남습니다.
추후 이 미니 프로젝트를 확장해나간다면, 추가적으로 구현하고 싶은 것은 아래와 같습니다.
조금씩 살을 붙여나가다 보면 언젠가 이 미니 프로젝트도, 실제로 한국 오큘러스 퀘스트 VR 사용자들에게 유용한 사이트가 되어 있지 않을까 생각합니다.