내일배움캠프/내일배움단

내일배움단 -개발일지 3주차 (1)

sogummi 2023. 3. 8. 23:50

13일차

  • 공부계획 : 웹개발 4주차 완강

< 미니 프로젝트 - 화성땅 공동구매 사이트 >

1) flask 폴더 구조 만들기
2) 가상환경(venv), 패키지 설치(flask, pymongo, dnspython)
*개발환경 복구 - pip freeze 활용(현재 서버에 설치된 라이브러리 목록을 저장할 수 있고, 새로운 가상환경에서 패키지들을 한번에 설치할 수 있다!)
3) mongoDB 창 띄우기

( POST 연습 )

4) API 만들기 - 이름, 주소, 평수 저장 (Creat -> POST)
(1) URL = /mars, 요청방식 = POST
(2) 클라이언트(fetch) -> 서버(flask) : name, address, size
(3) 서버(flask) -> 클라이언트(fetch) : 메세지를 보냄 (주문 완료!)
5) 클라이언트와 서버 연결 확인하기
6) 서버 만들기:DB에 연결

 from pymongo import MongoClient
 import certifi
    
 ca = certifi.where()
 client = MongoClient('mongodb+srv://sparta:test@cluster0.fqfuc0t.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
   db = client.dbsparta

7) DB에 name, address, size 받아 저장할 코드 작성

@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': '주문완료!'})

8) 클라이언트 만들기 : name, address, size 정보 보내기

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


  let formData = new FormData();
  formData.append("name_give", name);
  formData.append("address_give", address);
  formData.append("size_give", size);

  fetch('/mars',{method: "POST", body: formData,
    }).then((res) => res.json()).then((data) => {
      alert(data["msg"]);
      window.location.reload();

    });
}
~~~

9) 완성, 데이터 입력 하고 DB에 잘 들어갔는지 확인

( GET 연습 )

4) 저장된 주문 화면에 보여주기 (Read -> GET)
(1) URL = /mars, 요청방식 = GET
(2) 클라이언트(fetch) -> 서버(flask) : 없음 XXX
(3) 서버(flask) -> 클라이언트(fetch) : 전체 주문을 보내주기

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

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

클라이언트
$(document).ready(function() {
show_order()
})
function show_order() {
fetch('/mars').then((res) => res.json()).then((data) => {
console.log(data);
alert(data["msg"]);
});
}

6) 서버 만들기

    @app.route("/mars", methods=["GET"])
    def mars_get():
        mars_data = list(db.mars.find({},{'_id':False}))
        return jsonify({'result':mars_data})
    //DB에서 모든 data를 갖고와서 mars_data에 넣고, result로 mars_data를 클라이언트에 내려줌

7) 클라이언트 만들기
(1)주문 정보 : List형식 => forEach문 반복으로 데이터 뽑기
(2) 뽑은 데이터를 temp_html에 담기
(3) temp_html를 넣을 자리 찾아서 jQuery로 append

function show_order() {
        $("#order-box").empty();
        fetch('/mars').then((res) => res.json()).then((data) => {
            let rows = data['result']
	            rows.forEach((a) => {
              let name = a["name"];
              let address = a["address"];
              let size = a["size"];

              let temp_html = `<tr>
                        <td>${name}</td>
                        <td>${address}</td>
                        <td>${size}</td>
                      </tr>`;
              $("#order-box").append(temp_html);
            });
          });
      }

< 미니프로젝트 - 스파르타피디아 >

1) 프로젝트 세팅 (폴더 구조 생성, 가상환경 및 패키지 설치)

2) 조각 기능 구현 : app.py 밖에서 조각으로 구현한 다음 붙이는 것
=> 테스트를 일일이 flask에서 브라우저를 열고 진행하지 않아 편하고 빠름
=> 새 파일을 만들어 코드를 작업하고 성공하면 복사 후 app.py에 붙이기

3) 웹 스크래핑 사용해서 URL에서 페이지 정보 크롤링
(1) meta 태그 활용
- meta 태그 : 눈에 보이는 것 이외의 '웹의 속성 '을 설명해주는 태그
- meta 태그 예시) 카카오톡에서 url을 보냈을 때 자동으로 딸려오는 썸네일 사진,제목,설명 등
- 썸네일 사진 = og:image, 썸네일 제목 = og:title, 썸네일 설명 = og:description

(2) meta 태그 정보를 가져오는 조각기능 만들기
- 새 파일(meta_prac.py) 생성
- 크롤링 기본 코드 넣기
- meta 태그 크롤링 (구글링 : meta 태그 크롤링)
- select_one을 이용해 meta태그 가져오기

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

  print(og_image,og_title,og_description)
  => 코드 조각 준비 완료

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

5) index.html 준비

6) mongoDB창 띄우기

( POST 연습 ) 포스팅 API

7) API 만들고 사용 - (Creat -> POST)
1) URL = /movie, 요청방식 = POST
(2) 클라이언트(fetch) -> 서버(flask) : url, comment
(3) 서버(flask) -> 클라이언트(fetch) : 메세지를 보냄 (포스팅 완료!)

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

9) 서버 만들기

  • DB에 연결
    from pymongo import MongoClient
    import certifi

   ca = certifi.where()
   client = MongoClient('mongodb+srv://sparta:test@cluster0.fqfuc0t.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
   db = client.dbsparta
  • url, comment 정보 받아서 저장 (만들어둔 코드 조각 붙이고, DB에 저장)
@app.route("/movie", methods=["POST"])
def movie_post():
    url_receive = request.form['url_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')

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


    doc = {
        'image':ogimage,
        'title':ogtitle,
        'desc':ogdesc,
        'comment':comment_receive
    }

    db.movies.insert_one(doc)

    return jsonify({'msg':'포스팅 완료!'})

10) 클라이언트 만들기
url, comment 정보 보내기 (formData에 데이터 넣고 보내기)

function posting() {
            let url = $('#url').val()
            let comment = $('#comment').val()

            let formData = new FormData()
            formData.append('url_give', url)
            formData.append('comment_give', comment)

            fetch('/movie', {method: "POST",body: formData}).then(res => res.json()).then(data => {
                    alert(data['msg'])
                    window.location.reload() // 새로고침 
                })
        }

( GET 연습 )

7) API 만들고 사용하기 - 포스트 보여주기 API (Read -> GET)
(1) URL = /movie, 요청방식 = GET
(2) 클라이언트(fetch) -> 서버(flask) : 없음
(3) 서버(flask) -> 클라이언트(fetch) : 전체 주문 보내주기

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

9) 서버 만들기
받을 것 없으니 orders에 주문 정보를 담아서 보내주기만 하면 끝

@app.route("/movie", methods=["GET"])
def movie_get():
    all_movies = list(db.movies.find({},{'_id':False}))
    return jsonify({'result':all_movies})

10)클라이언트 만들기
주문정보 : List 형식 -> forEach문으로 반복해서 데이터 뽑기
뽑은 데이터 temp_html에 담고 temp_html넣을 자리 찾아서 append로 붙이기

11) 전체 완성 코드!! (별점 기능 추가)
💻app.py 코드(백엔드 - 스파르타 피디아 서버)

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

from pymongo import MongoClient
import certifi

ca = certifi.where()
client = MongoClient('mongodb+srv://sparta:test@cluster0.fqfuc0t.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta

import requests
from bs4 import BeautifulSoup

@app.route('/')
def home():
    return render_template('index.html')   // app.py에서 html파일 불러오기

@app.route("/movie", methods=["POST"]) 
def movie_post():
    url_receive = request.form['url_give']
    comment_receive = request.form['comment_give']
    star_receive = request.form['star_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')

    ogimage = soup.select_one('meta[property="og:image"]')['content']
    ogtitle = soup.select_one('meta[property="og:title"]')['content']
    ogdesc = soup.select_one('meta[property="og:description"]')['content']
     // meta태그 정보를 select_one으로 웹에서 가져옴 

    doc = {
        'image':ogimage,
        'title':ogtitle,
        'desc':ogdesc,
        'comment':comment_receive
    }

    db.movies.insert_one(doc) // 데이터를 딕셔너리 형태로 DB에 저장 
 
    return jsonify({'msg':'저장완료!'}) // 마지막으로 html posting함수에 msg 리턴

@app.route("/movie", methods=["GET"]) // 백엔드에서 프론트로 데이터 내려주기
def movie_get():
    all_movies = list(db.movies.find({},{'_id':False})) // 모든데이터 뽑아오기
    return jsonify({'result':all_movies}) //msg대신에 result에 all_movie데이터 리턴

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함수 동작 
            listing();
        });

        function listing() {  // 모든 데이터 결과 보여주기 
            fetch('/movie').then((res) => res.json()).then((data) => {
                let rows = data['result'] //DB에 있던 데이터들을 리스트로 묶음
                $('#cards-box').empty() // 반복문 돌기 전 비우기 
                rows.forEach((a)=>{  
                    let comment = a['comment']
                    let title = a['title']
                    let desc = a['desc']
                    let image = a['image']
                   // rows에 담긴 result들을 a에 하나씩 담아서 돌림
                      a의 각 키값들을 let 변수에 담음 

                    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>⭐⭐⭐</p>
                                                <p class="mycomment">${comment}</p>
                                            </div>
                                        </div>
                                    </div>`
                  //웹에 붙여 줄 temp_html 만들고(어디에 들어갈지 html에서 확인)
                    $('#cards-box').append(temp_html)
                 //id값 지정 후 append로 temp_html을 웹에 붙여준다! 
                })
            })
        }

        function posting() {
            let url = $('#url').val() //변수 url에 id가 url인 요소의 vaule가져오기
            let comment = $('#comment').val()
            let star = $('#star').val()

            let formData = new FormData(); // 새로운 Form 객체 형성
            formData.append("url_give", url); //name과 value를 가진 Form 필드 추가
            formData.append("comment_give", comment);
			formData.append("star_give", star);
            
            // /movie로 formData 생성(url,comment,star)해서 보냄
            fetch('/movie', { method: "POST", body: formData }).then((res) => res.json()).then((data) => { 
                alert(data['msg']) // 백엔드에서 DB에 데이터 저장 후 msg alert 
                window.location.reload() 
            })
        }

        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="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>
  • val() = 값을 가져오거나 변경하는 메소드
  1. $('input').val(); //input의 value값을 가져온다.
  2. var fruit = $("#apple").val();
    // 변수 fruit에 id가 apple인 요소의 value를 가져온다