내일배움캠프_개발일지/웹개발 종합반

웹개발 종합반 4주차 일지

msdou45 2022. 10. 26. 08:41

——————————————————————————————————————————————————————————————————————

 

 

4주차 강의.

파이썬을 기반으로 한 마이크로 웹 프레임워크 “flask” 를 사용하여 파이썬 서버(백엔드) 구축해보기.

 

 

폴더 : sparta -> projects

=> 파이썬 로컬 개발 환경 연습. 내 컴퓨터에 서버를 설치하고 실행하여 나 혼자 접속해보는 환경.

물론 몽고DB는 아틀라스에서 빌려오는 거지만.

 

 

 

 

Projects - prac  새 프로젝트 생성.

 

파이참 실행 -> 상단 메뉴 ‘파일’ -> 새 프로젝트 ->  최상단 위치(L) 는 sparta - projects - prac

-> 두 번째 위치 경로 마지막에 ‘vena’ 설정되어 있는지 확인 -> 기본 인터프리터는 파이썬 버전 3.8

-> 웰컴 스크립트 생성 해제 -> 생성

 

 

 

 

 

prac 프로젝트에 라이브러리 설치. 

=> 서버를 만들 수 있는 프레임워크, ‘flask’ 설치하기.

 

상단 메뉴 pycharm -> preferences -> 좌측 카테고리 중 ‘프로젝트:prac’ 선택 -> python 인터프리터 선택 -> 좌측 상단 즈음에 + 클릭

-> flask 검색, 설치.

 

 

 

 

 

 

파일: sparta - projects - prac -> app.py    생성.

 

flask 시작 코드

——

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)

——

5000 포트로 실행해보기. 

 

 

 

****** 만약 이미 5000 포트가 다른 프로그램에서 사용중이라며 실행이 안될 경우,

시스템 환경설정 - 공유 - ‘Airplay 수신모드’ 를 해제해봐.

 

 

*********** 콘솔창에서 Ctrl + c / Command + C 로 서버 종료가 안될 경우,

——

sudo lsof -i :[포트번호] ex) sudo lsof -i :5000

——

으로 5000번 포트의 pid 숫자를 확인. 그 후 그 pid 숫자로 프로세스를 강제 종료.

——

sudo kill -9 [프로세스 PID] ex) sudo kill -9 2345

——

 

 

 

 

flask 프로젝트를 만들 때에는, 기본적으로 우리가 지향해야 하는 폴더 구조가 정형화 되어 있어.

——

프로젝트 폴더 안에, 

ㄴstatic 폴더 (이미지, css파일) 

ㄴtemplates 폴더 (html파일) 

ㄴapp.py 파일 (서버를 실행시키는 py파일)

——

프로젝트안에 새로운 파일들을 만들 듯, 새 경로를 만들어주자.

——

파이참 화면 왼쪽 프로젝트 ‘prac’ 우클릭 -> 새로 만들기 -> 경로(디렉토리) -> ‘templates’, ‘static’ 폴더 만들어주기. 

——

 

 

 

파일 prac -> templates -> index.html 작성.

이 html 파일이, flask 서버를 통해서 클라이언트로 리퀘스트를 보내줄 때 함께 보내는 페이지 구성 html.

——

from flask import Flask, render_template

app = Flask(__name__)

 

@app.route('/')

def home():

   return render_template('index.html’)

——

app.py에는 이렇게 작성.

이렇게 ‘index.html’ 을 return에 담아서 리스폰스 시 html 태그를 함께 보내서 클라이언트에게 index.html을 보여주는거야.

 

 

 

 

 

———————————————————————————————————————

기본적인 준비가 되었으니, 간단한 flask API 를 만들어보자. Get 방식과 post 방식을 사용하면서 프론트엔드, 백엔드가 데이터를 주고받는 구조를 공부.

 

우선 ajax 요청을 사용하기 위해 제이쿼리 import

——

파일 : prac - templates - index.html

——

 

 

Get 연습.

——

<index.html>

 

<script>

    function hey() {

        $.ajax({

            type: "GET",

            url: "/test?title_give=봄날은간다",

            date: {},

            success: function (response) {

                console.log(response);

            }

        })

    }

</script>

——

 

——

<app.py>

 

@app.route('/test', methods=['GET'])          # request, jsonify 를 import 해야 함.

def test_get():

   title_receive = request.args.get('title_give')

   print(title_receive)

   return jsonify({'result':'success', 'msg': '이 요청은 GET!'})

——

 

=> 클라이언트가 /test 라는 주소로 ‘title_give=봄날은간다’ 라는 값을 함께 보내면 request-get 요청.

서버는 app.route(‘/test, methods=[‘GET’)  이라는, /test 주소로 get 요청을 받아.

그리고 title_receive 라는 변수에 리퀘스트-get 요청과 함께 넘어온 ‘title_give’ 라는 키에 담긴 데이터를 저장. 잘 넘어왔는지 print.

그리고 request 에 대한 대답으로서 jsonify({}) 를 리턴해.

클라이언트 (index.html) 에서는 서버에서 return 한 값을 ‘response’ 로 받아서 이를 콘솔로 띄워.

 

 

 

 

 

Post 연습.

——

<index.html>

 

<script>

    function hey() {

        $.ajax({

            type: "POST",

            url: "/test",

            data: {title_give: '봄날은간다'},

            success: function (response) {

                console.log(response)

            }

        })

 

    }

</script>

——

 

——

<app.py>

 

@app.route('/test', methods=['POST'])

def test_post():

   title_receive = request.form['title_give']

  print(title_receive)

  return jsonify({'result':'success', 'msg': '이 요청은 POST!'})

——

 

=> post 요청의 경우, ajax에서는 data:{} 에 데이터를 담아서 서버에 requeest 할거야. get은 해당 주소 뒤애 ? 로 보내는 것에 비해.

 

 

 

 

 

 

————————————————————————————————————————————————————————————

파이썬 flask 로 서버를 둔 로컬 개발 환경 연습하기. 계속해서.

 

 

<화성땅 공동구매> 프로젝트 만들어보기.

 

폴더 : sparta -> projects -> mars

 

 

파이참 -> 상단 ‘파일’ 새 프로젝트 -> 위치는 ‘mars’ -> 두 번째 위치칸에 vens 명시되어 있는지 확인 -> 파이썬 버전 3.8 확인 -> 웰컴 스크립트 생성 체크 해제

 

프로젝트 생성 후,

mars 안에 ‘static’, ‘templates’ 파일 경로 만들어주고 mars 바로 아래에 app.py 만들어주기.

 

패키지 설치.

flask, pymongo, dnspython, certifi

* flask 는 백엔드 서버 구축을 위해.

* pymongo 는 몽고DB 랑 커넥트하기 위해.

* dnspython 은 도메인 네임 시스템.  이 패키지는 사람이 읽을 수 있는 도메인 이름(www.naver.com)을

  머신이 읽을 수 있는 IP주소로 바꿔주는 기능을 함.

* certifi는 몽고DB 주소를 가져오는 과정에서 보안 상 필요한 패키지.

 

화성땅 공동구매 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)

——

=> import는

flask  (파이썬 백엔드 flask),

render_template  (template(index.html 을 가져와서 클라이언트에게 보여주기 위해),

request  (ajax 통신을 통해서 클라이언트로부터 request를 받고 이를 활용하기 위해),

jsonify  (response로서 데이터를 클라이언트에게 보내주고 싶은데, json 형식을 사용하여 데이터를 보내주기 위해)

 

 

 

예를 들어, index.html(클라이언트에게 보여주는 화면) 에서 input 태그를 저장하고 다음과 같이 값을 입력할 수 있다 하자

——

<input id="name" type="text" class="form-control">

 

<input id="address" type="text" class="form-control">

 

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

——

 

 

우리는 여기서 id 가 각각 #name , #address, #size 의 값들을 저장하여 ajax 통신으로 백엔드에 보낼 것. 즉 post 방식의 통신을 먼저 시도해 볼 것.

(방식은 ‘주문하기’ 라는 버튼을 누를 시 함수를 발동시키고, 그 함수 안에 ajax 코드가 들어가 있는 것)

——

let name = $('#name').val();

let address = $('#address').val();

let size = $('#size').val();

 

$.ajax({

    type: 'POST',

    url: '/mars',

    data: { name_give: name, address_give: address, size_give: size },

    success: function (response) {

        alert(response['msg'])

        window.location.reload()  // 새로 고침

    }

});

——

이렇게 말이다.

 

 

ajax 통신을 통해 클라이언트에게서 데이터를 받은 서버 측 post 통신은 다음과 같이 데이터를 가공하여 데이터베이스에 저장한다. (app.py)

——

@app.route("/mars", methods=["POST"])

def web_mars_post():

    name_give = request.form['name_give']

    address_give = request.form['address_give']

    size_give = request.form['size_give']

    print(name_give, address_give, size_give)

 

    doc = {

        'name': name_give,

        'adress': address_give,

        'size': size_give

    }

    db.mars.insert_one(doc)

 

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

——

 

 

 

다음은 get 방식을 연습해보자. 클라이언트의 document가 ready됨과 동시에, get 통신을 발동시켜서 데이터베이스에서 목록을 가져와

그대로 클라이언트의 화면에 띄울 것이야. 즉 서버에서 프론트로 데이터를 보내준다는 것.

——

@app.route("/mars", methods=["GET"])

def web_mars_get():

 

    all_order = list(db.mars.find({}, {'_id': False}))

    print(all_order)

 

    return jsonify({'result': all_order, 'msg': 'GET 연결 완료!'})

——

app.py 에서는 get 방식의 requests를 받을 경우 다음과 같이 실행한다.

DB에서 _id 를 제외한 모든 리스트 값들을 들고와서 클라이언트에게 return 해준다.

 

 

——

function show_order() {

    $.ajax({

        type: 'GET',

        url: '/mars',

        data: {},

        success: function (response) {

            console.log(response['msg']);

            console.log(response['result']);

 

 

            let result = response['result'];

 

            for (let i = 0; i<result.length; i++) {

                let name = result[i].name

                let address = result[i].address

                let size = result[i].size

 

                let temp_html = `<tr>

                                <td>${name}</td>

                                <td>${address}</td>

                                <td>${size}</td>

                            </tr>`;

                $('#order_list').append(temp_html);

            }

        }

    });

}

——

클라이언트에서는 위와 같이 response 를 받아서, 그 안에 담겨 있는 값(result) 를 이용하여 for 문을 돌려 order_list 를 작성한다.

 

 

 

 

 

 

 

 

 

 

————————————————————————————————————————————————————————————

 

다음은 sparta - projects - movie 폴더에서 처음부터 다시 연습해보자.

 

다음은 기본 셋팅. 우선 flask 쪽.

——

패키지 설치.

flask, pymongo, dnspython, certifi

* flask 는 백엔드 서버 구축을 위해.

* pymongo 는 몽고DB 랑 커넥트하기 위해.

* dnspython 은 도메인 네임 시스템.  이 패키지는 사람이 읽을 수 있는 도메인 이름(www.naver.com)을

  머신이 읽을 수 있는 IP주소로 바꿔주는 기능을 함.

* certifi는 몽고DB 주소를 가져오는 과정에서 보안 상 필요한 패키지.

 

스파르타피디아 movie 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 web_mars_post():

    sample_receive = request.form['sample_give']

    print(sample_receive)

    return jsonify({'msg': 'POST 연결 완료!'})

 

@app.route("/movie", methods=["GET"])

def web_mars_get():

    return jsonify({'msg': 'GET 연결 완료!'})

 

if __name__ == '__main__':

   app.run('0.0.0.0', port=5000, debug=True)

——

=> import는

flask  (파이썬 백엔드 flask),

render_template  (template(index.html 을 가져와서 클라이언트에게 보여주기 위해),

request  (ajax 통신을 통해서 클라이언트로부터 request를 받고 이를 활용하기 위해),

jsonify  (response로서 데이터를 클라이언트에게 보내주고 싶은데, json 형식을 사용하여 데이터를 보내주기 위해)

 

 

 

스파르타피디아 movie 에서는 크롤링도 할 것이기에, 패키지를 추가로 설치해줘야 해.

——

requests, bs4

——

이렇게 해서 총 6개의 패키지를 설치해주는 거지. 참고로 requests는 http 통신에 필요한 패키지.

 

 

templates - index.html  의 뼈대 코드는 코드스니펫에서 가져오기.

 

 

 

******* 어떠한 목적성을 가지고 프로젝트를 시작할 때, 프로젝트를 본격적으로 시작하기 전, 이 프로젝트에 필요한 기능들을 먼저 구현해보는 것이 좋아 *******

그래야지 이 프로젝트가 앞으로 잘 돌아갈지 안 돌아갈지 알 수 있으니까.

    이러한 작업을 ‘조각 기능’ 이라 부르고, 프로젝트를 시작할 때에는 우선 조각 기능을 먼저 개발해 보고 정상적으로 작동한다면 그 다음에 본격적으로 업무를 시작하는 것이 좋아.

 

 

스파르타피디아 movie 조각 기능 작업. 우선은 크롤링.

크롤링을 구현하기에 앞서, <meta 태그> 에 대해서 알아보자.

Meta 태그는 <head> 태그 안에 들어가는 태그로서, body 외에 사이트의 속성에 대해 명시해주는 태그. 

ex) 구글 검색 시 표시 될 설명문, 사이트 제목, 카톡 공유 시 표시 될 이미지 등.     => 이런 식으로 써먹을 수가 있어.

 

——

파일 : movie - 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')

 

 

# 여기에 코딩을 해서 meta tag를 먼저 가져와 보자.

 

title = soup.select_one('meta[property="og:title”]’)       # meta 태그의 property 가 “og:title” 인 meta 태그를 가져와라.

print(title)

print(title['content'])    # 해당 meta 태그의 content 값.

 

 

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

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

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

 

print(title_content, img_content, desc_content)

——

* url 은 우리가 meta태그를 스크래핑 해 올 네이버 영화 사이트.

 

 

 

이제는 movie - app.py 에 post 메소드와 이렇게 받아온 데이터를 크롤링 및 DB저장에 사용할 수 있도록 import 를 해주고 기능을 구현화.

——

** import 부분 **

from flask import Flask, render_template, request, jsonify    # flask import

app = Flask(__name__)

 

import requests                         # 크롤링 import

from bs4 import BeautifulSoup

 

from pymongo import MongoClient            # 몽고DB import

import certifi

ca = certifi.where()

client = MongoClient('mongodb+srv://msdou46:klh17dj5a8@cluster0.n5ofnw1.mongodb.net/Cluster0?retryWrites=true&w=majority', tlsCaFile=ca)

db = client.dbsparta

 

 

** post 부분 **

 

@app.route("/movie", methods=["POST"])

def web_mars_post():

        # 클라이언트가 request 할 때 같이 post로 받아온 값들을 변수에 저장.

    url_receive = request.form['url_give']

    star_receive = request.form['star_give']

    comment_receive = request.form['comment_give']

 

        # 크롤링 구현을 위한 코드. 그리고 크롤링해 온 html 코드들을 soup 에 저장, 여기서 필요한 부분들만 빼내서 content 변수로 저장.

    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_content = soup.select_one('meta[property="og:title"]')['content']

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

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

 

    print(title_content, img_content, desc_content)

 

        # post로 받아온 값들과, url 주소를 크롤링하여 뽑아온 값들을 DB에 저장.

    doc = {

        'title': title_content,

        'image': img_content,

        'desc': desc_content,

        'star': star_receive,

        'comment': comment_receive

    }

    db.movies.insert_one(doc)

 

    return jsonify({'msg': '저장 완료!'})

——

 

 

index.html은 mars 처럼.

——

  ** html **

<input id="url" type="email" class="form-control" placeholder="name@example.com">

<label>영화URL</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>

 

<textarea id="comment" class="form-control" placeholder="Leave a comment here"></textarea>

<label for="floatingTextarea2">코멘트</label>

 

<button onclick="posting()" type="button" class="btn btn-dark">기록하기</button>

 

 

** script **

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()  // 새로 고침

        }

    });

}

——

 

 

get 은 mars와 마찬가지로 클라이언트가 로드됨과 동시에 get 요청을 app.py, 즉 서버로 보내고,

서버에서는 moives2 DB에서 list를 받아와 클라이언트로 쏴 줘.

클라이언트에서는 response 에 담긴 데이터들 중 필요한 값을 뽑아 list 수 만큼 for문을 돌리며 html에 append 해준다.