11코딩완주챌린지 [5주차] 10,11일차

1. 학습내용


✔[무비스타] - 프로젝트 세팅
flask,pymongo,requests,bs4세팅
✔[무비스타] - DB 만들기(데이터 쌓기)
moviestar 폴더 안에 init_db.py 파일을 만들어 (시간있을 때 분석할 것!)

import requests
from bs4 import BeautifulSoup

from pymongo import MongoClient

client = MongoClient('localhost', 27017)
db = client.dbsparta


# DB에 저장할 영화인들의 출처 url을 가져옵니다.
def get_urls():
    headers = {
        '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'}
    data = requests.get('https://movie.naver.com/movie/sdb/rank/rpeople.nhn', headers=headers)

    soup = BeautifulSoup(data.text, 'html.parser')

    trs = soup.select('#old_content > table > tbody > tr')

    urls = []
    for tr in trs:
        a = tr.select_one('td.title > a')
        if a is not None:
            base_url = 'https://movie.naver.com/'
            url = base_url + a['href']
            urls.append(url)

    return urls


# 출처 url로부터 영화인들의 사진, 이름, 최근작 정보를 가져오고 mystar 콜렉션에 저장합니다.
def insert_star(url):
    headers = {
        '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'}
    data = requests.get(url, headers=headers)

    soup = BeautifulSoup(data.text, 'html.parser')

    name = soup.select_one('#content > div.article > div.mv_info_area > div.mv_info.character > h3 > a').text
    img_url = soup.select_one('#content > div.article > div.mv_info_area > div.poster > img')['src']
    recent_work = soup.select_one(
        '#content > div.article > div.mv_info_area > div.mv_info.character > dl > dd > a:nth-child(1)').text

    doc = {
        'name': name,
        'img_url': img_url,
        'recent': recent_work,
        'url': url,
        'like': 0
    }

    db.mystar.insert_one(doc)
    print('완료!', name)


# 기존 mystar 콜렉션을 삭제하고, 출처 url들을 가져온 후, 크롤링하여 DB에 저장합니다.
def insert_all():
    db.mystar.drop()  # mystar 콜렉션을 모두 지워줍니다.
    urls = get_urls()
    for url in urls:
        insert_star(url)


### 실행하기
insert_all()

Run 실행해주기 (리스트가 완료될 것!)

✔[무비스타] - 뼈대 준비하기
<서버코드>app.py

from pymongo import MongoClient

from flask import Flask, render_template, jsonify, request

app = Flask(__name__)

client = MongoClient('localhost', 27017)
db = client.dbsparta


# HTML 화면 보여주기
@app.route('/')
def home():
    return render_template('index.html')


# API 역할을 하는 부분
@app.route('/api/list', methods=['GET'])
def show_stars():
    sample_receive = request.args.get('sample_give')
    print(sample_receive)
    return jsonify({'msg': 'list 연결되었습니다!'})


@app.route('/api/like', methods=['POST'])
def like_star():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'like 연결되었습니다!'})


@app.route('/api/delete', methods=['POST'])
def delete_star():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'delete 연결되었습니다!'})


if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)

<클라이언트 코드>index.html

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <title>마이 페이보릿 무비스타 | 프론트-백엔드 연결 마지막 예제!</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css"/>
        <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
        <style>
            .center {
                text-align: center;
            }

            .star-list {
                width: 500px;
                margin: 20px auto 0 auto;
            }

            .star-name {
                display: inline-block;
            }

            .star-name:hover {
                text-decoration: underline;
            }

            .card {
                margin-bottom: 15px;
            }
        </style>
        <script>
            $(document).ready(function () {
                showStar();
            });

            function showStar() {
                $.ajax({
                    type: 'GET',
                    url: '/api/list?sample_give=샘플데이터',
                    data: {},
                    success: function (response) {
                        alert(response['msg']);
                    }
                });
            }

            function likeStar(name) {
                $.ajax({
                    type: 'POST',
                    url: '/api/like',
                    data: {sample_give:'샘플데이터'},
                    success: function (response) {
                        alert(response['msg']);
                    }
                });
            }

            function deleteStar(name) {
                $.ajax({
                    type: 'POST',
                    url: '/api/delete',
                    data: {sample_give:'샘플데이터'},
                    success: function (response) {
                        alert(response['msg']);
                    }
                });
            }

        </script>
    </head>
    <body>
        <section class="hero is-warning">
            <div class="hero-body">
                <div class="container center">
                    <h1 class="title">
                        마이 페이보릿 무비스타😆
                    </h1>
                    <h2 class="subtitle">
                        순위를 매겨봅시다
                    </h2>
                </div>
            </div>
        </section>
        <div class="star-list" id="star-box">
            <div class="card">
                <div class="card-content">
                    <div class="media">
                        <div class="media-left">
                            <figure class="image is-48x48">
                                <img
                                        src="https://search.pstatic.net/common/?src=https%3A%2F%2Fssl.pstatic.net%2Fsstatic%2Fpeople%2Fportrait%2F201807%2F20180731143610623-6213324.jpg&type=u120_150&quality=95"
                                        alt="Placeholder image"
                                />
                            </figure>
                        </div>
                        <div class="media-content">
                            <a href="#" target="_blank" class="star-name title is-4">김다미 (좋아요: 3)</a>
                            <p class="subtitle is-6">안녕, 나의 소울메이트(가제)</p>
                        </div>
                    </div>
                </div>
                <footer class="card-footer">
                    <a href="#" onclick="likeStar('김다미')" class="card-footer-item has-text-info">
                        위로!
                        <span class="icon">
              <i class="fas fa-thumbs-up"></i>
            </span>
                    </a>
                    <a href="#" onclick="deleteStar('김다미')" class="card-footer-item has-text-danger">
                        삭제
                        <span class="icon">
              <i class="fas fa-ban"></i>
            </span>
                    </a>
                </footer>
            </div>
        </div>
    </body>
</html>

✔[무비스타] - GET연습(보여주기) : 영화인 정보를 카드로 보여주기(Read)
API 만들고 사용하기 - 영화인 조회 API (Read → GET)
(1) 조회(Read) 기능: 영화인 정보 전체를 조회

1. 클라이언트와 서버 연결 확인하기
<서버 코드> app.py

@app.route('/api/list', methods=['GET'])
def show_stars():
    sample_receive = request.args.get('sample_give')
    print(sample_receive)
    return jsonify({'msg': 'list 연결되었습니다!'})

<클라이언트 코드> index.html

function showStar() {
      $.ajax({
          type: 'GET',
          url: '/api/list?sample_give=샘플데이터',
          data: {},
          success: function (response) {
              alert(response['msg']);
          }
      });
  }

app.py에서 Run 실행 후, localhost:5000Enter 후 새로고침했을 때, 'list 연결되었습니다.' 라는 메시지가 뜨면 동작하는 것입니다.

  1. 서버부터 만들기

    서버가 하는 일
    \1. mystar 목록 전체를 검색합니다. ID는 제외하고 like 가 많은 순으로 정렬
    \2. 성공하면 success 메시지와 함께 stars_list 목록을 클라이언트에 전달

@app.route('/api/list', methods=['GET'])
def show_stars():
    movie_star = list(db.mystar.find({}, {'_id': False}).sort('like', -1))    ---pymongo sort w3chool 구글링
    return jsonify({'movie_stars': movie_star})
  1. 클라이언트 만들기

    클라이언트가 하는 일
    \1. #star_box의 내부 html 태그를 모두 삭제
    \2. 서버에 1) GET 방식으로, 2) /api/list 라는 주소로 stars_list를 요청
    \3. 서버가 돌려준 stars_list를 stars라는 변수에 저장
    \4. for 문을 활용하여 stars 배열의 요소를 차례대로 조회
    \5. stars[i] 요소의 name, url, img_url, recent, like 키 값을 활용하여 값 조회
    \6. 영화인 카드 코드 만들어 #star-box에 붙이기

function showStar() {
            $.ajax({
                type: 'GET',
                url: '/api/list?sample_give=샘플데이터',
                data: {},
                success: function (response) {
                    let mystars = response['movie_stars']
                    console.log(mystars)
                    }
                });
            }                        

페이지에서 새로고침 후 검사 및 콘솔창에서 잘 돌아가는지 확인!
for 문 돌아야 한다.

function showStar() {
                $.ajax({
                    type: 'GET',
                    url: '/api/list?sample_give=샘플데이터',
                    data: {},
                    success: function (response) {
                        let mystars = response['movie_stars']
                        for (let i = 0, i < mystars.length; i++) {
                            let name = mystars[i]['name']
                            let img_url = mystars[i]['img_url']
                            let recent = mystars[i]['recent']
                            let url = mystars[i]['url']
                            let like = mystars[i]['like']
                            console.log(name, img_url, recent, url, like)

                        }
                    }
                });
            }

페이지에서 새로고침 후 검사 및 콘솔창에서 잘 돌아가는지 확인!

<div class="card">
                <div class="card-content">
                    <div class="media">
                        <div class="media-left">
                            <figure class="image is-48x48">
                                <img
                                        src="https://search.pstatic.net/common/?src=https%3A%2F%2Fssl.pstatic.net%2Fsstatic%2Fpeople%2Fportrait%2F201807%2F20180731143610623-6213324.jpg&type=u120_150&quality=95"
                                        alt="Placeholder image"
                                />
                            </figure>
                        </div>
                        <div class="media-content">
                            <a href="#" target="_blank" class="star-name title is-4">김다미 (좋아요: 3)</a>
                            <p class="subtitle is-6">안녕, 나의 소울메이트(가제)</p>
                        </div>
                    </div>
                </div>
                <footer class="card-footer">
                    <a href="#" onclick="likeStar('김다미')" class="card-footer-item has-text-info">
                        위로!
                        <span class="icon">
              <i class="fas fa-thumbs-up"></i>
            </span>
                    </a>
                    <a href="#" onclick="deleteStar('김다미')" class="card-footer-item has-text-danger">
                        삭제
                        <span class="icon">
              <i class="fas fa-ban"></i>
            </span>
                    </a>
                </footer>
            </div>

하단에서 cards안에 있는 것들 가져오기

function showStar() {
            $.ajax({
                type: 'GET',
                url: '/api/list?sample_give=샘플데이터',
                data: {},
                success: function (response) {
                    let mystars = response['movie_stars']
                    for (let i = 0; i < mystars.length; i++) {
                        let name = mystars[i]['name']
                        let img_url = mystars[i]['img_url']
                        let recent = mystars[i]['recent']
                        let url = mystars[i]['url']
                        let like = mystars[i]['like']

                        let temp_html = `<div class="card">
                <div class="card-content">
                    <div class="media">
                        <div class="media-left">
                            <figure class="image is-48x48">
                                <img
                                        src="${img_url}"
                                        alt="Placeholder image"
                                />
                            </figure>
                        </div>
                        <div class="media-content">
                            <a href="${url}" target="_blank" class="star-name title is-4">${name} (좋아요: ${like})</a>
                            <p class="subtitle is-6">${recent}</p>
                        </div>
                    </div>
                </div>
                <footer class="card-footer">
                    <a href="#" onclick="likeStar('${name}')" class="card-footer-item has-text-info">
                        위로!
                        <span class="icon">
              <i class="fas fa-thumbs-up"></i>
            </span>
                    </a>
                    <a href="#" onclick="deleteStar('${name}')" class="card-footer-item has-text-danger">
                        삭제
                        <span class="icon">
              <i class="fas fa-ban"></i>
            </span>
                    </a>
                </footer>
            </div>`
                        $('#star-box').append(temp_html)
                    }
                }
            });
        }

하단에서 가져온 id값인 star-box를 붙여주며, 그 하단에 있던 card...는 지워도 된다.

  1. 완성 확인하기
    화면을 새로고침 했을 때 영화인 정보가 조회되는지 확인합니다.
    Robot3T실행하여 mystar에서 한 사람의 like를 조정하여(Edit Document 클릭) 저장 후 페이지 새로고침 했을 때 한 사람이 첫번째 위로 가는지 확인!

✔[무비스타] - POST연습(좋아요+1)
API 만들고 사용하기 - 좋아요 API (Update → POST)
(2) 좋아요: 클라이언트에서 받은 이름(name_give)으로 찾아서 좋아요(like)를 증가

1. 클라이언트와 서버 연결 확인하기
<서버 코드>app.py

@app.route('/api/like', methods=['POST'])
def like_star():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'like 연결되었습니다!'})

<클라이언트 코드>index.html

function likeStar(name) {
    $.ajax({
        type: 'POST',
        url: '/api/like',
        data: {sample_give:'샘플데이터'},
        success: function (response) {
            alert(response['msg']);
        }
    });
}

'위로' 버튼을 눌렀을 때, 'like 연결되었습니다!' 내용의 alert창이 뜨면 제대로 동작하는 것입니다.

  1. 서버부터 만들기

    서버가 하는 일
    \1. 클라이언트가 전달한 name_give를 name_receive 변수에 넣습니다.
    \2. mystar 목록에서 find_one으로 name이 name_receive와 일치하는 star를 찾습니다.
    \3. star의 like 에 1을 더해준 new_like 변수를 만듭니다.
    \4. mystar 목록에서 name이 name_receive인 문서의 like 를 new_like로 변경합니다.

@app.route('/api/like', methods=['POST'])
def like_star():
    name_receive = request.form['name_give']           ---이름 받았어요!

    target_star = db.mystar.find_one({'name': name_receive})    ---이름하나 찾았어요!
    current_like = target_star['like']             ---찾은 것중에 like값을 찾아야 해요!

    new_like = current_like + 1                 ---like값에 1를 더한 것!

    db.mystar.update_one({'name': name_receive}, {'$set': {'like': new_like}})   ---/4

    return jsonify({'msg': '좋아요 완료!'})
  1. 클라이언트 만들기

    클라이언트가 하는 일
    \1. 서버에
    1) POST 방식으로,
    2) /api/like 라는 url에,
    3) name_give라는 이름으로 name을 전달합니다.
    (참고) POST 방식이므로 data: {'name_give': name} 사용
    \2. '좋아요 완료!' alert 창을 띄웁니다.
    \3. 변경된 정보를 반영하기 위해 새로고침합니다.

function likeStar(name) {
            $.ajax({
                type: 'POST',
                url: '/api/like',
                data: {name_give:name},
                success: function (response) {
                    alert(response['msg']);
                    window.location.reload()
                }
            });
        }
  1. 완성 확인하기
    '위로' 버튼을 눌렀을 때 좋아요 수가 증가하고 영화인 카드의 순위가 변경되는지 확인합니다.

✔[무비스타] - POST연습(삭제하기)
API 만들고 사용하기 - 카드 삭제 API (Delete → POST)
(3). 삭제(Delete) 기능: 클라이언트에서 받은 이름(name_give)으로 영화인을 찾고, 해당 영화인을 삭제

1. 클라이언트와 서버 연결 확인하기
<서버 코드>app.py

@app.route('/api/delete', methods=['POST'])
def delete_star():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'delete 연결되었습니다!'})

<클라이언트 코드>index.html

function deleteStar(name) {
    $.ajax({
        type: 'POST',
        url: '/api/delete',
        data: {sample_give:'샘플데이터'},
        success: function (response) {
            alert(response['msg']);
        }
    });
}

'삭제' 버튼을 눌렀을 때, 'delete 연결되었습니다!' alert창이 뜨면
클라이언트 코드와 서버 코드가 연결 되어있는 것입니다.

2.서버부터 만들기

서버가 하는 일
\1. 클라이언트가 전달한 name_give를 name_receive 변수에 넣기
\2. mystar 에서 delete_one으로 name이 name_receive와 일치하는 star를 제거
\3. 성공하면 success 메시지를 반환

@app.route('/api/delete', methods=['POST'])
def delete_star():
    name_receive = request.form['name_give']
    db.mystar.delete_one({'name': name_receive})
    return jsonify({'msg': '삭제 완료!'})
  1. 클라이언트 만들기

    클라이언트가 하는 일
    \1. 서버에
    1) POST 방식으로,
    2) /api/delete 라는 url에,
    3) name_give라는 이름으로 name을 전달
    (참고) POST 방식이므로 data: {'name_give': name}
    \2. '삭제 완료! 안녕!' alert창 띄우기
    \3. 변경된 정보를 반영하기 위해 새로고침

function deleteStar(name) {
            $.ajax({
                type: 'POST',
                url: '/api/delete',
                data: {name_give:name},
                success: function (response) {
                    alert(response['msg']);
                    window.location.reload()
                }
            });
        }
  1. 완성 확인하기
    삭제 버튼을 눌렀을 때 영화인 카드가 삭제되는지 확인합니다.

✔내 프로젝트를 서버에 올리기

  • 언제나 요청에 응답하려면,
    1) 컴퓨터가 항상 켜져있고 프로그램이 실행되어 있어야하고,
    2) 모두가 접근할 수 있는 공개 주소인 공개 IP 주소(Public IP Address)로 나의 웹 서비스에 접근할 수 있도록 해야해요.
  • 서버는 그냥 컴퓨터라는거 기억나시죠? 외부 접속이 가능하게 설정한 다음에 내 컴퓨터를 서버로 사용할 수도 있어요.
  • 우리는 AWS 라는 클라우드 서비스에서 편하게 서버를 관리하기 위해서 항상 켜 놓을 수 있는 컴퓨터인 EC2 사용권을 구입해 서버로 사용할 겁니다.

✔AWS 서버 구매하기

[가장 많이 쓰이는 리눅스 명령어]
ls: 내 위치의 모든 파일을 보여준다.
pwd: 내 위치(폴더의 경로)를 알려준다.
mkdir: 내 위치 아래에 폴더를 하나 만든다.
cd [갈 곳]: 나를 [갈 곳] 폴더로 이동시킨다.
cd .. : 나를 상위 폴더로 이동시킨다.
cp -r [복사할 것][붙여넣기 할 것]: 복사 붙여넣기
rm -rf [지울 것]: 지우기
sudo [실행 할 명령어]: 명령어를 관리자 권한으로 실행한다.
sudo su: 관리가 권한으로 들어간다. (나올때는 exit으로 나옴)

그 후 만들었던 페이지를 서버에 올리는 과정은 강의자료에 쏙쏙쏙!!!

2. 학습소감

이로써 커리큘럼이 마치는 순간, 들었던 건 웹페이지하나가 공개적으로 올리는 과정이 넘나 신기했고, 기본적인 HTML, CSS, Javascript를 기초적인 거 배우면서 코드를 짜고 디자인하고 크롤링하면서 DB에 저장 후 서버에 올리는 과정이 참 재미있었고 처음으로 나와 이 프로그래밍과의 합을 맞춘 토대가 되어준 이 강의가 도움이 많이 되었다. 에러가 날 때, 모르는 코드는 구글링하며, 참고가 되어주는 부트스트랩 같은 기능을 보면서 참 이 직업을 택하더라도 아이디어와 커뮤니케이션 스킬, 끈기 등등 충분하다면, 이 직업으로 취업도전할 마음이 생긴것같다.
일단은 한번 따라해봤으니, 강의 한번 더 복습하고, 다음 강의커리큘럼에 레벨업해야겠다!!!

-----------웹개발 종합반(왕초보 시작반) 끝-------------

좋은 웹페이지 즐겨찾기