• 유투브 알고리즘을 따라해보자! 유사 유투바 알고리즘 만들기

    2021. 3. 2. 20:39

    by. 위지원

    RESUT API를 제공하는 웹서비스를 Resutful API라고 함.

     

    - Rest :: Network상에서 Client와 Server 사이의 통신 방식 중 하나

    - URI는 자원을 표현하는 데에 집중하고 행위에 대한 정의는 HTTP Method를 통해 하는 것이 REST한(CRUD) API를 설계하는 중심 규칙을 가지고 있음

        - CRUD Operation

           1. Create 

           2. Read

           3. Update

           4. Delete

           5. HEAD: Header 정보 조회

     

    왜 REST가 필요한가?

        1. 다양한 클라이언트

        2. 애플리케이션 분리 및 통합

        3. 멀티 플랫폼 지원

     

    REST 구성 요소

        1. 자원: Url, 클라이언트는 Url을 통해 자원을 지정하고 조작을 서버에 요청

        2. 행위: HTTP Method

        3. 표현: XML, JSON, TEXT 등 (json, xml이 일반적)

     

    그냥 하나 만들어보자

    플라스크를 이용했다.  

     

    유투브 url을 넣어서 서버에 저장하는 코드를 작성했다.

    특정 카테고리를 입력하면 해당 url 중 랜덤으로 하날 추천했다.

     

    이름하야... 유사 유투바 알고리즘..

    from flask import Flask
    from flask_restx import reqparse, abort, Api, Resource
    from collections import defaultdict
    from pytube import YouTube
    import random
    import ssl
    ssl._create_default_https_context = ssl._create_unverified_context
    
    app = Flask(__name__)
    api = Api(
        app,
        version='0.1',
        title="유사 유투바 알고리즘",
        description="유투바의 알고리즘을 따라잡자!",
        terms_url="/youtube"
    )
    
    url_dic = defaultdict(dict)
    
    parser = reqparse.RequestParser()
    parser.add_argument('url')
    parser.add_argument('category')
    
    just_category_parser = reqparse.RequestParser()
    just_category_parser.add_argument('category')
    
    
    
    def abort_category(category):
        if category not in url_dic:
            abort(404, message="Category {} doesnt' exist".format(category))
    
    
    def abort_url(category, url):
        if url not in url_dic[category]:
            abort(404, message="url {} doesnt' exist in Category {}".format(url, category))
    
    
    @api.route('/youtube')
    class Url(Resource):
        @api.expect(just_category_parser)
        def get(self):
            """ 지정된 카테고리의 url을 무작위로 추출합니다. """
            global url_dic
            args = just_category_parser.parse_args()
            category = args['category']
            abort_category(category=category)
            return random.choice(list(url_dic[category].values()))
    
    
        @api.expect(parser)
        def delete(self):
            """ 유투브 url을 삭제합니다. """
            global url_dic
            args = parser.parse_args()
            category = args['category']
            url = args['url']
            abort_url(category=category, url=url)
            del url_dic[category][url]
            return '', 204
    
        @api.expect(parser)
        def put(self):
            """ 유투브 url을 삽입합니다. """
            args = parser.parse_args()
            global url_dic
            category = args['category']
            url = args['url']
            yt_name = str(YouTube(url).title)
    
            if url in url_dic[category]:
                return '이미 추가하신 곡입니다', 202
            else:
    
                url_dic[args['category']][url] = yt_name
                return_value = url_dic[category][url]
                return return_value, 201
    
    
    @api.route('/youtube/<string:category>')
    class Url_list(Resource):
        def get(self, category):
            """ 특정 카테고리의 url을 모두 보여줍니다."""
            global url_dic
            return url_dic
    
    @api.route('/yotube/all')
    class Url_list_all(Resource):
        def get(self):
            """ 전체 url 목록을 보여줍니다. """
            global url_dic
            return url_dic
    
        
    api.add_resource(Url, '/youtube')
    api.add_resource(Url_list, '/youtube/<string:category>')
    api.add_resource(Url_list, '/youtube/all')
    
    if __name__ == '__main__':
        app.run(debug=True, host='0.0.0.0', port=4444)
    

     

    하지만 서버가 reset 될때마다 내 소중한 노동요 리스트들이 사라졌다..

    db를 연결해주자.

     

    database.py

    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, String
    
    
    Base = declarative_base()
    
    
    class url_list(Base):
        __tablename__ = 'url_list'
        url = Column(String(1000), primary_key=True)
        category = Column(String(100))
        url_name = Column(String(100))
    
        def __init__(self, url, category, url_name):
            self.url = url
            self.category = category
            self.url_name = url_name
    
    def insert_url(session, url, url_name, category):
        try:
            new_info = url_list(url=url, category=category ,url_name=url_name)
            session.add(new_info)
            session.commit()
    
        except Exception as e:
            print("\nUnique value insert exception\n")
            session.rollback()
    
    
    def delete_url(session, url):
        deleted_objects = url_list.__table__.delete().where(url_list.url.is_(url))
        session.execute(deleted_objects)
        session.commit()
    
    
    def select_url(session, category=None):
        if category is not None: #전체 다 보여
            urls = session.query(url_list.url_name, url_list.url)\
            .filter(url_list.category == category).all()
    
        else:
            urls = session.query(url_list.category, url_list.url_name, url_list.url).all()
    
        return urls

    app.py

    import sqlalchemy
    from flask import Flask
    from flask_restx import reqparse, abort, Api, Resource
    from collections import defaultdict
    from pytube import YouTube
    from sqlalchemy.orm import sessionmaker
    
    import database as db
    import random
    import ssl
    
    ssl._create_default_https_context = ssl._create_unverified_context
    
    app = Flask(__name__)
    api = Api(
        app,
        version='0.1',
        title="유사 유투바 알고리즘",
        description="유투바의 알고리즘을 따라잡자!",
        terms_url="/youtube"
    )
    
    
    url_dic = defaultdict(dict)
    
    parser = reqparse.RequestParser()
    parser.add_argument('url')
    parser.add_argument('category')
    
    just_category_parser = reqparse.RequestParser()
    just_category_parser.add_argument('category')
    
    just_url_parser = reqparse.RequestParser()
    just_url_parser.add_argument('url')
    
    
    @api.route('/youtube')
    class Url(Resource):
        @api.expect(just_category_parser)
        def get(self):
            """ 지정된 카테고리의 url을 무작위로 추출합니다. """
            global url_dic
            args = just_category_parser.parse_args()
            category = args['category']
    
            category_url_list = db.select_url(session=dbconnect(), category=category)
            if category_url_list:
                return random.choice(list(category_url_list)),201
            else:
                return "해당 카테고리에 url이 존재하지 않습니다!"
    
    
        @api.expect(just_url_parser)
        def delete(self):
            """ 유투브 url을 삭제합니다. """
            global url_dic
            args = just_url_parser.parse_args()
            url = args['url']
            db.delete_url(session=dbconnect(),url=url)
            return f'{url} 삭제 완료!', 201
    
        @api.expect(parser)
        def put(self):
            """ 유투브 url을 삽입합니다. """
            args = parser.parse_args()
            global url_dic
            category = args['category']
            url = args['url']
            yt_name = str(YouTube(url).title)
    
            if url in url_dic[category]:
                return '이미 추가하신 곡입니다'
            else:
                db.insert_url(session=dbconnect(), url=url, category=category, url_name=yt_name)
    
                return_value = "{}:{}".format(yt_name, url)
                return return_value, 201
    
    
    @api.route('/youtube/<string:category>')
    class Url_list(Resource):
        def get(self, category):
            """ 특정 카테고리의 url을 모두 보여줍니다."""
            return db.select_url(session=dbconnect(), category=category), 201
    
    
    @api.route('/youtube/all')
    class Url_list_all(Resource):
        def get(self):
            """ 전체 url 목록을 보여줍니다. """
            return db.select_url(session=dbconnect()), 201
    
    
    api.add_resource(Url, '/youtube')
    api.add_resource(Url_list, '/youtube/<string:category>')
    api.add_resource(Url_list_all, '/youtube/all')
    
    
    def dbconnect():
        engine = sqlalchemy.create_engine('sqlite:///youtube.db')
        Session = sessionmaker(bind=engine)
        return Session()
    
    
    if __name__ == '__main__':
        engine = sqlalchemy.create_engine('sqlite:///youtube.db')
        db.Base.metadata.create_all(engine)
        app.run(debug=True, host='0.0.0.0', port=1919)
    

    완성본은 아래와 같음.

    내가 디비에 put한 데이터들 중에서 

    랜덤으로 음악 url을 추천해주도록 설계되어있음.

    아래처럼 간단하게 웹 붙여서 요즘 필요할 떄 듣는다.. ㅎㅎ

     

    Reference

    gmlwjd9405.github.io/2018/09/21/rest-and-restful.html

    niceman.tistory.com/101

     

    '2021년 > 개발공부' 카테고리의 다른 글

    맥에서 Go 설치하기  (0) 2021.03.18
    파이썬 유닛테스트  (0) 2021.03.18
    스프링 시작하기 #2  (0) 2021.03.09
    Intellij+git  (0) 2021.03.08
    스프링 시작하기 #1  (0) 2021.03.08