1) 프로젝트 폴더(PEDIA) 생성
2) 프로젝트 폴더 안에 app.py 파일 생성
3) 가상환경(venv) 만들고 활성화하기
4) PEDIA 폴더 안에 templates 폴더 생성
5) templates 폴더 안에 index.html 파일 생성
pedia 폴더 구조
- - -
pedia
|— venv
|— app.py (서버)
|— templates
|— index.html (클라이언트 파일)
6) 패키지 설치 (flask, pymongo, dnspython, requests, bs4,)
pip install flask pymongo dnspython requests bs4(여러 개를 설치할 때는 띄어쓰기로 구분)
스파르타피디아에서 나는 URL, 별점, 코멘트만 작성했는데 기록되는 정보들은 이미지, 제목, 영화 설명까지 딸려와 기록된다. 이것은 meta 태그를 활용하면 된다.
ex) 카카오톡에서 영화 링크 보낼 때
링크만 보냈는데 위의 세 가지 정보가 딸려오는데 이 정보들이 meta태그이다.
가져올 meta 태그 정보들은 스파르타피디아에서 포스팅 정보에 들어간다. meta 태그로 크롤링을 하면 원하는 정보를 더 쉽게 가져올 수 있다.
1) 테스트를 위해 새 파일(meta_prac.py)파일을 만든다.
2) 크롤링 기본 코드를 넣어준다.
import requests
from bs4 import BeautifulSoup
URL = 'https://movie.daum.net/moviedb/main?movieId=161806'
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를 먼저 가져와보겠습니다.
3) 이제 meta 태그를 크롤링 → 구글링: meta 태그 크롤링
URL을 들어가보면,
크롤링 해올 정보들이 meta 태그에 들어가 있는 것을 볼 수 있다.
이전에 크롤링 했던 방법은 개발자도구의 데이터에서 원하는 부분의 Copy → Copy selector로 선택자를 복사해서 select_one()함수를 이용해서 값을 담고 .text()로 텍스트 부분만 출력했다.
이번에는 좀 더 특정지어서 구체적으로 명령내리는 방법을 써보자.
ogtitle = soup.select_one('meta[property="og:title"]')['content']
print(ogtitle)
→ meta 태그 중 'property'가 "og:title"인 것의 'content'를 가지고와서 print해라.
ogtitle = soup.select_one('meta[property="og:title"]')['content']
ogdesc = soup.select_one('meta[property="og:description"]')['content']
ogimage = soup.select_one('meta[property="og:image"]')['content']
print(ogimage,ogtitle,ogdesc)
만약, URL을 바꿔본다면,
import requests
from bs4 import BeautifulSoup
URL = 'https://spartacodingclub.kr'
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')
ogtitle = soup.select_one('meta[property="og:title"]')['content']
ogdesc = soup.select_one('meta[property="og:description"]')['content']
ogimage = soup.select_one('meta[property="og:image"]')['content']
print(ogimage,ogtitle,ogdesc)
잘 작동한다. 이것은 어떤 URL들이 공통적으로 가지고 있는 요소들을 크롤링 해와서 보여주는 방법인 것이다. 왜냐면,
유저가 저 URL에 어느 URL을 넣을지 모르기 때문에 이런 방법이 있는 것이다.
유저가 URL, 별점, 코멘트를 작성하고 '기록하기'를 누르면 기록한 데이터와 이 URL의 meta 태그(title, description, image)도 같이 db에 넣어줄 때 백엔드가 사용될 것이다. 이제 이것이 app.py의 어떤 부분에 들어갈지 알아보자.
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html') # html을 app.py로 가져오는 애(Flask의 render_template)
@app.route("/movie", methods=["POST"]) # API 1
def movie_post():
sample_receive = request.form['sample_give'] # 'sample give'를 받아서 뭔가를 함.
print(sample_receive)
return jsonify({'msg':'POST 연결 완료!'}) # 'POST 연결 완료'라는 'msg'를 클라이언트로 내려줌.
@app.route("/movie", methods=["GET"]) # API 2 # "/movie"로 들어옴.
def movie_get(): # 아무것도 안받음.
return jsonify({'msg':'GET 연결 완료!'}) # 'GET 연결 완료!'라는 'msg'를 클라이언트로 내려줌.
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, 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) => { # app.py의 API(GET요청)의 '/movie'로 뭔가를 요청함(fetch).
console.log(data) # app.py에서 내려준 데이터를 콘솔에 찍음.
alert(data['msg']) # app.py에서 내려준 데이터의 'msg'값을 알림으로 띄운다.
})
}
function posting() { # 기록하기 버튼에 연결된 함수.
let formData = new FormData();
formData.append("sample_give", "샘플데이터"); # "sample_give"라는 곳에 데이터를 축적해서
fetch('/movie', {method : "POST",body : formData}).then((res) => res.json()).then((data) => { # formData에 실어서 POST 요청으로 '/movie'로 보낸다(fetch).
console.log(data) # app.py에서 내려준 데이터를 콘솔에 찍음.
alert(data['msg']) # app.py에서 내려준 데이터의 '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="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>
/movie
, 요청 방식 = POST
url
, comment
포스팅 완료!
)[서버 코드 - app.py]
@app.route("/movie", methods=["POST"])
def movie_post():
sample_receive = request.form['sample_give']
print(sample_receive)
return jsonify({'msg':'POST 연결 완료!'})
[클라이언트 코드 - index.html]
function posting() {
let formData = new FormData();
formData.append("sample_give", "샘플데이터");
fetch('/movie', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
console.log(data);
alert(data["msg"]);
});
}
<button onclick="posting()" type="button" class="btn btn-dark">기록하기</button>
→ 어느 버튼에 들어가있는지 확인
<button onclick="posting()" type="button" class="btn btn-dark">기록하기</button>
→ ""posting()""함수 확인
function posting() {
let formData = new FormData();
formData.append("sample_give", "샘플데이터");
fetch('/movie', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
console.log(data);
alert(data["msg"]);
});
}
→ "샘플데이터"라는 데이터를 만들어서 formData라는 변수에 넣고 "sample_give"라는 이름으로 주고 있다(append).
→ "샘플데이터"라는 데이터를 만들어서 formData라는 변수에 넣고 "sample_give"라는 이름으로 주고 있다(append).
→ 그 데이터를 실어서 '/movie'(URL)에 formData를 POST라는 방식으로(method: "POST") 요청함 = 서버(백엔드)로 가져옴(fetch).
fetch('/movie', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
→ app.py(백엔드)에서 보면 "/movie"라는 이름으로 데이터(request.form['sample_give'])가 들어옴(flask).
@app.route("/movie", methods=["POST"])
def movie_post():
sample_receive = request.form['sample_give']
→ 'sample_give'가 데이터를 찾음 (formData.append("sample_give", "샘플데이터"))
→ '샘플데이터'가 터미널에 찍히고
print(sample_receive)
→ 메세지({'msg':'POST 연결 완료!'})를 내려줌.(서버(flask) → 클라(fetch))
return jsonify({'msg':'POST 연결 완료!'})
→ 내려준 메시지는 클라이언트(index.html)의 console.log(data)에 들어옴.
console.log(data);
console.log({'msg':'POST 연결 완료!'});
→ 이 데이터는 딕셔너리. 이 데이터 값의 'msg'만 가지고 alert를 띄워준다.
alert(data["msg"]);
→ 클라이언트와 서버 연결 확인할 때 'sample_give'로 받아왔던 것처럼 이번엔 'url_give', 'comment_give'로 받아와서 'url_receive', 'comment_receive'의 형태로 각각의 변수에 넣어보자.
@app.route("/movie", methods=["POST"])
def movie_post():
#sample_receive = request.form['sample_give']
url_receive = request.form['url_give']
comment_receive = request.form['comment_give']
#print(sample_receive)
return jsonify({'msg':'POST 연결 완료!'})
→ 스파르타피디아에서 나는 URL, 별점, 코멘트만 작성했는데 기록되는 정보들은 이미지, 제목, 영화 설명까지 딸려와 기록된다. 이것은 URL을 기반으로 meta 태그를 이용해서 크롤링을 해오면 되는데, 미리 만들어둔 meta_prac을 참고해서 붙여넣어보자.
[meta_prac 코드]
import requests
from bs4 import BeautifulSoup
URL = 'https://movie.daum.net/moviedb/main?movieId=161806'
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')
ogtitle = soup.select_one('meta[property="og:title"]')['content']
ogdesc = soup.select_one('meta[property="og:description"]')['content']
ogimage = soup.select_one('meta[property="og:image"]')['content']
print(ogimage,ogtitle,ogdesc)
[app.py로 가져옴]
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
import requests
from bs4 import BeautifulSoup
@app.route('/')
def home():
return render_template('index.html')
@app.route("/movie", methods=["POST"])
def movie_post():
#sample_receive = request.form['sample_give']
url_receive = request.form['url_give']
comment_receive = request.form['comment_give']
#print(sample_receive)
URL = 'https://movie.daum.net/moviedb/main?movieId=161806'
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')
ogtitle = soup.select_one('meta[property="og:title"]')['content']
ogdesc = soup.select_one('meta[property="og:description"]')['content']
ogimage = soup.select_one('meta[property="og:image"]')['content']
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)
→ 이제 이 크롤링 코드에 크롤링해서 가져온 데이터를 받을 URL에 app.py(백엔드)에서 url 데이터를 받는 변수 url_receive를 넣어준다.
URL = 'https://movie.daum.net/moviedb/main?movieId=161806'
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')
URL = 'https://movie.daum.net/moviedb/main?movieId=161806'
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')
→ 이제 받은 데이터들(url_receive, comment_receive, ogtitle, ogdesc, ogimage)를 pymongo를 이용해서 db에 넣는다. pymongo import 코드를 넣어준다.
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
client = MongoClient('mongodb+srv://sparta:test@cluster0.wop0dox.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.route("/movie", methods=["POST"])
def movie_post():
#sample_receive = request.form['sample_give']
url_receive = request.form['url_give']
comment_receive = request.form['comment_give']
#print(sample_receive)
URL = 'https://movie.daum.net/moviedb/main?movieId=161806'
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')
ogtitle = soup.select_one('meta[property="og:title"]')['content']
ogdesc = soup.select_one('meta[property="og:description"]')['content']
ogimage = soup.select_one('meta[property="og:image"]')['content']
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)
→ 이제 document를 만들어서 insert_one(doc)해주면 된다. pymongo로 데이터 db에 저장하기 코드로 받은 데이터들을 넣어준 변수의 값들을 딕셔너리 형태로 넣어준다.
doc = {
'title':ogtitle,
'desc':ogdesc,
'image':ogimage,
#'url':url_receive, html을 보면 우리가 영화 포스팅을 붙여넣는데 url이 필요한 부분이 없다. 그래서 저장도 해줄 필요 없음.
'comment':comment_receive
}
→ 이제 insert_one(doc)으로 db에 movies 프로젝트에 넣어준다.
db.movies.insert_one(doc)
→ db에 저장이 완료 되었다는 데이터의 'msg' 값을 '저장완료!'로 변경한다.
return jsonify({'msg':'저장완료!'})
→ 백엔드 완성
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
client = MongoClient('mongodb+srv://sparta:test@cluster0.wop0dox.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.route("/movie", methods=["POST"])
def movie_post():
#sample_receive = request.form['sample_give']
url_receive = request.form['url_give']
comment_receive = request.form['comment_give']
#print(sample_receive)
URL = 'https://movie.daum.net/moviedb/main?movieId=161806'
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')
ogtitle = soup.select_one('meta[property="og:title"]')['content']
ogdesc = soup.select_one('meta[property="og:description"]')['content']
ogimage = soup.select_one('meta[property="og:image"]')['content']
doc = {
'title':ogtitle,
'desc':ogdesc,
'image':ogimage,
'url':url_receive,
'comment':comment_receive
}
db.movies.insert_one(doc)
return jsonify({'msg':'저장완료!'})
@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)
이제 서버는 완성했으니까 서버에서 url_receive와 comment_receive가 index.html(클라이언트)로부터 url이 포함되어있는 input 태그의 id값과 comment가 포함되어있는 textarea 태그의 id값을 jQuery를 이용해서 val() 밸류값을 뽑아 각각의 변수에 넣고 formData에 담아서 url_give, comment_give의 형태로 .append 해서 fetch로 서버에 데이터를 보내주자.
→ index_html에서 '기록하기'버튼에 연결되어있는 posting()함수를 수정한다. 스파르타피디아에서 사용자가 입력한 url과 comment 값을 "샘플데이터"의 형태로 담아주기 위해 각 정보가 포함되어있는 태그의 id값을 jQuery의 val()을 이용해서 밸류값을 추출해 각각의 변수에 담고 formData에 담아서 url_give, comment_give의 형태로 .append 해서 fetch로 서버에 데이터를 보내주자.
function posting() {
let formData = new FormData();
formData.append("sample_give", "샘플데이터");
fetch('/movie', { method: "POST", body: formData }).then((res) => res.json()).then((data) => {
console.log(data)
alert(data['msg'])
})
}
<input id="url" type="email" class="form-control" placeholder="name@example.com">
<label>영화URL</label>
<textarea id="comment" class="form-control" placeholder="Leave a comment here"></textarea>
<label for="floatingTextarea2">코멘트</label>
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()
})
}
→ 잘 되는지 브라우저에서 주문해보고 mongoDB에서 확인해보자.
window.location.reload()로 로딩이 완료되면 자동으로 fetch로 데이터를 날려서 사용자가 기록한 포스팅 카드들이 붙게 만든다.
(POST요청으로 DB에 데이터가 저장되고 저장완료! alert가 뜬 후 Refresh가 되어 페이지가 로딩되면 자동으로 fetch로 데이터를 날려 GET요청을 해서 데이터를 받아와서 보여준다.)
/movie
, 요청 방식 = GET
전체 주문을 보내주기
[서버 코드 - app.py]
@app.route("/movie", methods=["GET"])
def movie_get():
return jsonify({'msg':'GET 연결 완료!'})
[클라이언트 코드 - index.html]
$(document).ready(function(){
listing();
});
function listing() {
fetch('/movie').then((res) => res.json()).then((data) => {
console.log(data)
alert(data['msg'])
})
}
받을 것 없이 db의 movies에서 영화정보를 다 가져와서(담아서) 내려주기만 하면 된다.
→ 일단, DB에서 데이터를 서버로 다 가져옴.(pymongo 사용)
@app.route("/movie", methods=["GET"])
def movie_get():
all_movies = list(db.movies.find({},{'_id':False}))
return jsonify({'result':all_movies})
→ 서버에서 클라이언트로 데이터가 잘 내려갔는지 all_movies를 꺼내서 콘솔에 출력해보자.
$(document).ready(function () {
listing();
});
function listing() {
fetch('/movie').then((res) => res.json()).then((data) => {
let rows = data['result']
console.log(rows) // 콘솔에서만 확인해보자.
//alert(data['msg']) 내려주는 데이터가 'msg'값이 아니기 때문에 없애줌.
})
}
리스트의 형태로 가져옴. 리스트를 만나면 돌려라!
→ 위에서 가져온 데이터 리스트에 저장되는 데이터들이 많아졌을 경우를 생각해보면, 페이지에 ('영화URL'은 필요없고) 'comment', 'desc', 'image', 'title'을 각각 출력하기 위해서는, 서버에서 내려온 리스트 형태의 데이터를 forEach반복문을 통해 하나씩 뽑아내서 그 데이터의 'comment', 'desc', 'image', 'title'의 값을 각각의 변수에 담고 붙여주고 싶은 html의 형태로 jQuery를 사용해서 변수 temp_html에 담아 append해주면 된다.
→ 서버에서 내려온 리스트 형태의 데이터를 forEach반복문을 통해 하나씩 뽑아서 콘솔에 찍어보자.
function listing() {
fetch('/movie').then(res => res.json()).then(data => {
let rows = data['result']
rows.forEach((a) =>
let comment = a['comment']
let title = a['title']
let image = a['image']
let desc = a['desc']
console.log(comment,title,image,desc)
→ 붙여주고 싶은 html에는 데이터의 '이름','주소','평수' 각각 따로 붙여줘야 하니까 각각의 변수에 담고 temp_html에 원하는 html의 형태로 백틱으로 감싸서 담아서 id="cards-box"에 붙여준다. 붙여주기전에 .empty()로 원래 있던 카드들은 비워준다.
function listing() {
fetch('/movie').then(res => res.json()).then(data => {
let rows = data['result']
//console.log(rows)
$('#cards-box').empty()
rows.forEach((a) => {
let comment = a['comment']
let title = a['title']
let image = a['image']
let desc = a['desc']
//console.log(comment,title,image,desc)
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 class="mycomment">${comment}</p>
</div>
</div>
</div>`
$('#cards-box').append(temp_html)
})
})
}
→ 브라우저에서 서버에서 내려온 데이터가 출력되는지 보자.
새로운 영화를 기록해보자.
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('/')
def home():
return render_template('index.html')
@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 = {
'title':ogtitle,
'desc':ogdesc,
'image':ogimage,
'comment':comment_receive
}
db.movies.insert_one(doc)
return jsonify({'msg':'저장완료!'})
@app.route("/movie", methods=["GET"])
def movie_get():
all_movies = list(db.movies.find({},{'_id':False}))
return jsonify({'result':all_movies})
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, 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() {
fetch('/movie').then(res => res.json()).then(data => {
let rows = data['result']
$('#cards-box').empty()
rows.forEach((a) => {
let comment = a['comment']
let title = a['title']
let image = a['image']
let desc = a['desc']
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 class="mycomment">${comment}</p>
</div>
</div>
</div>`
$('#cards-box').append(temp_html)
})
})
}
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()
})
}
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>
[ index.html 별점 추가하기 코드]
<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>
→ 위와 같이 만들기 위해 영화 URL이 있는 div와 코멘트가 있는 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>
→ 이제 위와 같이 별점을 선택해서 기록하면 아래의 형태로 포스팅 카드가 붙게 만들어보자.
→ 별점마다 value 속성값이 들어있다.
일단 선택한 별점을 temp_html에 붙여넣기 위해서 별모양의 문자가 필요한데
위 별점 선택 div의 select 태그에 지정되어있는 id값('id = star')을 forEach 반복문 안에 하나의 변수에 let star = a['star']
로 넣어주고
예전에 배웠던 반복함수 repeat()를 이용해서 변수 star의 값에 따라 별모양을 반복한 값을 또 하나의 변수에 star_repeat = '⭐'.repeat(star)
로 넣어준다.
이제 temp_html에 'id = star'에서 사용자가 선택한 별점 값이 들어있는 변수 'star'의 값만큼 반복된 별모양들이 들어있는 변수 star_repeat를 <p>${star_repeat}</p>
의 형태로 'desc'와 'comment' 사이에 넣어준다.
$(document).ready(function () {
listing();
});
function listing() {
fetch('/movie').then((res) => res.json()).then((data) => {
let rows = data['result']
//console.log(rows)
$('#cards-box').empty()
rows.forEach((a) => {
let comment = a['comment']
let title = a['title']
let image = a['image']
let desc = a['desc']
let star = a['star']
let star_repeat = '⭐'.repeat(star)
//console.log(comment,title,image,desc)
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_repeat}</p>
<p class="mycomment">${comment}</p>
</div>
</div>
</div>`
$('#cards-box').append(temp_html)
})
})
}
→ 이제 이것을 db에 저장하고(POST) db에서 데이터를 가져와서 브라우저에 띄우기 위해(GET) 클라이언트(index.html)의 posting()함수에서 별의 값을 val()로 담아 star라는 변수에 넣고 'star_give'의 형태로 변수 star의 값을 formData에 담아(.append) fetch로 서버(app.py)에 POST요청으로 데이터를 보낼 것이다. 그리고 서버(app.py)에서 'star_give'를 'star_receive'의 형태로 받아서 db에 저장할 값인 document에 'star_receive'를 담을 것이다.
[클라이언트(index.html)]
function posting() {
let url = $('#url').val()
let comment = $('#comment').val()
let star = $('#star').val()
let formData = new FormData()
formData.append("url_give", url)
formData.append("comment_give", comment)
formData.append("star_give", star)
fetch('/movie', { method: "POST", body: formData }).then(res => res.json()).then(data => {
alert(data['msg'])
window.location.reload()
})
}
[서버(app.py)]
@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']
URL = 'https://movie.daum.net/moviedb/main?movieId=161806'
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')
ogtitle = soup.select_one('meta[property="og:title"]')['content']
ogdesc = soup.select_one('meta[property="og:description"]')['content']
ogimage = soup.select_one('meta[property="og:image"]')['content']
doc = {
'title':ogtitle,
'desc':ogdesc,
'image':ogimage,
'star':star_receive,
'comment':comment_receive
}
db.movies.insert_one(doc)
return jsonify({'msg':'저장완료!'})
→ 브라우저에서 영화 포스팅 카드를 추가해보고 db에서 잘 저장되는지 확인해보자.