💡수업 목표💡
- Flask 프레임워크를 활용해서 API를 만들 수 있다.
- '화성에 땅사기' API를 만들고 클라이언트에 연결한다.
- '스파르타피디아' API를 만들고 클라이언트와 연결한다.
Flask란?
Flask는 파이썬 기반으로 작성된 마이크로 웹 프레임워크 중 하나이다.
프레임워크 Framework는 기능을 모아놓은 라이브러리 이상으로 소프트웨어를 개발하기 위해서 표준 구조를 구현하는 클래스와 인터페이스의 집합을 의미한다. 즉 설계의 기반, 뼈대라고 보면된다.
어플리케이션을 개발 시 반드시 필요한 서버 구동, 알고리즘, DB 연동같은 기능들을 위한 설계의 기반이 되는 틀(기반코드)을 제공하기 때문에 개발자는 프레임워크가 정해놓은 구조 안에서 자신이 원하는 기능들을 구현하면 된다. 단순 기능들을 뽑아쓰는 라이브러리 형식과는 약간 차이가 있다.
- Java 서버 개발에 사용되는 Spring
- Python 서버 개발에 사용되는 Django, Flask
- 안드로이드 앱 개발에 사용되는 Android
- 아이폰 앱 개발에 사용되는 Cocoa Touch
- 웹 개발에 사용되는 Angular, Vue.js 등
- 자바 기반의 JSP를 위한 프레임 워크 Struts
- 루비로 작성된 MVC패턴을 이용하는 Ruby on Rails
Flask는 Django와 함께 Python 개발에 사용되는 프레임워크이지만 웹 어플리케이션 개발에 필요한 기능을 꽉꽉 담은 Django와 다르다.
웹 어플리케이션 개발에 필요한 최소한의 가벼운 기능을만 넣은 마이크로 웹 프레임워크로 가볍게 배우고, 사용할수 있으며 구조가 최소한이기 때문에 확장성 또한 넓다게 Flask의 주요 특징이다.
Flask 시작하기
Flask를 사용할려면 우선 패키지를 설치해야한다.
Preferences > Project > Python Interpereter를 보면 해당 프로젝트에서 현재 사용중인 패키지 리스트들을 확인할수 있다.
Flask 실행하기
Flask 패키지를 설치했다면 별다른 설치 없이 간단한 소스로 로컬컴퓨터에서 웹서버를 바로 실행할 수 있다.
app.py 파일을 만들어 아래 코드를 붙여넣어 실행시켜보자!
👉 파일 이름은 아무렇게나 해도 상관없지만, 통상적으로 flask 서버를 돌리는 파일은 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) #각자의 개발환경에 따라 5000포트가 안될때도 있다. 당황하지말고 숫자를 바꿔주자.
'Run app'을 클릭해서 터미널에 Running이 뜨면 성공!
크롬에 http://localhost:5000/ 혹은 http://127.0.0.1:5500/ 으로 접속하면 로컬 웹서버로 접속이 가능하다.
Flask URL 추가하기
@app.route('/') 부분을 수정해서 URL을 나눌 수 있다.
@app.route('/') 아래 부분의 함수가 해당 URL일때 실행이 된다. 이때, url 별로 함수명이 같거나, route('/')내의 주소가 같으면 안된다.
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'This is Home!'
@app.route('/mypage')
def mypage():
return 'This is My Page!'
if __name__ == '__main__':
app.run('0.0.0.0',port=5000,debug=True)
Flask 기본 디렉토리 구조
Flask는 프레임워크이기때문에 Flask에서 정의되어 있는 디렉토리 구조를 따라야한다.
- venv : 가상환경 디렉토리.
- static : HTML 파일 안에 들어갈 리소스(CSS, JS, image 등)를 관리하는 디렉토리.
- templates : HTML 파일을 관리하는 디렉토리.
- app.py : Flask 메인 실행 파일.
Flask의 template을 활용해보기
Flask 기본 보드를 보면 @app.route('/') 아래 함수의 return 값이 해당 URL에 페이지 화면이 된다.
하지만 reuturn에 장문의 html을 작성하기에 적합하지 않으므로 별도의 html파일을 렌더링(화면에 출력되는 과정) 해준다.
from flask import Flask, render_template
app = Flask(__name__)
## URL 별로 함수명이 같거나,
## route('/') 등의 주소가 같으면 안됩니다.
@app.route('/')
def home():
## return 'This is My Page!' 여기 HTML을 모조리 쓰기엔 너무 불편하니 template으로 관리하자
return render_template('index.html')
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
<!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>
Flask로 API 만들기
🔥리마인드🔥 HTTP request mehtod (요청메소드)
- GET
→ 통상적으로! 데이터 조회(Read)를 요청할 때 예) 영화 목록 조회
→ 데이터 전달 : URL 뒤에 물음표를 붙여 key=value로 전달
→ 예: google.com?q=북극곰 - POST
→ 통상적으로! 데이터 생성(Create), 변경(Update), 삭제(Delete) 요청 할 때 예) 회원가입, 회원탈퇴, 비밀번호 수정
→ 데이터 전달 : 바로 보이지 않는 HTML body에 key:value 형태로 전달
Flask에서 GET, POST 방식으로 통신하기
Flask에서 GET, POST방식으로 통신하기 위해서는 HTTP 통신하는 request와 데이터를 json형식으로 주고받는 jsonify를 import 해주어야한다.
GET 방식
app.py
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return render_template("index.html")
@app.route('/test', methods=['GET'])
def test_get():
title_receive = request.args.get('title_give')
print(title_receive)
return jsonify({'result':'success', '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">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
function hey_get() {
$.ajax({
type: "GET",
url: "/test?title_give=봄날은간다",
data: {},
success: function (response) {
console.log(response)
}
})
}
</script>
</head>
<body>
<h1>나의 첫 웹페이지!</h1>
<button onclick="hey_get()">버튼을 만들자 GET</button>
</body>
</html>
POST방식
app.py
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return render_template("index.html")
@app.route('/test', methods=['GET'])
def test_get():
title_receive = request.args.get('title_give')
print(title_receive)
return jsonify({'result':'success', 'msg': '이 요청은 GET!'})
@app.route('/test', methods=['POST'])
def test_post():
title_receive = request.form['title_give']
print(title_receive)
return jsonify({'result':'success', 'msg': '이 요청은 POST!'})
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">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
// GET 방식 호출
function hey_get() {
$.ajax({
type: "GET",
url: "/test?title_give=봄날은간다",
data: {},
success: function (response) {
console.log(response)
}
})
}
// POST 방식 호출
function hey_post() {
$.ajax({
type: "POST",
url: "/test",
data: {title_give: '봄날은간다'},
success: function (response) {
console.log(response)
}
})
}
</script>
</head>
<body>
<h1>나의 첫 웹페이지!</h1>
<button onclick="hey_get()">버튼을 만들자 GET</button>
<button onclick="hey_post()">버튼을 만들자 POST</button>
</body>
</html>
Project01 - 화성땅 공동구매
http://spartacodingclub.shop/web/mars
프로젝트 준비 및 설정
Flask 폴더 구조 : static / templates / app.py
패키지 설치 : Flask, pymongo, dnspython
프로젝트 뼈대 구성
- 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)
- 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>
주문 저장 API 만들기 - POST 연습
화성땅 공동구매 사이트를 위해서 index.html에서 이름, 주소, 평수를 받아서 DB에 저장하기 (Create -> POST)
1. 요청 정보 : URL= /mars, 요청 방식 = POST
2. 클라(ajax) → 서버(flask) : name, address, size
3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (주문 완료!)
app.py - 서버 코드
from pymongo import MongoClient
client = MongoClient('----mongoDB URL-----')
db = client.dbsparta
@app.route("/mars", methods=["POST"])
def mars_post():
name_receive = request.form['name_give']
address_receive = request.form['address_give']
size_receive = request.form['size_give']
# mongoDB 저장
doc = {
'name': name_receive,
'address': address_receive,
'size': size_receive
}
db.orders.insert_one(doc)
return jsonify({'msg': '주문 완료!'})
index.html - 클라이언트 코드
function save_order() {
//input에 담긴 값 가져오기
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()
}
});
}
결과 확인하기
index.html에서 입력후 주문하기 버튼을 클릭했을때 '주문 완료' 알림창이 나오면 성공이다.
실제로 mongoDB를 확인해서 입력한 값이 정상적으로 추가가 되었는지 까지 확인하면 완벽!
주문 조회 API 만들기 - GET 연습
화성땅 공동구매 사이트를 위해서 index.html에서 기존에 DB에 저장던 데이터를 받아서 보여주기 (Read -> GET)
1. 요청 정보 : URL=/mars, 요청 방식 =GET
2. 클라(ajax) → 서버(flask) : (없음)
3. 서버(flask) → 클라(ajax) : 전체 주문을 보내주기
app.py - 서버 코드
@app.route("/mars", methods=["GET"])
def mars_get():
#DB 전체 데이터 조회
orders_list = list(db.orders.find({},{'_id':False}))
return jsonify({'orders':orders_list})
index.html - 클라이언트 코드
function show_order() {
$('#order-box').empty()
$.ajax({
type: 'GET',
url: '/mars',
data: {},
success: function (response) {
// DB전체를 전달받은 것을 for문으로 하나씩 출력
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']
// HTML 본문에 삽입
let temp_html = `<tr>
<td>${name}</td>
<td>${address}</td>
<td>${size}</td>
</tr>`
$('#order-box').append(temp_html)
}
}
});
}
결과 확인하기
index.html에서 새로고침할때마다 저장된 데이터가 정상적으로 나타나는지 확인되면 성공!
Project02 - 스파르타피디아
http://spartacodingclub.shop/web/movie
프로젝트 준비 및 설정
Flask 폴더 구조 : static / templates / app.py
패키지 설치 : Flask, pymongo, dnspython, bs4, requests
프로젝트 뼈대 구성
- 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>
웹크롤링 조각 기능 구현해보기
API를 본격적으로 만들기 전에 익숙하지 않은 기능들은 따로 python 파일을 만들어서 미리 디버깅 해보면 좋습니다.
입력받을 부분은 URL, 별점, 코멘트 뿐인데 만들어야하는 카드에는 '제목', '썸네일이미지', '설명'도 같이 필요하다.
이러한 정보는 우리가 입력한 URL페이지의 meta태그에서 가져올 예정이다.
Meta 태그
메타 태그(meta tag)는 웹페이지가 담고 있는 컨텐츠가 아닌 웹페이지 자체의 정보를 명시하기 위한 목적으로 사용되는 태그를 의미.
이러한 웹페이지의 메타 정보는 HTML 문서 내에서 <head> 요소 아래 배치되므로 일반 유저가 보게되는 웹페이지의 컨텐츠(<body></body>)에는 아무 영향을 주지 않지만 반면에 검색엔진과 같은 기계들이 웹페이지를 읽어야할 때는 메타 태그의 내용들이 해당 서비스에서 어떻게 표시될지를 결정하는 매우 핵심적인 요소가 된다.
ex) 구글 검색 엔진, 카카오 등 SNS 공유 이미지
<meta>태그 스크랩핑 하기
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를 먼저 가져와보겠습니다.
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)
print(og_title)
print(og_description)
포스팅 API 만들기 - POST 연습
스파르타피디아 사이트를 위해서 index.html에서 URL, 평점, 코멘트를 받고 URL에서 영화정보(제목, 썸네일이미지, 설명)을 크롤링해서 DB에 함께 저장하기 (Create -> POST)
1. 요청 정보 : URL= /movie, 요청 방식 = POST
2. 클라(ajax) → 서버(flask) : url, star, comment
3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (주문 완료!)
app.py - 서버 코드
이전에 미리 만들어놓은 크롤링 조각 코드를 참고해서 사용한다.
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
client = MongoClient('----mongoDB URL-----')
db = client.dbsparta
import requests
from bs4 import BeautifulSoup
@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')
image = soup.select_one('meta[property="og:image"]')['content']
title = soup.select_one('meta[property="og:title"]')['content']
description = soup.select_one('meta[property="og:description"]')['content']
# mongoDB에 저장
doc = {
'image':image,
'title':title,
'desc':description,
'star':star_receive,
'comment':comment_receive
}
db.movies.insert_one(doc)
return jsonify({'msg':'POST 연결 완료!'})
index.html - 클라이언트 코드
function save_order() {
//input에 담긴 값 가져오기
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()
}
});
}
결과 확인하기
index.html에서 입력후 영화 기록하기 버튼을 클릭했을때 '저장 완료' 알림창이 나오면 성공이다.
실제로 mongoDB를 확인해서 입력한 값이 정상적으로 추가가 되었는지 까지 확인하면 완벽!
주문 조회 API 만들기 - GET 연습
스파르타피디아 사이트를 위해서 index.html에서 기존에 DB에 저장던 포스팅데이터를 받아서 보여주기 (Read -> GET)
1. 요청 정보 : URL=/movie, 요청 방식 =GET
2. 클라(ajax) → 서버(flask) : (없음)
3. 서버(flask) → 클라(ajax) : 전체 영화를 보내주기
app.py - 서버 코드
@app.route("/movie", methods=["GET"])
def movie_get():
# DB 전체 데이터 조회
movies_list = list(db.movies.find({}, {'_id': False}))
return jsonify({'movies': movies_list})
index.html - 클라이언트 코드
function listing() {
$('#cards-box').empty()
$.ajax({
type: 'GET',
url: '/movie',
data: {},
success: function (response) {
let rows = response['movies']
for(let i = 0; i < rows.length; i++) {
let image = rows[i]['image']
let title = rows[i]['title']
let desc = rows[i]['desc']
let star = rows[i]['star']
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)
}
}
})
}
결과 확인하기
index.html에서 새로고침할때마다 저장된 데이터가 정상적으로 나타나는지 확인되면 성공!
HW04 - 팬명록 완성하기
http://spartacodingclub.shop/web/homework
프로젝트 준비 및 설정
Flask 폴더 구조 : static / templates / app.py
패키지 설치 : Flask, pymongo, dnspython
app.py - 서버코드
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
client = MongoClient('-----mongoDB URL-----')
db = client.dbsparta
@app.route('/')
def home():
return render_template('index.html')
@app.route("/homework", methods=["POST"])
def homework_post():
name_receive = request.form['name_give']
comment_receive = request.form['comment_give']
doc = {
'name' : name_receive,
'comment' : comment_receive
}
db.homework.insert_one(doc)
return jsonify({'msg':'응원 완료!'})
@app.route("/homework", methods=["GET"])
def homework_get():
comment_list = list(db.homework.find({}, {'_id': False}))
return jsonify({'comments': comment_list})
if __name__ == '__main__':
app.run('0.0.0.0', port=5050, debug=True)
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>
<title>초미니홈피 - 팬명록</title>
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@200;300;400;500;600;700;900&display=swap"
rel="stylesheet">
<style>
* {
font-family: 'Noto Serif KR', serif;
}
.mypic {
width: 100%;
height: 300px;
background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://img.hankyung.com/photo/202205/03.30135835.1.jpg');
background-position: center 30%;
background-size: cover;
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.mypost {
width: 95%;
max-width: 500px;
margin: 20px auto 20px auto;
box-shadow: 0px 0px 3px 0px black;
padding: 20px;
}
.mypost > button {
margin-top: 15px;
}
.mycards {
width: 95%;
max-width: 500px;
margin: auto;
}
.mycards > .card {
margin-top: 10px;
margin-bottom: 10px;
}
</style>
<script>
$(document).ready(function () {
set_temp()
show_comment()
});
function set_temp() {
$.ajax({
type: "GET",
url: "http://spartacodingclub.shop/sparta_api/weather/seoul",
data: {},
success: function (response) {
$('#temp').text(response['temp'])
}
})
}
function save_comment() {
let name = $("#name").val();
let comment = $("#comment").val();
$.ajax({
type: 'POST',
url: '/homework',
data: {name_give: name, comment_give : comment},
success: function (response) {
alert(response['msg'])
window.location.reload()
}
})
}
function show_comment() {
$('#comment-list').empty()
$.ajax({
type: "GET",
url: "/homework",
data: {},
success: function (response) {
let rows = response['comments']
for (let i = 0; i < rows.length; i++) {
let name = rows[i]['name']
let comment = rows[i]['comment']
let temp_html = `<div class="card">
<div class="card-body">
<blockquote class="blockquote mb-0">
<p>${comment}</p>
<footer class="blockquote-footer">${name}</footer>
</blockquote>
</div>
</div>`
$('#comment-list').append(temp_html)
}
}
});
}
</script>
</head>
<body>
<div class="mypic">
<h1>세븐틴 팬명록</h1>
<p>현재기온: <span id="temp">36</span>도</p>
</div>
<div class="mypost">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="name" placeholder="url">
<label for="floatingInput">닉네임</label>
</div>
<div class="form-floating">
<textarea class="form-control" placeholder="Leave a comment here" id="comment"
style="height: 100px"></textarea>
<label for="floatingTextarea2">응원댓글</label>
</div>
<button onclick="save_comment()" type="button" class="btn btn-dark">응원 남기기</button>
</div>
<div class="mycards" id="comment-list">
<div class="card">
<div class="card-body">
<blockquote class="blockquote mb-0">
<p>새로운 앨범 너무 멋져요!</p>
<footer class="blockquote-footer">호빵맨</footer>
</blockquote>
</div>
</div>
<div class="card">
<div class="card-body">
<blockquote class="blockquote mb-0">
<p>새로운 앨범 너무 멋져요!</p>
<footer class="blockquote-footer">호빵맨</footer>
</blockquote>
</div>
</div>
<div class="card">
<div class="card-body">
<blockquote class="blockquote mb-0">
<p>새로운 앨범 너무 멋져요!</p>
<footer class="blockquote-footer">호빵맨</footer>
</blockquote>
</div>
</div>
</div>
</body>
</html>
'스파르타코딩클럽 > 웹개발' 카테고리의 다른 글
웹개발종합반 개발일지 | 5주차 - 7,8강 AWS EC2 인스턴스 생성 (0) | 2022.09.01 |
---|---|
웹개발종합반 개발일지 | 5주차 - 1,2,3,4,5,6강 (0) | 2022.08.29 |
웹개발종합반 개발일지 | 4주차 - 숙제 (0) | 2022.08.29 |
웹개발종합반 개발일지 | 4주차 - 9,10,11,12,13강 (0) | 2022.08.29 |
웹개발종합반 개발일지 | 4주차 - 5,6,7,8강 (0) | 2022.08.28 |