Thumbnail image from DALL-E
저번 포스트에 이어서, 이번에는 웹페이지에 유튜브 채널 id를 넣으면 동영상 목록을 출력해보려 한다.
- INPUT = 브라우저는 유튜브 채널 ID 를 입력하면
- OUTPUT = 유튜브 채널에 있는 영상 ID, 링크 목록과 채널 ID 까지 출력, JSON 파일로 저장하기
우선, 플라스크가 무엇인지부터 알아보겠다. 🧪
플라스크(Flask)는 2004년 오스트리아의 오픈소스 개발자 아르민 로나허(Armin Ronacher)가 만든 웹 프레임워크이다. 플라스크는 아르민 로나허가 만우절에 장난삼아 던진 아이디어였는데 사람들의 관심이 높아져 서비스로 만들어졌다고 한다. 플라스크는 장고(Django)와 더불어 파이썬 웹 프레임워크의 양대 산맥으로 자리매김하고 있다.
Flask 란 간단히 말해서 웹서비스를 만들어주는 mini 파이썬 웹서버이다. 즉, 웹 애플리케이션 개발을 위한 파이썬 프레임워크이다. Django 대신 라이트한 개발을 할 때 유용하다.
플라스크(Flask) 에는 폼(form), 데이터베이스(database)를 처리하는 기능이 없다. 예를 들어 장고(Django)라는 웹 프레임워크는 프레임워크 자체에 폼과 데이터베이스를 처리하는 기능이 포함되어 있다. 장고는 쉽게 말해 덩치가 큰 프레임워크다. 그러면 플라스크는 이런 기능을 어떻게 보완할까? 플라스크는 확장 모듈을 사용하여 이를 보완한다. 이 말은 플라스크로 만든 프로젝트의 무게가 가볍다는 것을 의미한다. 왜냐하면 플라스크는 처음부터 모든 기능을 포함하고 있지 않기 때문이다. 그때그때 개발자가 필요한 확장 모듈을 포함해 가며 개발하면 된다.
가상환경(나는 파이참 프로젝트를 사용하기도 해서 기본 내장 가상환경인 venv를 사용하기로 했다) 과 관련된 건 아래의 간단한 설명을 참고하자!
# rendering 하지 않고 텍스트를 바로 입력해서 app.py를 통해서만 생성할 수도 있지만
# url_for, html 상속을 위해서 바로 render_template을 이용했습니다.
# route는 url 주소가 바뀔 때 routing되는 함수를 지정
# Flask에서 웹 페이지를 route()하게 되면 기본적으로 GET 요청만 지원한다
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def basic():
return render_template("basic.html")
@app.route('/info')
def info():
return render_template("info.html")
if __name__ == '__main__':
app.run(port=5001)
app.py
(Flask는 기본적으로 app.py
라는 이름의 파일로 시작하도록 설정되어있지만 원하는 이름으로 하셔도 상관 없다. 단 추후에 설정이 필요하다.) 라는 프로젝트를 시작할 파일을 하나 생성하고, 위와같이 작성하여 준다.
@app.route()
는 Flask에 기본적으로 존재하는 데코레이터로 URL과 Flask 코드를 매핑시켜줍니다.
파이썬에서 데코레이터(decorator)는 기본적으로 다른 함수를 수정하는 함수입니다. 데코레이터를 사용하면 기존 함수의 동작을 변경하거나 확장할 수 있으며, 이는 함수나 메서드의 정의를 변경하지 않고도 추가 기능을 주입할 수 있게 해줍니다.
그리고 앞선 포스팅에서 했던 기능을 합쳐보면 리스트를 출력할 수 있다!
그리고 조금만 더 수정해준다면... 아래 사진처럼, 처음의 요구사항을 만족한다!
json
파일을 설계할 때는 channel_id
가 중복되지 않고 한 번만 나오도록 했다.
그 외 정보는 각 영상마다 다르므로 videos
배열에 저장해줬다.
# app.py
# flask를 구동하고 웹페이지를 라우팅하고 렌더링하여 띄워 줄 python 파일이다.
from flask import Flask, render_template, request
import main
app = Flask(__name__)
app.config['SECRET_KEY'] = 'sdklgjifjlsfjidsg' # CSRF 보호를 위한 비밀 키 설정
@app.route('/', methods=['GET', 'POST'])
def index():
videos = []
channel_id = ' '
if request.method == 'POST':
channel_id = request.form['channel_id']
videos = main.get_channel_videos(channel_id)
return render_template('index.html', videos=videos, channel_id=channel_id)
if __name__ == '__main__':
app.run(debug=True)
# main.py
def get_channel_videos(channel_id):
video_links = []
next_page_token = None
while True:
# 특정 채널의 동영상 목록을 검색하고, 이 목록을 페이지별로 나누어 가져오는 요청
res = youtube.search().list(
part="id",
channelId=channel_id,
maxResults=50, # 한 페이지에 표시될 최대 결과 수
pageToken=next_page_token, # 페이지 네비게이션 토큰
type="video"
).execute()
video_ids = [item['id']['videoId'] for item in res['items']]
video_links.extend([f'https://www.youtube.com/watch?v={id}' for id in video_ids])
next_page_token = res.get('nextPageToken')
if not next_page_token:
break
get_info_JSON(api_key, channel_id)
return video_links
def get_info_JSON(api_key, channel_id):
youtube = build('youtube', 'v3', developerKey=api_key)
video_info = []
request = youtube.search().list(part='snippet', channelId=channel_id, maxResults=50, type='video')
response = request.execute()
for item in response['items']:
video_id = item['id']['videoId']
video_title = item['snippet']['title']
video_link = f'https://www.youtube.com/watch?v={video_id}'
video_info.append({
"video_id": video_id,
"title": video_title,
"link": video_link
})
# 결과를 JSON 파일로 저장
channel_info = {
"channel_id": channel_id,
"videos": video_info
}
with open(f'info_{channel_id}.json', 'w', encoding='utf-8') as f:
json.dump(channel_info, f, indent=4, ensure_ascii=False)
print(f"채널 ID와 각 동영상의 정보가 'info_{channel_id}.json' 파일로 저장되었습니다.")
# index.html
<!DOCTYPE html>
<html>
<head>
<title>YouTube Channel Video Links</title>
</head>
<body>
<h1>Enter YouTube Channel ID</h1>
<form method="POST" action="/">
<input type="text" name="channel_id" placeholder="Channel ID">
<input type="submit" value="Get Videos">
</form>
{% if videos and channel_id %}
<h2>Video Links:</h2>
<h5>채널 ID와 각 동영상의 정보가 'info_{{ channel_id }}.json' 파일로 저장되었습니다.</h5>
<ul>
{% for video in videos %}
<li><a href="{{ video }}">{{ video }}</a></li>
{% endfor %}
</ul>
{% endif %}
</body>
</html>