Nellie's Blog

[스파르타코딩클럽] 웹개발 종합반 4주차 정리 본문

회고록/항해99

[스파르타코딩클럽] 웹개발 종합반 4주차 정리

Nellie Kim 2022. 9. 22. 10:07
728x90

👉 4주차 수업목표  

1. Flask 프레임워크를 활용해서 API를 만들 수 있다.

2. '화성에 땅사기' API를 만들고 클라이언트에 연결한다.

3. '스파르타피디아' API를 만들고 클라이언트와 연결한다.

 

1,2주차에는 html,css,js를 배웠고, 3주차에는 서버를 다룰수있는 python과 저장소인 db를 배웠다.

4주차에는 드디어 서버를 배워본다!

▲ 현재 우리가 개발하고 있는 로컬환경(클라이언트 = 서버)

👉 Flask 시작하기 - 서버만들기

참고) 파이썬으로 웹개발을 할 때 가장 유명한 것은 Django(장고)인데, 장고는 무겁고 기능이 많아서 복잡하여 초보가 쓰기 쉬운 라이트한 flask프레임워크를 사용한다. (자바의 Spring)

- HTML과 mongoDB까지 연동해서 서버를 만들어보자!

1. 파이참에서 Flask 패키지 설치 (Flask 프레임워크: 서버를 구동시켜주는 편한 코드 모음)

2.  app.py파일만들고 flask시작코드 넣고 우클릭- run 해서 실행 (보통 flask 서버돌리는 파일은 app.py라고 짓는다)

 

- flask 시작 코드

from flask import Flask   #flask모듈 임포트
app = Flask(__name__)  #flask객체를 app이라는 변수에 할당. 현재 스크립트가 main스크립트임을 확인하는것.

@app.route('/')  #Flask에서는 URL을 방문할때 준비된 함수가 트리거되도록 바인딩하기위해 route()데코레이터를 사용한다. 이를 '웹을 라우팅한다'라고 한다.
def home():
    return 'hello world!'
    
if __name__ == '__main__': #현재 스크립트가 main스크립트이기 때문에 app.run()을 실행하게 해주는것!
    app.run('0.0.0.0', port=5000, debug=True) #서버 실행!!!
    
    #debug=True라고 명시하면 해당 파일의 코드를 수정할 때마다 Flask가 변경된 것을 인식하고 다시 시작한다. 코딩시 내용을 바로 반영해서 결과를 확인하기 편하다.

- 그럼 아래 창에 이렇게 뜰거고, 크롬에서 http://localhost:5000/ 으로 접속 후 Hello World! 보이면 성공!

▲ 생애 첫 서버를 만들기 성공!

터미널 창을 클릭하고, ctrl + c 을 누르면 서버를 종료할 수 있다.

 

3. URL 나눠보기

- @app.route('/) 부분을 수정해서 URL을 나눌 수 있다. (중복되면 안된다)

from flask import Flask
app = Flask(__name__)

@app.route('/')  #URL에서 첫 화면 주소 (localhost:5000)
def home():
    return 'hello world!'

@app.route('/mypage')  #URL 주소 추가 (localhost:5000/mypage)
def mypage():
    return 'This is mypage!' #⭐이쯤 의문이 드는것.. return뒤에 html구조가 들어가는거 같은데.. 
#⭐모든 html을 return뒤에 쭉쭉 다 써줘야하나?..놉 아래를 계속 보자!

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

▲ 웹페이지 2개를 만든것이다.

👉 Flask 시작하기 - HTML파일 주기

1.  Flask 기본 폴더구조

Flask 서버를 만들 때, 항상, 프로젝트 폴더 안에,

ㄴstatic 폴더 (이미지, css파일을 넣는곳)

ㄴtemplates 폴더 (html파일을 넣는곳)

ㄴapp.py 파일 이렇게 세 개를 만들어두고 시작하기! (env는 실제로는 보이지만, 안보인다고 생각! )

 

2.  HTML 파일 불러오기 (렌더링)

1)  templates 폴더에 index.html파일에 아래와 같은 간단한 코드를 넣는다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <title>Document</title>
    <script>
        function hey() {
            alert('안녕!')
        }
    </script>
</head>
<body>
<button onclick="hey()">나는 버튼!</button>
</body>
</html>

2)  app.py파일에서 flask내장함수인 render_template을 사용해서 html을 불러오기. (2줄 추가)

- 맨위에 ,render_template 넣기

- return뒤에 'hello world' 지우고 render_template('index.html') 써주면 된다.

from flask import Flask, render_template   #⭐ ,render_template 넣기
app = Flask(__name__)

@app.route('/')
def home():
    return render_template('index.html')   #⭐ render_template('index.html') 넣기. index.html파일을 렌더링해줘!

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

3) 그렇게 하고 app.py에서 실행하면 html이 그대로 따와져서 로컬호스트화면에 나타난다.

- 이런 과정을 렌더링이라고 한다. 렌더링이란 서버로부터 HTML 파일을 받아 브라우저에 뿌려주는 과정이다.

 

👉 GET / POST 방식 이해하기

* GET → 데이터 조회를 요청할 때 (서버에서 데이터를 가져와줘!)

예) 영화 목록 조회 → 데이터 전달 : URL 뒤에 물음표를 붙여 key=value로 전달

    → 예: google.com?q=북극곰

   요청형태 : google.com?q=북극곰

   요청데이터 : q=북극곰

 

* POST → 데이터 생성, 변경, 삭제를 요청 할 때 (데이터를 서버에 저장해줘!)

예) 회원가입, 회원탈퇴, 비밀번호 수정 → 데이터 전달 : 바로 보이지 않는 HTML body에 key:value 형태로 전달

   요청형태 : google.com

   요청데이터 : 노출되지 않는다.

👉  Flask시작하기 - 본격 API 만들기

1. (클라이언트) index.html파일에서 ajax로 요청하는 함수 만들기

1) JQuery 임포트하기. ajax를 사용하기위해 필요하다.

2) <script>에 ajax코드 작성하기. GET, POST요청코드를 작성할수 있다. (GET요청시 url : "/창구이름?key=value")

//⭐index.html 파일
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> //제이쿼리임포트. 그래야 ajax로 요청을 할수 있으니까!


    <script>     //여기에 ajax써줄거야.
        function hey() { //함수를 만들어서 버튼을 누르면 ajax가 실행되도록 만들자.
            $.ajax({
                type: "GET",
                url: "/test?title_give=봄날은간다", // /test라는 창구에 갔는데, title_give(주민번호)의 내용중에 봄날은간다(980101)라는 데이터를 내가 갖고갈게! 근데../test창구는 어떻게 만들지?
                data: {},
                success: function (response) {
                    console.log(response)
                }
            })
            
            $.ajax({
            type: "POST",
            url: "/test",
            data: {title_give: '봄날은간다'},  // /test창구에 이 data정보를 가져가서, 저장해줘!요청
            success: function (response) {
                console.log(response['msg'])
            	}
        	})
        }
    </script>
</head>
<body>
<button onclick="hey()">나는 버튼!</button>
</body>
</html>

2. (서버) app.py파일에서 정보를 반환하는 함수 만들기 - 내가 만든 창구(API)를 만들기

  1) request, jsonify  임포트 해주기. (jsonify : 사전or 배열을 던져서 쉽게 JSON 타입의 HTTP 응답 데이터를 생성해줌)

  2) @app.route('/창구이름', methods=['GET']) ~ 라고 시작한후 함수 만들기

#⭐app.py 파일
from flask import Flask, render_template, request, jsonify #여기서 request, jsonify 추가로 임포트 해주기

app = Flask(__name__)


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


@app.route('/test', methods=['GET']) #내가 만든 get요청 api코드 5줄!! 내가 /test창구를 만든거야 !!
def test_get():
    title_receive = request.args.get('title_give') #title_give라는애를 title_receive변수에 넣고 print로 찍어줄게!
    print(title_receive)
    return jsonify({'result': 'success', 'msg': '이 요청은 GET!'})
    
@app.route('/test', methods=['POST'])
def test_post():
    title_receive = request.form['title_give']  #너 'title_give'가져왔니? 응 가져왔어! -> 그럼 title_receive에 넣고 찍어줄게!
    print(title_receive)
    return jsonify({'result': 'success', 'msg': 'POST!'})    

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

👉   화성땅 공동구매 사이트 만들기 (+ DB사용)

- 웹페이지에서 이름, 주소, 평수를 선택하고 주문하기 버튼을 누르면, (POST)

- 자동으로 그 밑에 저장한 값들이 보여지게 해보자 (GET)

- 먼저, 패키지 설치 (4개) : flask, pymongo, dnspython, requests

1. POST 연습(주문 저장)

1. 요청 정보 : URL= /mars , 요청 방식 = POST
2. 클라(ajax) → 서버(flask) : name , address , size  (서버에 저장해 주세요!)  -> 서버는 데이터를 DB에 저장한다.
3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (주문 완료!)  

1) 클라이언트와 서버 연결 확인하기

- 같은창구(/mars)인지, 같은방식(POST)인지, 같은 데이터(sample_give)를 주고받는지 확인!

#⭐app.py 파일
@app.route("/mars", methods=["POST"])
def web_mars_post():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'POST 연결 완료!'})
// ⭐index.html 파일
function save_order() {
    $.ajax({
        type: 'POST',
        url: '/mars',
        data: {sample_give: '데이터전송'},
        success: function (response) {
            alert(response['msg'])
        }
    });
}

 

2) 서버부터 만들기

#⭐app.py 파일

from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

#⭐DB를사용하려면 항상 이 pymongo3줄이 필요하다고 했다. DB와 서버 연결을 위해 추가해주기!
from pymongo import MongoClient 
client = MongoClient('mongodb+srv://test:sparta@cluster0.ryuvr6l.mongodb.net/Cluster0?retryWrites=true&w=majority')
db = client.dbsparta

@app.route("/mars", methods=["POST"])
def web_mars_post():  #⭐기계적으로 쓰자!!
    name_receive = request.form['name_give']  #⭐'_give'가 중간다리 역할이라고 생각하자! 얘가 받아서 또 담아주니까!
    address_receive = request.form['address_give'] 
    size_receive = request.form['size_give']

#⭐doc변수에 데이터를 담고, mars데이터베이스에 저장해주기!
    doc = {  
        'name': name_receive,
        'address': address_receive,
        'size': size_receive
    }
    db.mars.insert_one(doc)

    return jsonify({'msg': '주문 완료!'}) #⭐화면에 알림창 띄우기. return문은 함수를 종료시키니 db저장코드 다음에 써줄것!!!

 

3) 클라이언트 만들기

// ⭐index.html 파일

<script>
function save_order() {
    let name = $('#name').val()   // ⭐아래<body>에서 내가 원하는 정보의 id값을 확인해서 .val()로 원하는값 추출하고 다시 변수에 넣기
    let address = $('#address').val()
    let size = $('#size').val()

    $.ajax({
        type: 'POST',
        url: '/mars',
        data: {name_give: name, address_give:address, size_give:size}, // ⭐드디어 데이터에 담아서 서버에 보낼 준비. 항상 '_give' 에 담아서 서버의 중간다리로 사용되게 하자.
        success: function (response) {
            alert(response['msg'])
            window.location.reload() // ⭐입력완료 후, 글씨가 남아있으면 지저분하니까 새로고침 해주기!
        }
    });
}
</script>
.....


<body>
<div class="order-info">
        <div class="input-group mb-3">
            <span class="input-group-text">이름</span>
            <input id="name" type="text" class="form-control">  // ⭐id="name" 찾고
        </div>
        <div class="input-group mb-3">
            <span class="input-group-text">주소</span>
            <input id="address" type="text" class="form-control">  // ⭐id="address" 찾고
        </div>
        <div class="input-group mb-3">
            <label class="input-group-text" for="size">평수</label>
            <select class="form-select" id="size">  // ⭐ id="size" 찾았으면 위로 올라가서 추출!
                <option selected>-- 주문 평수 --</option>
                <option value="10평">10평</option>
            </select>
        </div>
        <button onclick="save_order()" type="button" class="btn btn-warning mybtn">주문하기</button>
    </div>
</div>  
<body>

4) 웹사이트에서 이름,주소,평수 넣고 DB에 잘 저장 되있는것 확인!

 

2. GET 연습 (주문 한것 보여주기)

1. 요청 정보 : URL= /mars , 요청 방식 = GET
2. 클라(ajax) → 서버(flask) : (없음)
3. 서버(flask) → 클라(ajax) : 전체 주문을 보내주기

1) 클라이언트와 서버 연결 확인하기

- 같은창구(/mars)인지, 같은방식(GET)인지 확인!

 

2) 서버부터 만들기

@app.route("/mars", methods=["GET"])
def web_mars_get():
    orders_list = list(db.mars.find({}, {'_id': False})) #⭐mars데이터베이스에 있는 값을 모두 가져온다.
    return jsonify({'orders': orders_list}) #⭐항상 key : value 값으로 적어야해. 'orders'같은 중간다리변수를 key로 만들어줘야해.

3) 클라이언트 만들기

- 클라이언트에서는 항상 let변수가 여러개 들어간다!!

<script>
    $(document).ready(function () {   //⭐저장된데이터를 로딩되자마자 자동으로 보여줘야하니까.
        show_order();
    });

    function show_order() {
        $.ajax({
            type: 'GET',
            url: '/mars',
            data: {},
            success: function (response) {
                let rows = response['orders']   //⭐DB에서 받은 데이터를 한줄한줄 뽑아야 하니까 rows변수로 받아주기!
                for(let i = 0; i < rows.length; i++){    //⭐한줄씩 반복해야하니까 for문!
                    let name = rows[i]['name']   //⭐내가 원하는데이터를 받아올 변수 만들고 데이터담기! [i]빼먹지말자!!!
                    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)  //⭐넣은데이터를 이곳에 붙여줄게!
                }
            }//⭐헷갈리니까 중간중간 console.log()찍어서 확인하면서 코딩하자..!!!
        });
    }
  ......      
  }      
</script>

4) 웹사이트에서 내가 넣은 이름,주소,평수가 잘 나타나는지 확인!

3. POST / GET 비교

👉   스파르타피디아 사이트에 서버 추가하기 (+ 크롤링)

- 사이트에서 url,별점,코멘트(3가지정보)를 입력하면, url에서 자동으로 영화제목, 이미지, 영화설명까지 불러와서 화면에 표시되도록 해보자. (화면에 표시되는것 5가지 : 영화제목, 이미지, 영화설명, 별점, 코멘트)

- 패키지 설치하기 5개 : flask, pymongo, dnspython, bs4, requests

url,별점,코멘트만 입력했는데 , 자동으로 이미지,제목,설명까지 덧붙여서 화면에 나오게 만들어보자.

1. URL에서 페이지 정보 가져오기 (meta태그 스크래핑)

- meta태그란?

URL만 입력했는데, 자동으로 불러와지는 부분.  눈으로 보이는 것(body) 외에 사이트의 속성을 설명해주는 태그들.

예) 구글 검색 시 표시 될 설명문, 사이트 제목, 카톡 공유 시 표시 될 이미지 등

이런 데이터들은 'meta'태그를 크롤링으로 추출, 우리는 그 중 og:image / og:title / og:description을 크롤링 할 것이다.

메타태그를 붙여 공유시 이미지 등이 표시됨
개발자도구에서 메타태그를 찾아보자! og:image / og:title / og:description을 확인

#⭐meta_prac.py파일

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파일에 복붙해서 쓸거다.

2. POST 연습 (포스팅하기)

1) 서버 만들기

from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

import requests   #⭐meta_prac.py에서 두줄 복붙(크롤링시 필요)
from bs4 import BeautifulSoup

from pymongo import MongoClient  #⭐dbprac.py에서 3줄 복붙 (db저장시 필요)
client = MongoClient('mongodb+srv://test:sparta@cluster0.ryuvr6l.mongodb.net/Cluster0?retryWrites=true&w=majority')
db = client.dbsparta

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

@app.route("/movie", methods=["POST"])
def movie_post():
    url_receive = request.form['url_give'] #⭐여기서 받아온 url은 평소처럼 doc에 바로저장하는게 아니라 크롤링코드로 한번 돌린후 title,image,desc를 추출!
    star_receive = request.form['star_give'] #⭐doc에 바로 저장
    comment_receive = request.form['comment_give'] #⭐doc에 바로 저장

    #⭐mata_prac.py에서 만들어놓은 headers ~ desc 까지 6줄 복붙 (title,image,desc 정보가져온거 저장하려고)
    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)   #⭐url -> url_receive 수정. 위에서 받은 url을 data에 넣고 굴리는거다.

    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': '저장 완료!'})

2) 클라이언트 만들기

function posting() {
    let url = $('#url').val()  //⭐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() //⭐새로고침도 꼭 잊지말고 해줘!
        }
    });
}
.......
<div class="mypost" id="post-box">
    <div class="form-floating mb-3">
        <input id="url" type="email" class="form-control" placeholder="name@example.com"> //⭐id="url"확인
        <label>영화URL</label>
    </div>
    <div class="input-group mb-3">
        <label class="input-group-text" for="inputGroupSelect01">별점</label>
        <select class="form-select" id="star">  //⭐id="star"확인
            <option selected>-- 선택하기 --</option>
        </select>
    </div>
    <div class="form-floating">
        <textarea id="comment" class="form-control" placeholder="Leave a comment here"></textarea> //⭐id="comment"확인
        <label for="floatingTextarea2">코멘트</label>
    </div>
</div>

 

3. GET 연습 (보여주기)

1) 서버 만들기

@app.route("/movie", methods=["GET"])
def movie_get():
    movie_list = list(db.movies.find({}, {'_id': False}))
    return jsonify({'movies': movie_list}) #⭐중간다리 역할을 하는 movies변수..제발 까먹지말고 잘쓰자.

 

2) 클라이언트 만들기

<script>
$(document).ready(function () {
    listing();
});

function listing() {
    $('#cards-box').empty()
    $.ajax({
        type: 'GET',
        url: '/movie', //⭐3주차 초에 한 스파르타피디아에 openAPI붙인거와의 차이점은 이 url이랑, POST작업이 없다는것!!!
        data: {},
        success: function (response) {
            let rows = response['movies']
            for(let i =0; i<rows.length; i++){
                let title = rows[i]['title']
                let star = rows[i]['star']
                let image = rows[i]['image']
                let desc = rows[i]['desc']
                let comment = rows[i]['comment']

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

 

 

👉   GET, POST 에서 서버, 클라이언트 만들기 정리

POST (클라이언트 -> 서버)
<서버만들기>

#app.py 파일에 flask, pymongo임포트

@app.route("/mars", methods=["POST"])
   name_receive = request.form['name_give']

    doc = {  
        'name': name_receive,
    }
    db.mars.insert_one(doc)

    return jsonify({'msg': '주문 완료!'}) 


name_give는 중간다리 변수.
name_receive는 여기서만 두번 쓰이고 끝나는 변수.
<클라이언트만들기> 

function save_order() {
    let name = $('#name').val()   

    $.ajax({
        type: 'POST',
        url: '/mars',
        data: {name_give: name,}, 
        success: function (response) {
            alert(response['msg'])
            window.location.reload() 
        }
    });

⭐POST에서 클라이언트를 만들때는 함수명 밑에 바로 let 변수로 받아올 데이터를 담아줘야 하는구나.
GET (서버 -> 클라이언트)
<서버만들기>

@app.route("/mars", methods=["GET"])
def web_mars_get():
    orders_list = list(db.mars.find({}, {'_id': False})) 

    return jsonify({'orders': orders_list}) 











orders_list 는 여기서만 두번 쓰이고 끝나는 변수.
orders는 중간다리 변수.
<클라이언트만들기> 
<script>
$(
document).ready(function () {
     show_order();
});


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 temp_html = `<tr> 
                                                   <td>${name}</td>
                                                </tr>`
                    $('#order-box').append(temp_html)  
                 }
            }
        });

⭐GET에서 클라이언트를 만들때는 response 밑에 바로 
let rows 변수로 받아온 데이터를 한줄한줄 담아줘야 하는구나.

 

조금 정리가 되는 것 같지만 숙달이 필요할 것 같다!!

 

 

출처 : [스파르타코딩클럽] 웹개발 종합반 4주차

출처 : https://murphymoon.tistory.com/entry/HTTP%EC%9D%98-GET%EA%B3%BC-POST-%EB%A9%94%EC%84%9C%EB%93%9C-%EB%B9%84%EA%B5%90-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B81