[스파르타코딩클럽] 웹개발 종합반 - 3주 차
복습 - OpenAPI 붙여보기
전에 했던 '내 생애 최고의 영화들'에서 OpenAPI를 이용해서 영화이미지, 제목 등등이 나열되게 해본다.
fetch("http://spartacodingclub.shop/web/api/movie")
.then(response => response.json())
.then(data => {
console.log(data['movies'])
})
영화 데이터를 콘솔에 찍어본다.
fetch("http://spartacodingclub.shop/web/api/movie")
.then(response => response.json())
.then(data => {
let rows = data['movies']
rows.forEach((a) => {
console.log(a)
})
})
movies를 forEach문으로 반복을 돌면서, 하나씩 출력해준다.
fetch("http://spartacodingclub.shop/web/api/movie")
.then(response => response.json())
.then(data => {
// console.log(data)
let rows = data['movies']
rows.forEach(a => {
//console.log(movie)
let title = a['title']
let desc = a['desc']
let comment = a['comment']
let star = a['star']
let image = a['image']
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}</p>
<p class="mycomment">${comment}</p>
</div>
</div>
</div>`
$('#cards-box').append(temp_html)
})
})
movie 내용을 (image, comment, title, desc, star) 가지고 HTML을 만들어 붙인다.
let star_image = '⭐'.repeat(star)
별을 반복한 값을 repeat()를 사용해 변수로 담아 붙여준다.
$('#cards').empty()
먼저 있던 영화를 지운다.
<!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>practice</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap');
* {
font-family: 'Gowun Dodum', sans-serif;
}
.mytitle {
background-color: aqua;
color: white;
height: 250px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
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;
}
.mytitle>button {
color: white;
width: 250px;
height: 50px;
background-color: transparent;
border: 1px solid white;
border-radius: 50px;
margin: 30px;
}
.mytitle>button:hover {
border: 2px solid white;
}
.mycomment {
color: gray;
}
.mycard {
width: 1200px;
margin: 20px auto 20px auto;
}
.mypost {
width: 500px;
margin: 20px auto 20px auto;
padding: 20px 20px 20px 20px;
box-shadow: 0px 0px 3px 0px gray;
}
.mybtn {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-top: 20px;
}
.mybtn>button {
margin-right: 10px;
}
</style>
<script>
$(document).ready(function () {
fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then(res => res.json()).then(data => {
let on = data['temp']
$('#temp').text(on)
})
fetch("http://spartacodingclub.shop/web/api/movie").then(res => res.json()).then(data => {
let rows = data['movies']
$('#cards').empty()
rows.forEach((a) => {
let title = a['title']
let desc = a['desc']
let comment = a['comment']
let star = a['star']
let image = a['image']
let star_image ='⭐'.repeat(star)
let temp_html = `<div class="col">
<div class="card">
<img src="${image}"
class="card-img-top" alt="...">
<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').append(temp_html)
})
})
})
</script>
</head>
<body>
<div class="mytitle">
<h1>내 생애 최고의 영화들</h1>
<div>현재 서울의 날씨 : <span id="temp">20</span>도</div>
<button onclick="hey()">영화 기록하기</button>
</div>
<div class="mypost">
<div class="form-floating mb-3">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
<label for="floatingInput">영화 URL</label>
</div>
<div class="input-group mb-3">
<label class="input-group-text" for="inputGroupSelect01">별점</label>
<select class="form-select" id="inputGroupSelect01">
<option selected>-- 선택하기 --</option>
<option value="1">⭐</option>
<option value="2">⭐⭐</option>
<option value="3">⭐⭐⭐</option>
</select>
</div>
<div class="form-floating">
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea"></textarea>
<label for="floatingTextarea">코멘트</label>
</div>
<div class="mybtn">
<button type="button" class="btn btn-dark">기록하기</button>
<button type="button" class="btn btn-outline-dark">닫기</button>
</div>
</div>
<div class="mycard">
<div id="cards" class="row row-cols-1 row-cols-md-4 g-4">
<div class="col">
<div class="card">
<img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
class="card-img-top" alt="...">
<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">
<img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
class="card-img-top" alt="...">
<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">
<img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
class="card-img-top" alt="...">
<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">
<img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
class="card-img-top" alt="...">
<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>
PYTHON
파이썬을 설치한다는 것은 일종의 번역팩을 설치한다는 것이다.
컴퓨터는 101010110101같은 언어만 알아듣기 때문에
파이썬 문법으로 된 것을 101001로 변환해줄 수 있도록, 번역 패키지를 설치하는 것이다.
터미널
사용자가 텍스트로 명령어를 입력하면, 결과를 텍스트로 화면에 출력해주는 도구이다.
파이썬 라이브러리를 설치하고, 파이썬 프로젝트를 실행하는데 사용한다.
명령어를 적어 작동시키는 것이 빠르고 편리하기 때문에 사용한다.
print('hi')
기초문법
변수, 기본연산
a = 3
3을 a에 넣는다.
숫자, 문자형
name = 'bob'
num = 12
변수에는 문자열, 숫자가 들어갈 수 있다.
is_number = True
True 또는 False -> "Boolean"형이 들어갈 수도 있다.
또, Javascript의 배열형과 동일한 리스트형, Dictionary 형도 들어갈 수 있다.
a=['사과','배','감']
a= {'name':'영수','age':24}
함수
함수의 정의 - 이름은 마음대로 정할 수 있다.
수학문제에서
y = f(x) = 2x+3 에서 x가 2일때
y의 값은 7이다.
def f(x):
return 2*x+3
y = f(2)
자바스크립트에서는 함수를 선언할 때 function을 사용하지만 파이썬에서는 def를 통해 함수를 선언한다.
위 수학문제를 파이썬을 통해서 나타낸 것이다.
(파이썬에서는 ' : '과 줄맞춤으로 함수의 내용물을 판단함)
함수를 응용해보면
def sum(a,b,c):
return a+b+c
result = sum(1,2,3)
이렇게 하고 print(result)했을 때 sum함수를 부르면 1,2,3이 들어가서 return된 result값이 1+2+3인 6이 출력된다.
조건문
age = 25
if age > 20:
print("성인입니다")
else:
print("청소년입니다")
반복문
fruits = ['사과','배','감','귤']
for fruit in fruits:
print(fruit)
파이썬에서의 반복문은, 리스트의 요소들을 하나씩 꺼내쓰는 형태이다.
따라서 무조건 리스트와 함께 쓰인다.
가상환경(virtual environment)은 같은 시스템에서 실행되는 다른 파이썬 응용 프로그램들의 동작에
영향을 주지 않기 위해, 파이썬 배포 패키지들을 설치하거나 업그레이드하는 것을 가능하게 하는 격리된 실행 환경이다.
Requests 라이브러리 사용해보기
Requests 라이브러리를 설치하고
import requests
r = requests.get('http://spartacodingclub.shop/sparta_api/seoulair')
rjson = r.json()
rows = rjson['RealtimeCityAir']['row']
for a in rows:
gu_name = a['MSRSTE_NM']
gu_mise = a₩['IDEX_MVL']
print(gu_name, gu_mise)
위처럼 서울시 대기 OpenAPI에서, 중구의 미세먼지 값을 가져와 보았다.
크롤링
import requests
from bs4 import BeautifulSoup
# 타겟 URL을 읽어서 HTML를 받아오고,
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/rmovie.naver?sel=pnt&date=20210829',headers=headers)
# HTML을 BeautifulSoup이라는 라이브러리를 활용해 검색하기 용이한 상태로 만듦
# soup이라는 변수에 "파싱 용이해진 html"이 담긴 상태가 됨
# 이제 코딩을 통해 필요한 부분을 추출하면 된다.
soup = BeautifulSoup(data.text, 'html.parser')
크롤링 기본 세팅이다.
항상 정확하지는 않으나, 크롬 개발자도구를 참고할 수도 있다.
1. 원하는 부분에서 마우스 오른쪽 클릭 → 검사
2. 원하는 태그에서 마우스 오른쪽 클릭
3. Copy → Copy selector로 선택자를 복사할 수 있음
a = soup.select_one('#old_content > table > tbody > tr:nth-child(3) > td.title > div > a')
trs = soup.select('#old_content > table > tbody > tr')
select를 이용해서, tr들을 불러오고,
for tr in trs:
a = tr.select_one('td.title > div > a')
if a is not None:
print(a.text)
반복문을 써서 불러온 tr들을 출력한다.
(a태그가 없으면 출력하지 않는다.)
beautifulsoup 내 select에 미리 정의된 다른 방법
# 선택자를 사용하는 방법 (copy selector)
soup.select('태그명')
soup.select('.클래스명')
soup.select('#아이디명')
soup.select('상위태그명 > 하위태그명 > 하위태그명')
soup.select('상위태그명.클래스명 > 하위태그명.클래스명')
# 태그와 속성값으로 찾는 방법
soup.select('태그명[속성="값"]')
# 한 개만 가져오고 싶은 경우
soup.select_one('위와 동일')
크롤링 연습
import requests
from bs4 import BeautifulSoup
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/rmovie.naver?sel=pnt&date=20210829',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')
trs = soup.select('#old_content > table > tbody > tr')
for tr in trs:
a = tr.select_one('td.title > div > a')
if a is not None:
title = a.text
rank = tr.select_one('td:nth-child(1) > img')['alt']
star = tr.select_one('td.point').text
print(rank,title,star)
위와 같은 방법으로 순위와 별점을 가져왔다.
Database
DB에는 Index 라는 순서로 데이터들이 정렬되어 있다.
크게 두 가지 종류
SQL - 행/열의 생김새가 정해진 엑셀에 데이터를 저장하는 것과 유사합니다. 데이터 50만 개가 적재된 상태에서, 갑자기 중간에 열을 하나 더하기는 어려울 것입니다. 그러나, 정형화되어 있는 만큼, 데이터의 일관성이나 / 분석에 용이할 수 있습니다. ex) MS-SQL, My-SQL 등
No-SQL - 딕셔너리 형태로 데이터를 저장해두는 DB입니다. 고로 데이터 하나 하나 마다 같은 값들을 가질 필요가 없게 됩니다. 자유로 운 형태의 데이터 적재에 유리한 대신, 일관성이 부족할 수 있습니다. ex) MongoDB
DB의 실체는 특별한 컴퓨터 같은 것이 아닌 프로그램과 같은 것이다.
즉, 내 컴퓨터에 게임도 설치하고, PPT도 설치하고, DB도 설치할 수 있는 것이다.
그런데, 이 마저도 요새는 Cloud 형태로 제공해주는 곳들이 많다.
유저가 몰리거나 / DB를 백업해야 하거나 / 모니터링 하기가 아주 용이하기 때문이다.
요새 트렌드는 클라우드라고 한다.
mongo DB 써보기
pymongo, dnspython을 설치한다.
from pymongo import MongoClient
client = MongoClient('여기에 URL 입력')
db = client.dbsparta
pymongo 기본 코드이다.
# 저장 - 예시
doc = {'name':'bobby','age':21}
db.users.insert_one(doc)
# 한 개 찾기 - 예시
user = db.users.find_one({'name':'bobby'})
# 여러개 찾기 - 예시 ( _id 값은 제외하고 출력)
all_users = list(db.users.find({},{'_id':False}))
# 바꾸기 - 예시
db.users.update_one({'name':'bobby'},{'$set':{'age':19}})
# 지우기 - 예시
db.users.delete_one({'name':'bobby'})
pymongo 코드 요약
저장하고, 찾고, 바꾸고, 지우고, 이렇게 네가지 기능.
from pymongo import MongoClient
client = MongoClient('mongodb+srv://sparta:test@cluster0.x2ustyq.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta
import requests
from bs4 import BeautifulSoup
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/rmovie.naver?sel=pnt&date=20210829',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')
trs = soup.select('#old_content > table > tbody > tr')
for tr in trs:
a = tr.select_one('td.title > div > a')
if a is not None:
title = a.text
rank = tr.select_one('td:nth-child(1) > img')['alt']
star = tr.select_one('td.point').text
doc = {'rank':rank
,'title':title
,'star':star}
db.movies.insert_one(doc)
위에서 했던 웹 스크래핑 결과를 DB에 저장해보았다.
웹스크래핑 결과 이용해보기
movie = db.movies.find_one({'title':'가버나움'})
print(movie['star'])
영화제목 '가버나움'의 평점을 가져오는 코드이다.
movie = db.movies.find_one({'title':'가버나움'})
target_star = movie['star']
movies = list(db.movies.find({'star':target_star}))
for a in movies:
print(a['title'])
'가버나움'의 평점과 같은 평점의 영화 제목들을 가져오는 코드이다.
db.movies.update_one({'title':'가버나움'},{'$set':{'star':'0'}})
'가버나움' 영화의 평점을 0으로 만드는 코드이다.
오늘 말로만 들어봤던 파이썬을 다뤄봤는데, 나름 재미있었다.
오늘 항해 99가 4월달로 미뤄진다는 소식을 들었다.
그럼 7월달에 끝나는 건데, 생각해보니까 나 7월달에 신검을 신청해놨다.
21일이라 별로 지장이 없긴 한데.. 군대가기 싫다.