*/스파르타코딩클럽 웹개발종합반
[스파르타코딩클럽 | 웹개발종합반] 3주차: Python, 크롤링, mongoDB
sssbin
2021. 9. 13. 00:29
1. 복습: 나홀로메모장에 OpenAPI 붙여보기
- 로딩 후 바로 실행
$(document).ready(function(){
listing();
});
function listing() {
console.log('화면 로딩 후 잘 실행되었습니다');
}
- html 붙이기
let temp_html=`<div class="card">
<img class="card-img-top" src="${image}" alt="Card image cap">
<div class="card-body">
<a class="card-title" href="${url}"> ${title} </a>
<p class="card-text"> ${desc} </p>
<p class="card-text comment"> ${comment} </p>
</div>
</div>`
$('#cards-box').append(temp_html)
// ${ }
// 링크는 "${ }"
// $('# ')
- 완성
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
<title>스파르타코딩클럽 | 부트스트랩 연습하기</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Stylish&display=swap" rel="stylesheet">
<style>
* {
font-family: 'Stylish', sans-serif;
}
.wrap {
width : 880px;
margin : auto;
}
.comment {
color : blue;
font-weight : bold;
}
.posting-box {
width : 500px;
margin : 0px auto 20px auto;
padding : 50px;
border : 2px solid black;
border-radius : 5px;
display : none;
}
</style>
<script>
$(document).ready(function () {
$('#cards-box').empty();
listing();
});
function listing() {
$.ajax({
type: "GET",
url: "http://spartacodingclub.shop/post",
data: {},
success: function (response) {
let rows = response['articles']
for (let i=0; i<rows.length; i++) {
let comment = rows[i]['comment']
let desc = rows[i]['desc']
let image = rows[i]['image']
let title = rows[i]['title']
let url = rows[i]['url']
let temp_html=`<div class="card">
<img class="card-img-top" src="${image}" alt="Card image cap">
<div class="card-body">
<a class="card-title" href="${url}"> ${title} </a>
<p class="card-text"> ${desc} </p>
<p class="card-text comment"> ${comment} </p>
</div>
</div>`
$('#cards-box').append(temp_html)
}
}
})
}
function openclose() {
let status = $('#post-box').css('display');
if (status == 'block') {
$('#post-box').hide();
$('#btn-posting-box').text('포스팅 박스 열기');
}
else {
$('#post-box').show();
$('#btn-posting-box').text('포스팅 박스 닫기');
}
}
</script>
</head>
<body>
<div class="wrap">
<div class="jumbotron">
<h1 class="display-4">나홀로 링크 메모장!</h1>
<p class="lead"> 중요한 링크를 저장해두고, 나중에 볼 수 있는 공간입니다 </p>
<hr class="my-4">
<p class="lead">
<a onclick="openclose()" id="btn-posting-box" class="btn btn-primary btn-lg" href="#" role="button">포스팅 박스 열기</a>
</p>
</div>
<div class="posting-box" id="post-box">
<div class="form-group">
<label> 아티클 URL </label>
<input type="email" class="form-control" id="article-url" aria-describedby="emailHelp">
<small id="emailHelp" class="form-text text-muted"> </small>
</div>
<div class="form-group">
<label for="exampleInputPassword1">간단 코멘트</label>
<textarea class="form-control" id="exampleInputPassword1" rows="3"> </textarea>
</div>
<button type="submit" class="btn btn-primary">기사저장</button>
</div>
<div class="card-columns" id="cards-box">
<div class="card">
<img class="card-img-top" src=https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg alt="Card image cap">
<div class="card-body">
<a class="card-title" href="http://naver.com/"> 여기 기사 제목이 들어가죠 </a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment"> 여기에 코멘트가 들어갑니다. </p>
</div>
</div>
<div class="card">
<img class="card-img-top" src=https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg alt="Card image cap">
<div class="card-body">
<a class="card-title" href="http://naver.com/"> 여기 기사 제목이 들어가죠 </a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment"> 여기에 코멘트가 들어갑니다. </p>
</div>
</div>
<div class="card">
<img class="card-img-top" src=https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg alt="Card image cap">
<div class="card-body">
<a class="card-title" href="http://naver.com/"> 여기 기사 제목이 들어가죠 </a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment"> 여기에 코멘트가 들어갑니다. </p>
</div>
</div>
<div class="card">
<img class="card-img-top" src=https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg alt="Card image cap">
<div class="card-body">
<a class="card-title" href="http://naver.com/"> 여기 기사 제목이 들어가죠 </a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment"> 여기에 코멘트가 들어갑니다. </p>
</div>
</div>
<div class="card">
<img class="card-img-top" src=https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg alt="Card image cap">
<div class="card-body">
<a class="card-title" href="http://naver.com/"> 여기 기사 제목이 들어가죠 </a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment"> 여기에 코멘트가 들어갑니다. </p>
</div>
</div>
<div class="card">
<img class="card-img-top" src=https://www.eurail.com/content/dam/images/eurail/Italy%20OCP%20Promo%20Block.adaptive.767.1535627244182.jpg alt="Card image cap">
<div class="card-body">
<a class="card-title" href="http://naver.com/"> 여기 기사 제목이 들어가죠 </a>
<p class="card-text">기사의 요약 내용이 들어갑니다. 동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라만세 무궁화 삼천리 화려강산...</p>
<p class="card-text comment"> 여기에 코멘트가 들어갑니다. </p>
</div>
</div>
</div>
</div>
</body>
</html>
2. Python
- 리스트
a_list = []
a_list.append(1) # a_list[0] = 1
a_list.append([2,3]) # a_list[1] = [2,3]
# a_list[1][0] = 2
- 딕셔너리
a_dict = {}
a_dict = {'name':'bob', 'age':21}
a_dict['height'] = 178 # a_dict = {'name':'bob', 'age':21, 'height':178}
- 함수
def sum(num1, num2) :
return num1+num2
result = sum(1,2)
print(result) # 3 출력
# 조건문
def is_adult(age):
if age > 20:
print('성인입니다') # 조건이 참이면 '성인입니다' 출력
else:
print('청소년이에요') # 조건이 거짓이면 '청소년이에요' 출력
is_adult(30) # '성인입니다' 출력
# 반복문: 리스트의 요소들을 하나씩 꺼내쓰는 형태
fruits = ['사과','배','배','감','수박','귤','딸기','사과','배','수박']
count = 0
for fruit in fruits:
if fruit == '사과':
count += 1
print(count) # 2 출력 (사과의 개수)
- requests 패키지 써보기
import requests # requests 라이브러리 설치 필요
r = requests.get('http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99')
rjson = r.json()
gus = rjson['RealtimeCityAir']['row']
for gu in gus:
gu_name = gu['MSRSTE_NM']
gu_mise = gu['IDEX_MVL']
if (gu_mise > 50) :
print(gu_name, gu_mise)
3. mongoDB
✔️ pymongo
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbspart
✔️ 코드 요약
# 저장 - 예시
doc = {'name':'bobby','age':21}
db.users.insert_one(doc)
# 한 개 찾기 - 예시
user = db.users.find_one({'name':'bobby'})
# 여러개 찾기 - 예시 ( _id 값은 제외하고 출력)
same_ages = list(db.users.find({'age':21},{'_id':False}))
# 바꾸기 - 예시
db.users.update_one({'name':'bobby'},{'$set':{'age':19}})
# 지우기 - 예시
db.users.delete_one({'name':'bobby'})
4. 크롤링
- requests로 요청하고 BeautifulSoup으로 솎아낸다 !
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.nhn?sel=pnt&date=20200303',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')
- select_one / select
# 선택자를 사용하는 방법 (copy selector)
soup.select('태그명')
soup.select('.클래스명')
soup.select('#아이디명')
soup.select('상위태그명 > 하위태그명 > 하위태그명')
soup.select('상위태그명.클래스명 > 하위태그명.클래스명')
# 태그와 속성값으로 찾는 방법
soup.select('태그명[속성="값"]')
# 한 개만 가져오고 싶은 경우
soup.select_one('위와 동일')
▶ 웹 크롤링 연습 (영화 순위, 제목, 평점 출력)
✔️ https://movie.naver.com/movie/sdb/rank/rmovie.naver?sel=pnt&date=20200303
✔️ 오른쪽 마우스 → copy → copy selector
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.nhn?sel=pnt&date=20200303',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')
trs = soup.select('#old_content > table > tbody > tr')
#old_content > table > tbody > tr:nth-child(2) > td:nth-child(1) > img
#old_content > table > tbody > tr:nth-child(2) > td.title > div > a
#old_content > table > tbody > tr:nth-child(2) > td.point
for tr in trs:
a_tag = tr.select_one('td.title > div > a')
if a_tag is not None:
rank = tr.select_one('td:nth-child(1) > img')['alt']
title = a_tag['title']
score = tr.select_one('td.point').text
print(rank, title, score)
▶ 웹 크롤링 결과 저장하기
import requests
from bs4 import BeautifulSoup
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbsparta
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.nhn?sel=pnt&date=20200303',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')
trs = soup.select('#old_content > table > tbody > tr')
#old_content > table > tbody > tr:nth-child(2) > td:nth-child(1) > img
#old_content > table > tbody > tr:nth-child(2) > td.title > div > a
#old_content > table > tbody > tr:nth-child(2) > td.point
for tr in trs:
a_tag = tr.select_one('td.title > div > a')
if a_tag is not None:
rank = tr.select_one('td:nth-child(1) > img')['alt']
title = a_tag['title']
score = tr.select_one('td.point').text
doc = {
'rank' : rank,
'title' : title,
'score' : score
}
db.movies.insert_one(doc)
▶ 퀴즈: 웹 크롤링 결과 이용하기
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbsparta
# (1) 영화제목 '매트릭스'의 평점을 가져오기
target_movie = db.movies.find_one({'title':'매트릭스'}, {'_id':False})
target_score = target_movie['score']
print(target_score)
# (2) '매트릭스'의 평점과 같은 평점의 영화 제목들을 가져오기
movies = list(db.movies.find({'score':target_score}, {'_id':False}))
for movie in movies:
print(movie['title'])
# (3) 매트릭스 영화의 평점을 0으로 만들기
db.movies.update_one({'title':'매트릭스'},{'$set':{'score':0}})
4. 숙제: 지니뮤직 크롤링하기
import requests
from bs4 import BeautifulSoup
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbsparta
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://www.genie.co.kr/chart/top200?ditc=D&ymd=20200403&hh=23&rtm=N&pg=1',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')
#body-content > div.newest-list > div > table > tbody > tr:nth-child(1)
#body-content > div.newest-list > div > table > tbody > tr:nth-child(1) > td.number
#body-content > div.newest-list > div > table > tbody > tr:nth-child(1) > td.info > a.title.ellipsis
#body-content > div.newest-list > div > table > tbody > tr:nth-child(1) > td.info > a.artist.ellipsis
trs = soup.select('#body-content > div.newest-list > div > table > tbody > tr')
for tr in trs:
info = tr.select_one('td.info')
if info is not None:
number = tr.select_one('td.number').text
title = info.select_one('a.title.ellipsis').text
artist = info.select_one('a.artist.ellipsis').text
print(number[0:2].strip(), title.strip(), artist)
✔️ strip() : 문자열에서 특정 문자 제거
- strip([chars]) : 인자로 전달된 문자를 String의 왼쪽과 오른쪽에서 제거
- lstrip([chars]) : 인자로 전달된 문자를 String의 왼쪽에서 제거
- rstrip([chars]) : 인자로 전달된 문자를 String의 오른쪽에서 제거
* 인자 X → 공백 제거