4주차 - Flask / 서버 /API
4주차에는 드디어 강의 내용에 내가 모르는 것들로 100% 가득 차 있었다.
그래서 조금 두렵기도 했고 설렜다.
부딪혀보고 나니 확실히 처음 배우는 것이라서 엄청 익숙하지가 않았다.
그래도 실습 여러 개를 영상보면서 정리하며 따라해도 조금 익숙해지지가 않았다.
하지만, 숙제를 할 때 했던 것을 가져와서 하긴 했지만 그래도 해설 코드를 보지 않고
나 혼자 했기 때문에 확실히 조금은 익숙해진 것 같기도 하다!
또한 1, 2주차 숙제를 나 혼자서 Develope 시켰다는 것이 굉장히 뿌듯했다!
Flask 시작하기 - 서버 만들기
서버를 돌아가게 만드는 파일 이름은 통상적으로 app.py
로 많이 쓰인다.
Flask : 프레임워크
※ 프레임워크 VS 라이브러리
프레임워크 : 남이 짜둔 규칙이나 틀 안에서 자유로운 코딩
라이브러리 : 자유롭게 코딩하는데 남이 만들어 놓은 것을 중간에 갖다 쓰는 것
따라서, 통상적으로 프레임워크는 하나의 프레임워크에서 작업하고
라이브러리는 여러 개를 사용할 수 있다!
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)
👉 port 5000으로 접속할 수 있는 서버를 만들었다!
@app.route(”/”)
: 사용자가 주소창에 엔터를 치면 “/”가 자동으로 맨 끝에 붙지만 숨겨져서 사용자의 눈에는 보이지 않는다.
따라서 @app.route(”/”)
는 [localhost:5000](http://localhost:5000)
이 주소창에 쳐졌을 때를 의미하고
그때 home이라는 함수를 실행한다!
port
: 출입구의 이름 → port 5000
: 5000번 출입구에 서버를 만들었다!
def home()
함수의 return 값 : 웹페이지에서 출력될 문구
→ <button></button>
을 입력하면 버튼이 나온다!
접속 : localhost:5000 입력!
→ 내가 만든 서버에 5000번 문으로 접속하겠다라는 의미
Flask에 HTML 파일 주기
현재 프로젝트 폴더에 templates
/ static
이라는 폴더를 만들고
html 파일은 templates
폴더에, CSS파일은 static
폴더에 넣는다.
그리고 나서 파이썬에서 import render_template
를 하고
함수 return 값을 render_template(”html파일이름”) 이렇게 하면
html을 가져올 수 있다!!
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
return render_template("index.html")
if __name__ == '__main__':
app.run('0.0.0.0',port=5000,debug=True)
API 만들기
API : 서버가 클라이언트의 요청을 받기 위해서 만들어 놓는 창구
API의 여러 종류 중 주로 쓰는 2가지 종류
서버에 요청할 때 → Ajax로 콜하기
API 만들기 → 클라이언트에서 Ajax로 콜하기 반복
request
, jsonify
추가로 import
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)
[localhost:5000](http://localhost:5000)
에 가서 개발자도구 콘솔에서 Ajax 콜을 해보면,
$.ajax({
type: "GET",
url: "/test?title_give=봄날은간다",
data: {},
success: function(response){
console.log(response)
}
})
콘솔에 이렇게 찍힌다!
이때 response는 서버에서 클라이언트에게 내려주는 정보이다.
이 response의 내용은?
Flask로 만든 서버의 jsonify를 사용해서 만든
return jsonify({'result':'success', 'msg': '이 요청은 GET!'})
리턴 값이다!!
과정 분석
@app.route('/test', methods=['GET'])
def test_get():
title_receive = request.args.get('title_give')
print(title_receive)
return jsonify({'result':'success', 'msg': '이 요청은 GET!'})
$.ajax({
type: "GET",
url: "/test?title_give=봄날은간다",
data: {},
success: function(response){
console.log(response)
}
})
→ 상세 정보 : type은 GET
이고, url이 /test?title_give=봄날은간다
이때,
methods=["GET"]
이렇게 타입은 GET으로 받는다고 약속했기 때문에 Ajax로 콜할 때 GET
타입으로 요청/test
로 했기 때문에 Ajax로 콜하는 url도 /test
로 요청"title_give"
로 정보를 요청하라고 약속했기 때문에 Ajax로 콜할 때 ?title_give=봄날은간다
로 요청 (?
뒤에는 요청할 데이터)이때, API에서 일어나는 일
고객이 “title_give”
에 봄날은간다
를 가지고 API에 왔다.
title_receive = request.args.get('title_give')
: title_give
로 가져온 값 가져와봐! 한 후 title_receive
에 저장print(title_receive)
: 서버에 클라이언트가 가져온 값(title_give
) 출력return jsonify({'result':'success', 'msg': '이 요청은 GET!'})
: 값을 클라이언트에게 제공(Ajax의 response으로 저장됨): 생김새가 조금 다르지만, 원리는 GET과 같다!
: GET과 비교하며 생각해보자!
@app.route('/test', methods=['POST'])
def test_post():
title_receive = request.form['title_give']
print(title_receive)
return jsonify({'result':'success', 'msg': '이 요청은 POST!'})
API 경로 : /test
/ 타입 : POST
title_receive = request.form['title_give']
: 클라이언트가 title_give
로 가져온 값 title_receive에 저장
→ GET과 원리는 똑같지만 request 뒤 생김새가 다르다. .form["title_give"]
$.ajax({
type: "POST",
url: "/test",
data: { title_give:'봄날은간다' },
success: function(response){
console.log(response)
}
})
찾아갈 경로 : /test
/ 타입 : POST
GET과 다른점 : DATA를 주는 방식
GET : data를 url으로 url: "/test?title_give=봄날은간다"
이렇게 서버에 전달, data는 빈 값 data : {},
POST : data를 data에 data: { title_give:'봄날은간다' }
이렇게 서버에 전달, url에는 찾아갈 경로만 입력 url : "/test",
[모두의책리뷰] - POST 연습(리뷰 저장)
서버에서 하는 일 : API에서 데이터(제목, 저자, 리뷰)를 받아서 DB에 저장
→ DB에 데이터를 추가하는 insert
사용
@app.route('/review', methods=['POST'])
def write_review():
title_receive = request.form['title_give']
author_receive = request.form['author_give']
review_receive = request.form['review_give']
doc = {
"title" : title_receive,
"author" : author_receive,
"review" : review_receive
}
db.bookreview.insert_one(doc)
return jsonify({'msg': '저장 완료!'})
title_give
/ author_give
/ review_give
으로 받은 데이터를 변수에 저장하고,
DB에 데이터를 저장하기 위해
doc = {
"title" : title_receive,
"author" : author_receive,
"review" : review_receive
}
이렇게 doc을 딕셔너리 형태로 저장하고
db.bookreview.insert_one(doc)
이렇게
DB에 bookreview라는 collection에 doc 데이터를 저장한다.
클라이언트에서 하는 일 : 제목, 저자, 리뷰를 가져와서 서버로 보낸다.
function makeReview() {
let title = $("#title").val();
let author = $("#author").val();
let review = $("#bookReivew").val();
$.ajax({
type: "POST",
url: "/review",
data: {title_give: title, author_give:author, reivew_give:review},
success: function (response) {
alert(response["msg"]);
window.location.reload();
}
})
}
makeReview()
라는 함수가 호출될 때 실행
let title = $("#title").val();
let author = $("#author").val();
let review = $("#bookReivew").val();
JQuery를 활용해서 각 input(제목, 저자, 리뷰)의 값을 저장한다.
$.ajax({
type: "POST",
url: "/review",
data: {title_give: title, author_give:author, reivew_give:review},
success: function (response) {
alert(response["msg"]);
window.location.reload();
}
})
}
Ajax를 통해 data를 미리 약속한 title_give
/ author_give
/ review_give
를 Key로, input의 값을 저장한 변수들을 각각의 Value로 하는 딕셔너리로 저장해서 요청한다.
👉 이렇게 하면 서버의 DB에 요청한 데이터들(제목, 저자, 리뷰)이 잘 저장된다.
[모두의책리뷰] - GET 연습(리뷰 보여주기)
서버에서 하는 일 : 클라이언트로부터 데이터를 받을 것이 없고, 모든 데이터(제목, 저자, 리뷰)를 DB에서 가져와서 그대로 클라이언트에 내려주면 된다!
→ DB에서 여러 데이터를 조회하는 find
사용
@app.route('/review', methods=['GET'])
def read_reviews():
reviews = list(db.bookreview.find({}, {'_id': False}))
return jsonify({'all_reviews': reviews})
클라이언트의 데이터가 저장된 DB에서 데이터를 가져오는 find
를 사용해서
list(db.bookreview.find({}, {'_id': False}))
코드 작성 → _id
열 빼고 모든 데이터를 리스트로 reviews라는 변수에 저장
그 후 return 값으로 all_reviews
라는 Key, 데이터가 들어 있는 변수 reviews
를 value로 하는 딕셔너리로 반환
클라이언트에서 하는 일 : all_reviews
가 잘 내려오면 그것을 받아서 for문을 돌면서 리뷰들을 붙여주기
페이지가 새로고침되면 showReview()
라는 함수 실행
→ 페이지가 처음 열렸을 때 새로고침되므로 기존의 리뷰들 보여줄 수 있다.
→ 리뷰 작성하기를 누르면 페이지가 새로고침되게 해서 작성한 리뷰까지 추가되어서 보여진다.
$(document).ready(function () {
showReview();
});
function showReview() {
$.ajax({
type: "GET",
url: "/review",
data: {},
success: function (response) {
let reviews = response["all_reviews"];
for (let i = 0; i < reviews.length; i++) {
let title = reviews[i]["title"];
let author = reviews[i]["author"];
let review = reviews[i]["review"];
let temp_html = `<tr>
<td>${title}</td>
<td>${author}</td>
<td>${review}</td>
</tr>`
$("#reviews-box").append(temp_html)
}
}
})
}
all_reviews
라는 서버에서 내려준 DB 데이터가 response에 저장되어 있다.
따라서, response 중에 all_reviews
만을 뽑아서 reviews
변수에 저장
현재 reviews 변수에는 제목, 저자, 리뷰가 딕셔너리 형태로 저장되어 있으므로
for문을 통해서 i번째 데이터 추출 후 jquery를 통해서 append하여 html 태그 추가해서 화면에 보여주기
[나홀로 메모장] - API 설계
API에 어떤 기능이 필요한지 먼저 설계
필요한 기능
→ DB에 저장해야할 것 : 카드의 요소들(이미지, 제목, 제목링크, 요약, 코멘트)
/memo
/ 요청 방식 = POST
/memo
/ 요청 방식 = GET
[나홀로 메모장] - 미리 테스트해보는 조각 기능 구현
우리는 URL을 넣어서 이미지, 제목, 요약을 자동으로 가져오게 해야한다.
이 URL에 이 정보들은 안의 태그에 있다.
따라서, meta태그를 스크래핑해야한다!
※ meta 태그는 눈에 보이는 태그 이외의 사이트의 속성을 설명해주는 태그이다.
meta태그를 스크래핑하려고 할 때 해오던 방식대로 하면 스크래핑이 되지 않는다.
import requests
from bs4 import BeautifulSoup
url = 'https://movie.naver.com/movie/bi/mi/basic.nhn?code=171539'
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')
title = soup.select_one("head > meta:nth-child(9)")
print(title)
이렇게 하면 meta 태그 내용이 나오지 않는다.
이유는, 웹 페이지에서 검사를 눌러서 나오는 meta 태그의 순서와 파이썬 코드가 접속했을 때 나오는 meta 태그의 순서가 다르기 때문이다.
따라서, Beautifulsoup을 사용하는 다른 방법을 알아야 한다!
import requests
from bs4 import BeautifulSoup
url = 'https://movie.naver.com/movie/bi/mi/basic.nhn?code=171539'
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')
title = soup.select_one("meta[property="og:title"]")
print(title)
title = soup.select_one("meta[property="og:title"]")
👉 meta 태그 중에서 property="og:ttitle"
인 meta 태그를 가져오라는 뜻!
[나홀로메모장] - POST 연습 (메모하기)
@app.route('/memo', methods=['POST'])
def saving():
url_receive = request.form['url_give']
comment_receive = request.form['comment_give']
@app.route('/memo', methods=['POST'])
def saving():
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')
title = soup.select_one('meta[property="og:title"]')["content"]
image = soup.select_one('meta[property="og:image"]')["content"]
desc = soup.select_one('meta[property="og:description"]')["content"]
@app.route('/memo', methods=['POST'])
def saving():
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')
title = soup.select_one('meta[property="og:title"]')["content"]
image = soup.select_one('meta[property="og:image"]')["content"]
desc = soup.select_one('meta[property="og:description"]')["content"]
doc = {
'title': title,
'image': image,
"desc" : desc,
"url" : url_receive,
"comment" : comment_receive
}
db.articles.insert_one(doc)
return jsonify({'msg':'저장이 완료되었습니다!'})
function postArticle() {
let url = $("#post-url").val();
let comment = $("#post-comment").val();
function postArticle() {
let url = $("#post-url").val();
let comment = $("#post-comment").val();
$.ajax({
type: "POST",
url: "/memo",
data: {url_give:url, comment_give:comment},
success: function (response) { // 성공하면
alert(response["msg"]);
}
})
}
기사저장을 눌러서 postAritcle()이 실행되어서 ajax 콜을 하고 난 후 페이지가 새로고침 되게 하기
window.location.reload();
사용
function postArticle() {
let url = $("#post-url").val();
let comment = $("#post-comment").val();
$.ajax({
type: "POST",
url: "/memo",
data: {url_give:url, comment_give:comment},
success: function (response) { // 성공하면
alert(response["msg"]);
window.location.reload();
}
})
}
[나홀로메모장] - GET 연습 (보여주기)
→ list(db.articles.find({}, {'_id': False}))
로 DB의 데이터를 가져와서 articles
변수에 저장
jsonify
로 클라이언트에게 내려주기
@app.route('/memo', methods=['GET'])
def listing():
articles = list(db.articles.find({}, {'_id': False}))
return jsonify({"all_articles":articles})
function showArticles() {
$.ajax({
type: "GET",
url: "/memo",
data: {},
success: function (response) {
let articles = response["all_articles"];
for (let i = 0; i < articles.length; i++) {
let title = articles[i]["title"];
let image = articles[i]["image"];
let url = articles[i]["url"];
let desc = articles[i]["desc"];
let comment = articles[i]["comment"];
let temp_html = `<div class="card">
<img class="card-img-top"
src="${image}"
alt="Card image cap">
<div class="card-body">
<a target="_blank" href="${url}" class="card-title">${title}</a>
<p class="card-text">${desc}</p>
<p class="card-text comment">${comment}</p>
</div>
</div>`
$("#cards-box").append(temp_html);
}
}
})
}