웹개발 종합반 4주차 (study)

신예진·2022년 2월 8일
0

(4주차 목표)
서버를 만드는 것

API (application programming interface)
: which is a software intermediary that allows two applications to talk to each other. Each time you use an app like Facebook, send an instant message, or check the weather on your phone, you're using an API.

Flask is a micro web framework written in Python

서버를 구동시켜주는 편한 코드 모음.
서버를 구동하려면 필요한 복잡한 일들을 쉽게 가져다 쓸 수 있다!
3분 요리/소스 세트라고 생각하면 된다!

1) Flask 시작하기 - 서버 만들기

① 인터프리터 설치
flask, dnspython, pymongo, certifi
  * 크롤링이 필요할 때는 - requests, bs4 추가 설치

② projects > prac > app.py 라는 파이썬 파일에 아래와 같이 입력 후 실행
from flask import Flask
app = Flask(__name__)

@app.route('/') # 여기서 '/'이후 부분은 주소창의 '/'이후 부분과 같음.
def home():
   return 'This is Home!'

if __name__ == '__main__':  
   app.run('0.0.0.0',port=5000,debug=True)
   
③ 주소창에 localhost:5000/ 입력 후 엔터를 치면 서버가 만들어 진 것을 확인할 수 있다
  # localhost : 내 컴퓨터에서 내가 개발하고 있고, 내 컴퓨터에서 내가 접속하고 있어. 그러니까 이건 local 개발환경이야.

2) Flask 시작하기 - HTML 파일 주기

① 기본적으로 만들고 시작할 것
directory > templates
directory > templates > index.html # app.py 에서 함수 안에 return 값으로 입력해도 실행되긴 하지만 그걸 언제 다 쓰냐,, html 파일을 따로 만들어서 쓰는게 굿.
directory > static

② HTML 파일 주기
from flask import Flask, render_template
app = Flask(__name__)

@app.route('/')
def home():
   return render_template('index.html') # index.html 파일을 읽어와서 줌.

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

3) Flask 시작하기 - 본격 API 만들기

① GET/POST 리마인드
GET : 통상적으로, 데이터 조회(read)를 요청할 때
      예) 영화 목록 조회
      데이터 전달 방식 : URL 뒤에 물음표를 붙여 key=value로 전달
      예) google.com?q=북극곰

POST : 통상적으로, 데이터 생성/변경/삭제 요청할 때
       예) 회원가입, 회원탈퇴, 비밀번호 수정
       데이터 전달 방식 : 바로 보이지 않는 HTML body에 key:value 형태로 전달

② JQuery 임포트
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

③ GET 요청 확인 Ajax 코드 - index.html 의 <script>에다가
function hey(){      # 이왕이면 함수를 만들어서 버튼에 붙여주는 것도 좋은 예시
    $.ajax({
        type: "GET",
        url: "/test?title_give=봄날은간다",     # /test라는 창구에 가는데 title_give라는 이름으로 '봄날은간다'라는 데이터를 내가 갖고 갈게.
        data: {},
        success: function(response){      # 잘 된다면 내가 console에다가 찍어볼게
        console.log(response)
        }
    })
}    

④ GET 요청 API 코드 - app.py에다가 import에 request, jsonify 먼저 추가하고.
@app.route('/test', methods=['GET'])
def test_get():
title_receive = request.args.get('title_give')     # 요청한 것을 잘 가져왔고
print(title_receive)
return jsonify({'result':'success', 'msg': '이 요청은 GET!'})     # 받은 것을 다시 가져가서 콘솔에 찍게 된다

⑤ POST 요청 확인 Ajax 코드 - index.html에다가
    $.ajax({
        type: "POST",
        url: "/test",
        data: { title_give:'봄날은간다' },
        success: function(response){
        console.log(response)
        }
})

⑥ POST 요청 API 코드 - app.p에다가
@app.route('/test', methods=['POST'])       # /test 창구에서 POST로 받는 애들 모여라~
def test_post():
title_receive = request.form['title_give']
print(title_receive)
return jsonify({'result':'success', 'msg': '이 요청은 POST!'})

예제 1) 화성땅 공동구매

① app.py 기본 코드
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

@app.route('/')
def home():
	return render_template('index.html')

@app.route("/mars", methods=["POST"])
def web_mars_post():
	sample_receive = request.form['sample_give']
	print(sample_receive)
	return jsonify({'msg': 'POST 연결 완료!'})

@app.route("/mars", methods=["GET"])
def web_mars_get():
	return jsonify({'msg': 'GET 연결 완료!'})

if __name__ == '__main__':
	app.run('0.0.0.0', port=5000, debug=True)
    
② templates > index.html 기본 코드
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
            crossorigin="anonymous"></script>

    <link href="https://fonts.googleapis.com/css2?family=Gowun+Batang:wght@400;700&display=swap" rel="stylesheet">

    <title>선착순 공동구매</title>

    <style>
        * {
            font-family: 'Gowun Batang', serif;
            color: white;
        }

        body {
            background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://cdn.aitimes.com/news/photo/202010/132592_129694_3139.jpg');
            background-position: center;
            background-size: cover;
        }

        h1 {
            font-weight: bold;
        }

        .order {
            width: 500px;
            margin: 60px auto 0px auto;
            padding-bottom: 60px;
        }

        .mybtn {
            width: 100%;
        }

        .order > table {
            margin: 40px 0;
            font-size: 18px;
        }

        option {
            color: black;
        }
    </style>
    <script>
        $(document).ready(function () {
            show_order();
        });

        function show_order() {
            $.ajax({
                type: 'GET',
                url: '/mars',
                data: {},
                success: function (response) {
                    alert(response['msg'])
                }
            });
        }

        function save_order() {
            $.ajax({
                type: 'POST',
                url: '/mars',
                data: {sample_give: '데이터전송'},
                success: function (response) {
                    alert(response['msg'])
                }
            });
        }
    </script>
</head>
<body>
<div class="mask"></div>
<div class="order">
    <h1>화성에 땅 사놓기!</h1>
    <h3>가격: 평 당 500원</h3>
    <p>
        화성에 땅을 사둘 수 있다고?<br/>
        앞으로 백년 간 오지 않을 기회. 화성에서 즐기는 노후!
    </p>
    <div class="order-info">
        <div class="input-group mb-3">
            <span class="input-group-text">이름</span>
            <input id="name" type="text" class="form-control">
        </div>
        <div class="input-group mb-3">
            <span class="input-group-text">주소</span>
            <input id="address" type="text" class="form-control">
        </div>
        <div class="input-group mb-3">
            <label class="input-group-text" for="size">평수</label>
            <select class="form-select" id="size">
                <option selected>-- 주문 평수 --</option>
                <option value="10평">10평</option>
                <option value="20평">20평</option>
                <option value="30평">30평</option>
                <option value="40평">40평</option>
                <option value="50평">50평</option>
            </select>
        </div>
        <button onclick="save_order()" type="button" class="btn btn-warning mybtn">주문하기</button>
    </div>
    <table class="table">
        <thead>
        <tr>
            <th scope="col">이름</th>
            <th scope="col">주소</th>
            <th scope="col">평수</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td>홍길동</td>
            <td>서울시 용산구</td>
            <td>20평</td>
        </tr>
        <tr>
            <td>임꺽정</td>
            <td>부산시 동구</td>
            <td>10평</td>
        </tr>
        <tr>
            <td>세종대왕</td>
            <td>세종시 대왕구</td>
            <td>30평</td>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>

③ POST 연습 (주문 저장)
- 요청 정보 : URL = /mars, 요청 방식 = POST
- 클라이언트(ajax) → 서버(flask) : name, address, size
- 서버(flask) → 클라이언트(ajax) : 메시지를 보냄 (주문 완료!)

-1) 클라이언트와 서버 연결 확인하기
-2) 서버부터 만들기 - app.py에다가
@app.route("/mars", methods=["POST"])
def web_mars_post():
    name_receive = request.form['name_give']     # 데이터를 받아서
    address_receive = request.form['address_give']
    size_receive = request.form['size_give']

    doc = {
        'name': name_receive,
        'address': address_receive,
        'size': size_receive
    }
    db.mars.insert_one(doc)    # 서버에 넣어준다
    return jsonify({'msg': '주문 완료!'})
    
-3) 클라이언트 만들기
function save_order() {
        let name = $('#name').val()    # $('name') - id값
        let address = $('#address').val()
        let size = $('#size').val()

        $.ajax({
            type: 'POST',
            url: '/mars',
            data: { name_give : name, address_give : address, size_give : size },    # 위에서 서버가 name_give ... 이런 이름으로 가져오랬으니까
            success: function (response) {
                alert(response['msg'])    # 'msg' 내용만 alert로 보여줌
                window.location.reload()    # 다 되면 새로고침해주게
            }
        });
    }
-4) 완성 확인하기

④ GET 연습 (주문 보여주기)
- 요청 정보 : URL = /mars, 요청 방식 = GET
- 클라이언트(ajax) → 서버(flask) : (X)
- 서버(flask) → 클라이언트(ajax) : 전체 주문을 보내주기

-1) 클라이언트와 서버 확인하기
-2) 서버부터 만들기 - db에서 모든 주문을 가져와야함
@app.route("/mars", methods=["GET"])
def web_mars_get():
    order_list = list(db.mars.find({}, {'_id': False}))
    return jsonify({'orders': order_list})

-3) 클라이언트 만들기 - index.html에다가
 function show_order() {
        $.ajax({
            type: 'GET',
            url: '/mars',
            data: {},
            success: function (response) {
                let rows = response['orders']
                for (let i = 0; i < rows.length; i++){
                    let name = rows[i]['name']
                    let address = rows[i]['address']
                    let size = rows[i]['size']

                    let temp_html = `<tr>
                                        <td>${name}</td>
                                        <td>${address}</td>
                                        <td>${size}</td>
                                    </tr>`
                    $('#order-box').append(temp_html)    # 붙이고 싶은 곳에 id = "order-box"
                }

            }
        });
    }
-4) 완성 확인하기

예제 2) 스파르타피디아

① URL에서 페이지 정보 가져오기 (meta태그 스크래핑)
  : 메타 태그는, <head></head> 부분에 들어가는, 눈으로 보이는 것(body) 외에 사이트의 속성을 설명해주는 태그들이다.
    예) 구글 검색 시 표시 될 설명문, 사이트 제목, 카톡 공유 시 표시 될 이미지 등
    
import requests
from bs4 import BeautifulSoup

url = 'https://movie.naver.com/movie/bi/mi/basic.naver?code=191597'

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')

title = soup.select_one('meta[property="og:title"]')['content']
image = soup.select_one('meta[property="og:image"]')['content']
desc = soup.select_one('meta[property="og:description"]')['content']

print(title,image,desc)

② app.py 기본 코드
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

@app.route('/')
def home():
    return render_template('index.html')

@app.route("/movie", methods=["POST"])
def movie_post():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg':'POST 연결 완료!'})

@app.route("/movie", methods=["GET"])
def movie_get():
    return jsonify({'msg':'GET 연결 완료!'})

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)
    
③ index.html 기본 코드
<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
            crossorigin="anonymous"></script>

    <title>스파르타 피디아</title>

    <link href="https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap" rel="stylesheet">

    <style>
        * {
            font-family: 'Gowun Dodum', sans-serif;
        }

        .mytitle {
            width: 100%;
            height: 250px;

            background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://movie-phinf.pstatic.net/20210715_95/1626338192428gTnJl_JPEG/movie_image.jpg');
            background-position: center;
            background-size: cover;

            color: white;

            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        .mytitle > button {
            width: 200px;
            height: 50px;

            background-color: transparent;
            color: white;

            border-radius: 50px;
            border: 1px solid white;

            margin-top: 10px;
        }

        .mytitle > button:hover {
            border: 2px solid white;
        }

        .mycomment {
            color: gray;
        }

        .mycards {
            margin: 20px auto 0px auto;
            width: 95%;
            max-width: 1200px;
        }

        .mypost {
            width: 95%;
            max-width: 500px;
            margin: 20px auto 0px auto;
            padding: 20px;
            box-shadow: 0px 0px 3px 0px gray;

            display: none;
        }

        .mybtns {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: center;

            margin-top: 20px;
        }

        .mybtns > button {
            margin-right: 10px;
        }
    </style>
    <script>
        $(document).ready(function () {
            listing();
        });

        function listing() {
            $.ajax({
                type: 'GET',
                url: '/movie',
                data: {},
                success: function (response) {
                    alert(response['msg'])
                }
            })
        }

        function posting() {
            $.ajax({
                type: 'POST',
                url: '/movie',
                data: {sample_give: '데이터전송'},
                success: function (response) {
                    alert(response['msg'])
                }
            });
        }

        function open_box() {
            $('#post-box').show()
        }

        function close_box() {
            $('#post-box').hide()
        }
    </script>
</head>

<body>
<div class="mytitle">
    <h1>내 생애 최고의 영화들</h1>
    <button onclick="open_box()">영화 기록하기</button>
</div>
<div class="mypost" id="post-box">
    <div class="form-floating mb-3">
        <input id="url" type="email" class="form-control" placeholder="name@example.com">
        <label>영화URL</label>
    </div>
    <div class="input-group mb-3">
        <label class="input-group-text" for="inputGroupSelect01">별점</label>
        <select class="form-select" id="star">
            <option selected>-- 선택하기 --</option>
            <option value="1"></option>
            <option value="2">⭐⭐</option>
            <option value="3">⭐⭐⭐</option>
            <option value="4">⭐⭐⭐⭐</option>
            <option value="5">⭐⭐⭐⭐⭐</option>
        </select>
    </div>
    <div class="form-floating">
        <textarea id="comment" class="form-control" placeholder="Leave a comment here"></textarea>
        <label for="floatingTextarea2">코멘트</label>
    </div>
    <div class="mybtns">
        <button onclick="posting()" type="button" class="btn btn-dark">기록하기</button>
        <button onclick="close_box()" type="button" class="btn btn-outline-dark">닫기</button>
    </div>
</div>
<div class="mycards">
    <div class="row row-cols-1 row-cols-md-4 g-4" id="cards-box">
        <div class="col">
            <div class="card h-100">
                <img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
                     class="card-img-top">
                <div class="card-body">
                    <h5 class="card-title">영화 제목이 들어갑니다</h5>
                    <p class="card-text">여기에 영화에 대한 설명이 들어갑니다.</p>
                    <p>⭐⭐⭐</p>
                    <p class="mycomment">나의 한줄 평을 씁니다</p>
                </div>
            </div>
        </div>
        <div class="col">
            <div class="card h-100">
                <img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
                     class="card-img-top">
                <div class="card-body">
                    <h5 class="card-title">영화 제목이 들어갑니다</h5>
                    <p class="card-text">여기에 영화에 대한 설명이 들어갑니다.</p>
                    <p>⭐⭐⭐</p>
                    <p class="mycomment">나의 한줄 평을 씁니다</p>
                </div>
            </div>
        </div>
        <div class="col">
            <div class="card h-100">
                <img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
                     class="card-img-top">
                <div class="card-body">
                    <h5 class="card-title">영화 제목이 들어갑니다</h5>
                    <p class="card-text">여기에 영화에 대한 설명이 들어갑니다.</p>
                    <p>⭐⭐⭐</p>
                    <p class="mycomment">나의 한줄 평을 씁니다</p>
                </div>
            </div>
        </div>
        <div class="col">
            <div class="card h-100">
                <img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
                     class="card-img-top">
                <div class="card-body">
                    <h5 class="card-title">영화 제목이 들어갑니다</h5>
                    <p class="card-text">여기에 영화에 대한 설명이 들어갑니다.</p>
                    <p>⭐⭐⭐</p>
                    <p class="mycomment">나의 한줄 평을 씁니다</p>
                </div>
            </div>
        </div>
    </div>
</div>
</body>

</html>

④ POST 연습 (포스팅하기)
- 요청 정보 : URL = /movie, 요청 방식 : POST
- 클라이언트(ajax) → 서버(flask) : url, star, comment
- 서버(flask) → 클라이언트(ajax) : 메시지를 보냄 (포스팅 완료!)

-1) 클라이언트와 서버 연결 확인하기
-2) 서버부터 만들기
@app.route("/movie", methods=["POST"])
def movie_post():
    url_receive = request.form['url_give']
    star_receive = request.form['star_give']
    comment_receive = request.form['comment_give']

    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_receive, headers=headers)

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

    title = soup.select_one('meta[property="og:title"]')['content']
    image = soup.select_one('meta[property="og:image"]')['content']
    desc = soup.select_one('meta[property="og:description"]')['content']

    doc = {
        'title': title,
        'image': image,
        'desc': desc,
        'star': star_receive,
        'comment': comment_receive
    }
    db.movies.insert_one(doc)
    return jsonify({'msg': '저장 완료!'})
    
-3) 클라이언트 만들기
function posting() {
        let url = $('#url').val()
        let star = $('#star').val()
        let comment = $('#comment').val()

        $.ajax({
            type: 'POST',
            url: '/movie',
            data: {url_give : url, star_give : star, comment_give : comment},
            success: function (response) {
                alert(response['msg'])
                window.location.reload()
            }
        });
    }
-4) 완성 확인하기

⑤ GET 연습 (보여주기)
- 요청 정보 : URL = /movie, 요청 방식 = GET
- 클라이언트(ajax) → 서버(flask) : (X)
- 서버(flask) → 클라이언트(ajax) : 전체 영화를 보내주기

-1) 클라이언트와 서버 확인하기
-2) 서버부터 만들기
@app.route("/movie", methods=["GET"])
def movie_get():
    movie_list = list(db.movies.find({}, {'_id': False}))
    return jsonify({'movies': movie_list})
    
-3) 클라이언트 만들기
function listing() {
        $.ajax({
            type: 'GET',
            url: '/movie',
            data: {},
            success: function (response) {
                let rows = response['movies']
                for (i = 0; i < rows.length; i++){
                    let comment = rows[i]['comment']
                    let title = rows[i]['title']
                    let desc = rows[i]['desc']
                    let image = rows[i]['image']
                    let star = rows[i]['star']

                    let star_image = '⭐'.repeat(star)

                    let temp_html = `<div class="col">
                                        <div class="card h-100">
                                            <img src="${image}"
                                                 class="card-img-top">
                                            <div class="card-body">
                                                <h5 class="card-title">${title}</h5>
                                                <p class="card-text">${desc}</p>
                                                <p>${star_image}</p>
                                                <p class="mycomment">${comment}</p>
                                            </div>
                                        </div>
                                    </div>`

                    $('#cards-box').append(temp_html)
                }
            }
        })
    }
-4) 완성 확인하기

0개의 댓글