fetch 문은 기존 코드와 똑같이 복사해준 뒤 url만 영화 API로 바꿔준다
fetch("http://spartacodingclub.shop/web/api/movie").then(res => res.json()).then(data => {
})
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">${comment}</p>
<p>${star_image}</p>
<p class="mycomment">${desc}</p>
</div>
</div>
</div>`
$('#cards').append(temp_html)
별 이모티콘 붙이는 방법
star에 별의 개수를 넣어준 뒤 star_image 에 별 이모지 ->⭐ 를 넣어준다.
repeat 함수를 통해 이모지를 반복해서 넣어준다
let star = a['star']
let star_image = '⭐'.repeat(star)
코드 전문
<!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>
<style>
@import url('https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap');
* {
font-family: 'Gowun Dodum', sans-serif;
}
.mytitle {
background-color: green;
color: white;
height: 250px;
/* 내용물 세로로 정렬, 가로는 column 대신 row */
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 지정 */
.mytitle>button {
width: 250px;
height: 50px;
/* 버튼은 투명, 글자색 흰색, 테두리선은 실선이며 흰색 */
background-color: transparent;
color: white;
border: 1px solid white;
border-radius: 50px;
margin-top: 20px;
}
/* 버튼을 누를 시 선이 굵어지게 */
.mytitle>button:hover {
border: 2px solid white;
}
.mycomment {
color: gray;
}
.mycards {
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: 20px;
}
</style>
<script>
//api fetch
$(document).ready(function () {
fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then(res => res.json()).then(data => {
//data 의 temp 에 실시간 기온 정보가 있음
let temp_now = data['temp']
//id = "temp" 인 곳에 붙이기
$('#temp').text(temp_now)
})
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 image = a['image']
let star = a['star']
let comment = a['comment']
//star 이미지로 붙이기
let star_image = '⭐'.repeat(star)
//id 아래에 붙여야 하로 <div class = "col"> 부터
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">${comment}</p>
<p>${star_image}</p>
<p class="mycomment">${desc}</p>
</div>
</div>
</div>`
$('#cards').append(temp_html)
})
})
})
</script>
</head>
<body>
<div class="mytitle">
<h1>내 생에 최고의 영화들</h1>
<div>현재 서울의 날씨 : <span id="temp"></span>도</div>
<button>영화 기록하기</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="mycards">
<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>
profile
결과
venv 이용하여 가상환경 만들기
윈도우 : Vscode 의 터미널에 python -m venv venv 입력
맥 : python3 -m venv venv
-> venv가 자동으로 만들어지는 것을 볼 수 있음
-> 라이브러리를 담아둘 폴더
이후 인터프리터 설정에서 venv를 선택한 뒤 new terminal을 누르면 (venv)가 뜬 터미널이 나오는 것을 볼 수 있다.
다음으로 라이브러리 이름을 하나 써준다
pip3 install requests
requests 사용 예시
import requests;
r = requests.get('http://spartacodingclub.shop/sparta_api/seoulair')
rjson = r.json()
print(rjson)
사전 준비
pip3 install bs4
기본 세팅
import requests
from bs4 import BeautifulSoup
URL = "https://movie.daum.net/ranking/reservation"
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을 통해 사이트에 들어간 뒤 개발자 도구의 elements 에서 제목 부분 copy > copy selector
bs4의 select_one() 함수에 복사해준 selector을 붙여넣어준 뒤 print 해보면 아래와 같은 결과가 나온다.
코드
import requests
from bs4 import BeautifulSoup
URL = "https://movie.daum.net/ranking/reservation"
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')
##<li></li> 태그의 2번째 라는 의미
title = soup.select_one('#mainContent > div > div.box_ranking > ol > li:nth-child(2) > div > div.thumb_cont > strong > a')
print(title.text)
결과
<a class="link_txt" data-tiara-layer="moviename" href="/moviedb/main?movieId=163777">엘리멘탈</a>
html 부분이 그대로 나온다.<li>
태그가 붙어있는 모든 영화 제목을 가져와야 하므로 html에서 li 다음은 지워준다.
영화 제목을 검사해보면
<a href="/moviedb/main?movieId=147080" class="link_txt" data-tiara-layer="moviename">밀수</a>
이것으로, class가 "link_txt" 인 것을 알 수 있다.
-> select_one() 안에 파라미터로 '.link_txt'를 넣어준 다음 반복문을 이용해 하나씩 출력해준다.
lis = soup.select('#mainContent > div > div.box_ranking > ol > li')
for li in lis :
title = li.select_one('.link_txt')
print(title.text)
순위와 평점의 html 태그
<span class="rank_num">1</span>
<span class="txt_grade">7.5</span>
class 를 알았으므로 위와 같은 방식으로 내용물만 바꿔서 해주면 된다
import requests
from bs4 import BeautifulSoup
URL = "https://movie.daum.net/ranking/reservation"
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')
##li 태그의 2번째 라는 의미
lis = soup.select('#mainContent > div > div.box_ranking > ol > li')
for li in lis :
title = li.select_one('.link_txt').text
rank = li.select_one('.rank_num').text
score = li.select_one('.txt_grade').text
print(rank, title, score)
데이터베이스를 이용하는 목적은 잘 저장하기 위함이 아니라, 잘 가져오기 위해서이다.
데이터베이스의 종류
정형화된 틀이 있다. 엑셀에 데이터를 넣는 것과 유사하다.
정형화되어 있기 때문에 중간에 수정/삽입/삭제하는 작업이 빈번한 데이터에는 적합하지 않지만, 일관적인 데이터를 분석하는 작업을 할 때에는 유리하다.
틀이 정해져있기 때문에 사람의 실수를 줄여주기 때문에 주로 대기업에서 사용한다.
ex) MYSQL 등
sql이 아니라는 뜻이 아니라, Not only SQL 이라는 뜻이다. SQL 형태의 데이터와 반대로 형태와 틀이 자유로워 데이터 적재에 유리하지만, 일관적인 데이터를 다룰 때에는 비효율적일 수 있다.
데이터의 유연성이 장점이기 때문에 아직 확실하지 않은 스타트업에서 많이 사용한다.
ex) MongoDB 등
최근의 데이터베이스는 컴퓨터가 아니라 클라우드 환경에 저장해놓는 경우가 많다.
mongoDB에 가입한 후 IP주소를 입력한 다음 데이터베이스에 접속해준다.
mongoDB를 파이썬으로 조작하기 위해서는 특정 라이브러리 - pymongo, dnspython - 가 필요하다.
pip3 install pymongo
pip3 install dnspython
pymongo 기본 조작 코드
from pymongo import MongoClient
client = MongoClient('여기에 URL 입력')
db = client.dbsparta
<password>
부분 비밀번호로 바꾸기insert_one 함수를 통해 연결된 데이터베이스에 데이터를 삽입해준다.
doc = {
'name':'bob',
'age':27
}
db.users.insert_one(doc)
pip3 install certifi
certifi 패키지 먼저 설치해주기
import certifi
ca = certifi.where()
추가해주고
client = MongoClient('url 부분', tlsCAFile=ca)
url 뒤에 tlsCAFile=ca 추가
코드 전문
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://sparta:test@cluster0.eh7wfh6.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta
doc = {
'name':'bob',
'age':27
}
db.users.insert_one(doc)
Cluster0 > Collections에서 데이터가 정상적으로 삽입된 것을 확인할 수 있다.
all_users = list(db.users.find({},{'_id':False}))
#제대로 가져왔는지 확인
for a in all_users:
print(a)
users라는 db에서 가져온 데이터를 list 형태로 만들어서 출력하는 코드이다.
결과
결과값 하나만 가져오고 싶을 경우 .find_one()을 사용한다
user = db.users.find_one({'name':'bob'},{'_id':False})
print(user)
db.users.update_one({'name':'bob'},{'$set':{'age':19}})
name이 bob인 데이터를 찾아 age를 19로 바꾸라는 명령어
mongoDB에서 refresh를 해주면 값이 제대로 바뀐 것을 확인할 수 있다.
db.users.delete_one({'name':'bob'})
name이 bob인 데이터를 찾아 제거하는 명령어
from pymongo import MongoClient
import requests
from bs4 import BeautifulSoup
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://sparta:test@cluster0.eh7wfh6.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta
URL = "https://movie.daum.net/ranking/boxoffice/yearly?date=2010"
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')
lis = soup.select(".list_movieranking > li")
for li in lis:
rank = li.select_one(".rank_num").text
age = li.select_one(".ico_see").text
title = li.select_one(".link_txt").text
print(rank, title, age)
doc = {
'rank': rank,
'title': title,
'age': age
}
db.movies2.insert_one(doc)
에러 - TypeError("index %r cannot be applied to Cursor instances" % index)
TypeError: index 'title' cannot be applied to Cursor instances
res = db.movie2.find({'age':age},{'_id':False})
print(m['title'])
처음에 데이터가 잘 나오는지 보려고 이렇게 쳤는데, typeError가 났다.
알아보니 find로 데이터를 받을 때에는 cursor 라는 객체로 '현재 검색하는 데이터의 위치' 까지 포함한 데이터를 반환하는데, 딕셔너리 형태로 정보를 찾으려할 때에는 이 cursor 을 사용할 수 없어서 나는 에러 같다.
그 뒤로도 몇 번 None 이 반환되는 에러가 있었는데, db 이름에 오타가 났기 때문이였다. 정신 차리고 살아야겠다.
답
from pymongo import MongoClient
import requests
from bs4 import BeautifulSoup
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://sparta:test@cluster0.eh7wfh6.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta
URL = "https://movie.daum.net/ranking/boxoffice/yearly?date=2010"
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')
movie = db.movies2.find_one({'title':"하모니"})
age = movie['age']
res = db.movies2.find({'age':age},{'_id':False})
for m in res :
print(m['title'])
from pymongo import MongoClient
import requests
from bs4 import BeautifulSoup
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://sparta:test@cluster0.eh7wfh6.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta
URL = "https://movie.daum.net/ranking/boxoffice/yearly?date=2010"
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')
db.movies2.update_one({'title':'부당거래'},{'$set':{'age':"18세이상관람가"}})
지니뮤직의 1~50위 곡을 스크래핑 해보세요.
에러 - 결과가 제대로 나오지 않음
Object...이렇게 한 줄만 뜨고 그 이상 뜨지 않아서 코드를 살펴본 결과
lis = soup.select('#body-content > div.newest-list > div > table > tbody')
에 문제가 있었다.
추출한 html selector 코드가
#body-content > div.newest-list > div > table > tbody > tr:nth-child(1) > td.info > a.title.ellipsis
였는데, 여기서 :nth-child(1) 에 더해서 tr까지 지워버려 제대로 스크래핑이 안 됐다.
lis = soup.select('#body-content > div.newest-list > div > table > tbody > tr')
로 고쳐주었다.
에러 - AttributeError: 'NoneType' object has no attribute '.text'
title = li.select_one('.title ellipsis').text
rank = li.select_one('.number').text
artist = li.select_one('.artist ellipsis').text
받아온 데이터에 text 타입이 없다는 말이다. 검사를 통해 분명 class="title ellipsis"인 것을 확인했는데 text를 없애고 출력해봐도 계속 none 이 나왔다.
해결 - title ellipsis가 아니라 title.ellipsis였다. 마우스를 가져다 대보면
이렇게 나오는 것을 확인할 수 있다.
title = li.select_one('.title.ellipsis').text
rank = li.select_one('.number').text
artist = li.select_one('.artist.ellipsis').text
로 바꿔보니 제목이 제대로 나오는 것을 확인할 수 있었다.
<td class="number">
2
<span class="rank">
<span class="rank">
<span class="rank-down">
1
<span class="hide">하강</span>
</span>
</span>
</span>
</td>
.text
에 '2 1 하강' 이 모두 포함되기 때문이다. text[0:2]
로 앞 두글자만 잘라서 출력해주자.
title = li.select_one('.title.ellipsis').text.strip()
strip()
을 이용해서 여백을 잘라준다.
문자열 공백 없애기에 대한 자세한 정보는
https://seong6496.tistory.com/360
코드 전문
import requests
from bs4 import BeautifulSoup
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://sparta:test@cluster0.eh7wfh6.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta
URL = "https://www.genie.co.kr/chart/top200?ditc=M&rtm=N&ymd=20230101"
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')
##li 태그의 2번째 라는 의미
lis = soup.select('#body-content > div.newest-list > div > table > tbody > tr')
for li in lis :
title = li.select_one('.title.ellipsis').text.strip()
rank = li.select_one('.number').text[0:2]
artist = li.select_one('.artist.ellipsis').text
print(rank,title,artist)
결과