💡수업 목표💡
- Flask 프레임워크를 활용해서 API를 만들 수 있다.
- '화성에 땅사기' API를 만들고 클라이언트에 연결한다.
- '스파르타피디아' API를 만들고 클라이언트와 연결한다.
2022.08.28 - [스파르타코딩클럽/웹개발종합반] - 웹개발종합반 개발일지 | 4주차 - 1,2,3,4강 Flask 시작하기
2022.08.28 - [스파르타코딩클럽/웹개발종합반] - 웹개발종합반 개발일지 | 4주차 - 5,6,7,8강
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에서 새로고침할때마다 저장된 데이터가 정상적으로 나타나는지 확인되면 성공!
'스파르타코딩클럽 > 웹개발' 카테고리의 다른 글
웹개발종합반 개발일지 | 4주차 (0) | 2022.08.29 |
---|---|
웹개발종합반 개발일지 | 4주차 - 숙제 (0) | 2022.08.29 |
웹개발종합반 개발일지 | 4주차 - 5,6,7,8강 (0) | 2022.08.28 |
웹개발종합반 개발일지 | 4주차 - 1,2,3,4강 Flask 시작하기 (0) | 2022.08.28 |
웹개발종합반 개발일지 | 3주차 (0) | 2022.08.28 |