수업 목표
- Flask 프레임워크를 활용해서 API를 만들 수 있다.
- ‘마이 페이보릿 무비스타’를 완성한다.
- EC2에 내 프로젝트를 올리고, 자랑한다!
1. 무비스타
- 좋아요 많은 순으로 영화배우의 이름, 사진, 소개url, 최근 작품 내용 게시
- 좋아요를 누르면 숫자 1 추가
- 삭제하기를 누르면 해당 영화배우 목록은 삭제
1-1 DB 만들기(데이터쌓기)
- 필요한 영화배우의 데이터를 네이버 영화 페이지에서 크롤링
1) 데이터 스크래핑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
import requests from bs4 import BeautifulSoup from pymongo import MongoClient client = MongoClient('localhost', 27017) # DB에 저장할 영화인들의 출처 url을 가져옵니다. def get_urls(): 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('https://movie.naver.com/movie/sdb/rank/rpeople.nhn', headers=headers) soup = BeautifulSoup(data.text, 'html.parser') trs = soup.select('#old_content > table > tbody > tr') urls = [] for tr in trs: a = tr.select_one('td.title > a') if a is not None: base_url = 'https://movie.naver.com/' db = client.dbsparta url = base_url + a['href'] urls.append(url) return urls # 출처 url로부터 영화인들의 사진, 이름, 최근작 정보를 가져오고 mystar 콜렉션에 저장합니다. # 'insert_all' 함수에서 같은 이름으로 사용하게 위해 url을 변수로 지정 def insert_star(url): 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') name = soup.select_one('#content > div.article > div.mv_info_area > div.mv_info.character > h3 > a').text img_url = soup.select_one('#content > div.article > div.mv_info_area > div.poster > img')['src'] recent_work = soup.select_one( '#content > div.article > div.mv_info_area > div.mv_info.character > dl > dd > a:nth-child(1)').text doc = { 'name': name, 'img_url': img_url, 'recent': recent_work, 'url': url, 'like': 0 } db.mystar.insert_one(doc) print('완료!', name) # 기존 mystar 콜렉션을 삭제하고, 출처 url들을 가져온 후, 크롤링하여 DB에 저장합니다. def insert_all(): db.mystar.drop() # mystar 콜렉션을 모두 지워줍니다. urls = get_urls() for url in urls: insert_star(url) ### 실행하기 insert_all()
2) 완성 확인하기
- mongoDB에 저장된 데이터들
1-2 GET 연습(보여주기)
1
2
3
4
5
@app.route('/api/list', methods=['GET'])
def show_stars():
sample_receive = request.args.get('sample_give')
print(sample_receive)
return jsonify({'msg': 'list 연결되었습니다!'})
- 클라이언트 코드 :
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$(document).ready(function () {
// 새로고침하고 'list 연결되었습니다!' 가 alert 창에 나오면 연결 성공
showStar();
});
function showStar() {
$.ajax({
type: 'GET',
url: '/api/list?sample_give=샘플데이터',
data: {},
success: function (response) {
alert(response['msg']);
}
});
}
2) 서버부터 만들기
1
2
3
4
5
@app.route('/api/list', methods=['GET'])
def show_stars():
stars = list(db.mystar.find({}, {'_id': False}).sort("like", -1))
# .sort() : like 값을 역순으로 정렬하라는 함수
return jsonify({'stars': stars})
3) 클라이언트 만들기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
function showStar() {
$.ajax({
type: 'GET',
url: '/api/list',
data: {},
success: function (response) {
let stars = response['stars']
for (let i = 0; i <stars.length; i++) {
let img_url = stars[i]['img_url']
let like = stars[i]['like']
let name = stars[i]['name']
let recent = stars[i]['recent']
let url = stars[i]['url']
// 배우 소개박스 코드에 DB로부터 받아온 데이터를 대입
let temp_html = `<div class="card" id="star_media">
<div class="card-content" >
<div class="media">
<div class="media-left">
<figure class="image is-48x48">
<img
src="${img_url}"
alt="Placeholder image"
/>
</figure>
</div>
<div class="media-content">
<a href="${url}" target="_blank" class="star-name title is-4">${name}(좋아요:
${like})</a>
<p class="subtitle is-6">${recent}</p>
</div>
</div>
</div>
<footer class="card-footer">
<a href="#" onclick="likeStar('${name}')" class="card-footer-item has-text-info">
위로!<span class="icon"><i class="fas fa-thumbs-up"></i></span>
</a>
<a href="#" onclick="deleteStar('${name}')" class="card-footer-item has-text-danger">
삭제<span class="icon"><i class="fas fa-ban"></i></span>
</a>
</footer>
</div>`
$('#star-box').append(temp_html)
}
}
});
}
4) 완성 확인하기
1-3 POST 연습(좋아요 +1)
- 좋아요를 누르면 좋아요 개수가 추가(DB 내 ‘Like’ +1)
1) 클라이언트와 서버 확인하기
- 서버 코드 :
app.py
1 2 3 4 5 6 7 8 9 10 11 12
@app.route('/api/like', methods=['POST']) def like_star(): name_receive = request.form['name_give'] target_star = db.mystar.find_one({'name': name_receive}) current_like = target_star['like'] new_like = current_like + 1 db.mystar.update_one({'name': name_receive}, {'$set': {'like': new_like}}) return jsonify({'msg': '좋아요 완료!'})
- 클라이언트 코드 :
index.html
1
2
3
4
5
6
7
8
9
10
11
function likeStar(name) {
$.ajax({
type: 'POST',
url: '/api/like',
data: {name_give:name},
success: function (response) {
alert(response['msg']);
window.location.reload()
}
});
}
2) 서버부터 만들기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@app.route('/api/like', methods=['POST'])
def like_star():
name_receive = request.form['name_give']
# 좋아요를 누른 영화배우를 DB에서 가져온다.
target_star = db.mystar.find_one({'name': name_receive})
# 현재 좋아요 수를 가져온다.
current_like = target_star['like']
# 현재 좋아요 수에 +1을 해준다.
new_like = current_like + 1
# 추가한 좋아요 수를 DB에 업데이트한다.
db.mystar.update_one({'name': name_receive}, {'$set': {'like': new_like}})
return jsonify({'msg': '좋아요 완료!'})
3) 클라이언트 만들기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// temp_html에 포함된 좋아요, 삭제하기 버튼 코드 , DB에서 가져온 name값을 변수로 받는다.
<footer class="card-footer">
<a href="#" onclick="likeStar('${name}')" class="card-footer-item has-text-info">위로!<span class="icon"><i class="fas fa-thumbs-up"></i></span> </a>
<a href="#" onclick="deleteStar('${name}')" class="card-footer-item has-text-danger">삭제<span class="icon"><i class="fas fa-ban"></i></span></a>
</footer>
⁞
function likeStar(name) {
$.ajax({
type: 'POST',
url: '/api/like',
// name 변수에 들어온 값을 name_give 라는 이름으로 서버에 전송 , 전송이 잘 되면(success) 서버로부터 return 값을 response 이름으로 받아와 함수 실행
data: {name_give:name},
// 서버에서 제대로 데이터를 받았다면 success 실행, 서버로부터 return 값을 response 이름으로 받아와 함수 실행
success: function (response) {
alert(response['msg']); // 메세지값 alert
window.location.reload(); // 페이지 리로드
}
});
}
4) 완성 확인하기
- 정상적으로 작동했다는 alert 메세지
- 추가된 좋아요 수와 좋아요 순으로 재정렬되는 리스트
1-4 POST 연습(삭제하기)
- 삭제하기를 누르면 해당 영화배우 데이터 전부 삭제(drop)
1) 클라이언트와 서버 확인하기
- 서버 코드 :
app.py
1 2 3 4 5
@app.route('/api/delete', methods=['POST']) def delete_star(): sample_receive = request.form['sample_give'] print(sample_receive) return jsonify({'msg': 'delete 연결되었습니다!'})
- 클라이언트 코드 :
index.html
1
2
3
4
5
6
7
8
9
10
function deleteStar(name) {
$.ajax({
type: 'POST',
url: '/api/delete',
data: {sample_give:'샘플데이터'},
success: function (response) {
alert(response['msg']);
}
});
}
2) 서버부터 만들기
1
2
3
4
5
6
7
8
@app.route('/api/delete', methods=['POST'])
def delete_star():
# 브라우저에서 보내준 데이터(post방식은 data 딕셔너리에 입력)를 받아와 변수에 담는다
name_receive = request.form['name_give']
# DB에 저장
db.mystar.delete_one({'name': name_receive})
# 위 과정이 완료되면 return값 전송
return jsonify({'msg': '삭제되었습니다!!'})
3) 클라이언트 만들기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// temp_html에 포함된 좋아요, 삭제하기 버튼 코드 , DB에서 가져온 name값을 변수로 받는다.
<footer class="card-footer">
<a href="#" onclick="likeStar('${name}')" class="card-footer-item has-text-info">위로!<span class="icon"><i class="fas fa-thumbs-up"></i></span> </a>
<a href="#" onclick="deleteStar('${name}')" class="card-footer-item has-text-danger">삭제<span class="icon"><i class="fas fa-ban"></i></span></a>
</footer>
⁞
function deleteStar(name) {
$.ajax({
type: 'POST',
url: '/api/delete',
data: {name_give:name},
success: function (response) {
alert(response['msg']);
window.location.reload()
}
});
}
4) 완성 확인하기
2. 웹 서비스 런칭
2-1 웹 서비스 런칭 기본 개념
- 웹 서비스 런칭 : 누구나 내 서비스를 이용할 수 있도록 하기 위한 작업
- 즉, 언제나 서버가 클라이언트의 요청에 응답해 줄 준비가 되어있어야 한다.
- 언제나 요청에 응답하려면, 아래 두가지 조건이 성립되어야 한다. 1) 컴퓨터가 항상 켜져있고 프로그램이 실행 2) 모두가 접근할 수 있는 공개 주소인 공개 IP 주소(Public IP Address)로 나의 웹 서비스에 접근 가능한 상태
- 우리는 AWS 라는 클라우드 서비스에서 편하게 서버를 관리하기 위해서 항상 켜 놓을 수 있는 컴퓨터인 EC2 사용권을 구입해 서버로 사용할 것이다.
2-2 웹 서비스 런칭 절차 및 세부 내용
1) AWS EC2서버 구매
- EC2서버란?
- Amazon Elastic Compute Cloud(Amazon EC2)의 약자로 Amazon Web Services(AWS) 클라우드에서 확장 가능 컴퓨팅 용량을 제공하는 것을 의미
- EC2를 구매하면 가상 컴퓨팅 기술을 통해 원격 서버를 사용할 수 있다.(구매절차 생략)
2) EC2 서버에 접속
- 접속 전, SSH(Secure Shell Protocol)란?
- 다른 컴퓨터에 접속할 때 쓰는 프로그램으로 다른 것들 보다 보안이 상대적으로 뛰어나다.
- 접속할 컴퓨터의 22번 포트가 열려있어야 접속 가능하며 AWS EC2의 경우, 이미 22번 포트를 열어놓는다.
- gitbash(Window의 경우 SSH가 없어서 이를 대체하는 프로그램)
1 2 3 4
ssh -i 받은키페어를끌어다놓기 ubuntu@AWS에적힌내아이피 예) 아래와 비슷한 생김새! ssh -i /path/my-key-pair.pem ubuntu@13.125.250.20
- 기본 리눅스 언어(일종의 마우스 역할)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
ls: 내 위치의 모든 파일을 보여준다. pwd: 내 위치(폴더의 경로)를 알려준다. mkdir: 내 위치 아래에 폴더를 하나 만든다. cd [갈 곳]: 나를 [갈 곳] 폴더로 이동시킨다. cd .. : 나를 상위 폴더로 이동시킨다. cp -r [복사할 것] [붙여넣기 할 것]: 복사 붙여넣기 rm -rf [지울 것]: 지우기 sudo [실행 할 명령어]: 명령어를 관리자 권한으로 실행한다. sudo su: 관리가 권한으로 들어간다. (나올 때는 exit으로 나옴)
3) 서버 환경 통일 (initial 파일 스크랩 하고 코드별 설명)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
# UTC to KST : 한국시간 세팅 sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime # python3 -> python : python3 명령어를 python으로 변경 sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 10 # pip3 -> pip : pip3 명령어를 pip으로 변경 sudo apt-get update sudo apt-get install -y python3-pip pip3 --version sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1 # port forwarding : http 기본 포트인 80포트로 요청이 들어오면 5000포트로 자동으로 넘겨주는 개념 # 'IP주소:5000'에서 ':5000'을 생략시키기 위한 작업 sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 5000 # MongoDB - install : MongoDB를 원격 서버에 설치 wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add - echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list sudo apt-get update sudo apt-get install -y mongodb-org sudo mkdir -p /data/db # MongoDB - run : MongoDB 실행 sudo service mongod start sleep 7 netstat -tnlp # MongoDB set user, set conf file : mongoDB 접속 계정 생성하기 # admin으로 계정 변경 및 계정 생성(ID,PW : test)하기 mongo admin --eval 'db.createUser({user: "test", pwd: "test", roles:["root"]});' sudo sh -c 'echo "security:\n authorization: enabled" >> /etc/mongod.conf' sudo sed -i "s,\\(^[[:blank:]]*bindIp:\\) .*,\\1 0.0.0.0," /etc/mongod.conf sudo service mongod stop sudo service mongod start sleep 5 netstat -tnlp # flask 패키지 설치 : app.py 실행을 위해 필수적 pip install flask
4) AWS에서 포트 열여주기
- EC2 서버(=가상의 내 컴퓨터)에서 포트를 따로 설정하는 것 외에도, AWS EC2에서도 자체적으로 포트를 열고/닫을 수 있게 관리를 할 수 있다. → 그래서 AWS EC2 Security Group에서 인바운드 요청 포트를 열어줘야 서버로 접속이 가능하다.
EC2 Security Group 에서 아래 3개의 포트 추가
- 80포트(기본 http 포트)
- 5000포트(flask 기본포트)
- 27017포트(외부에서 mongoDB 접속을 하기 위한 포트)
5) 원페이지 쇼핑몰 업로드하기
- mongoDB 명령어 수정
1 2 3 4 5 6
# 기존 명령어 : localhost로 접속 client = MongoClient('localhost', 27017) # 수정한 명령어 : 원격 서버로 접속 # 아이디 : test , 비밀번호 : test client = MongoClient('mongodb://아이디:비밀번호@localhost', 27017)
- pymongo 패키지 설치
1 2
# 설치하기 pip install pymongo
app.py
실행1
python app.py
- 브라우저에서 접속
1
http://내AWS아이피:5000/
6) nohup 설정
내가 SSH 접속을 끊었을 때 다른 사람이 내가 만든 사이트에 접속할 수 없다면 제대로 된 웹 서비스 런칭이라 볼 수 없다. 이를 해결하기 위한 방법이 nohup 설정을 하는 것이다.
- nohup 설정 명령어
- 원격 접속을 종료하더라도 서버가 계속 돌아가게 하기
1 2
# 아래의 명령어로 실행하면 된다 nohup python app.py &
- 서버 종료하기 - 강제종료하는 방법
1 2 3 4 5 6
# 아래 명령어로 미리 pid 값(프로세스 번호)을 본다 ps -ef | grep 'app.py' # 아래 명령어로 특정 프로세스를 죽인다 # pid값 : 5자리 숫자조합 중 앞에 두가지 값 kill -9 [pid값]
- 다시 켜기
1
nohup python app.py &
- 원격 접속을 종료하더라도 서버가 계속 돌아가게 하기
7) 도메인 구입(가비아)
- IP 주소
- 컴퓨터가 통신할 수 있도록 컴퓨터마다 가지는 숫자로 구성된 고유한 주소
- 가비아에서 구입한 url을 EC2서버 IP와 연결하면 완료!!
8) og 태그 설정
- 프로젝트를 sns에 공유했을 때 나오는 간략한 설명 혹은 이미지를 og태그라고 한다.
- og태그 설정 방법
1 2 3 4 5
// head 태그 안에 아래 태그를 추가, content 값을 원하는 대로 수정 // img 파일은 static 폴더 안에 저장(800X400 사이즈) <meta property="og:title" content="나만의 쇼핑몰" /> <meta property="og:description" content="맛있는 사과사세요~~🍎" /> <meta property="og:image" content="" />
- 카카오톡으로 공유한 프로젝트 모습
3. 최종 프로젝트 완성본
링크 : http://kimcno3.shop/