네이버 영화 페이지에서 크롤링을 진행해보겠다.
pip install bs4
, requests
, pymongo
, certifi
로 라이브러리를 설치해주고 시작한다.
(certifi는 mongodb 사용 중 보안 에러 때문에 설치했다.)
전체 코드는 아래와 같다.
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient('내 db 주소', tlsCAFile=ca)
db = client.dbsparta
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)
# soup이라는 변수에 "파싱 용이해진 html"이 담긴 상태가 됨
soup = BeautifulSoup(data.text, 'html.parser')
trs = soup.select("#old_content > table > tbody > tr")
for tr in trs :
title = tr.select_one("td.title > div > a")
if title is not None :
title = title.text
rank = tr.select_one("td:nth-child(1) > img")["alt"]
star = tr.select_one("td.point").text
print(rank, title, star)
doc = {
'title' : title,
'rank' : rank,
'star' : star,
}
# movies라는 collection을 생성해서 doc을 넣는 것
db.movies.insert_one(doc)
받아온 데이터(soup)에서 필요한 값(= 영화 제목, 순위, 별점)이 담겨진 태그를 선택자로 지칭하여 그 안의 값들을 trs 변수로 받는다.
<if title is not None>
이 있는 이유는 네이버 영화 페이지에서 구분선도 <tr>
로 처리했기 때문에 trs 리스트에 영화 값이 온전히 담긴 데이터만 있는것이 아니라서 title(=trs 리스트에서 셀렉한 태그 값)에 None
이 있을 수 있으므로 데이터가 있는 녀석들만 거르기 위해 넣는다.
db에 값을 넣을 때는 key : value 형태인 객체를 변수에 담아 insert 해주면 된다. collection은 DB에서 관련성 있는 데이터들을 모은 집합으로 내가 이름을 정의하여 값을 넣어주기만 하면 된다. https://cloud.mongodb.com/ 에서 확인 가능하다.
# 저장 - 예시
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'})
# 선택자를 사용하는 방법 (copy selector)
soup.select('태그명')
soup.select('.클래스명')
soup.select('#아이디명')
soup.select('상위태그명 > 하위태그명 > 하위태그명')
soup.select('상위태그명.클래스명 > 하위태그명.클래스명')
# 태그와 속성값으로 찾는 방법
soup.select('태그명[속성="값"]')
# 한 개만 가져오고 싶은 경우
soup.select_one('위와 동일')
# 혹은 크롬의 copy selector로 요소의 선택자를 텍스트로 뽑아올 수 있음
지니뮤직 홈페이지에서 순위, 가수, 곡을 크롤링 해보겠다.
위와 같은 방법으로
1. requests
와 bs4
설치
2. requests.get
('지니뮤직 홈페이지 주소')로 data 가져오기
3. 크롬의 copy-selector
로 필요한 값(순위, 가수, 곡)을 가진 태그 긁어오기
4. soup.select()
로 값이 담긴 리스트를 변수에 담고 반복문 돌려서 각각의 값들 select로 가져오기
이때 주의할 점은 값을 가져오면 깔끔하게 나오지 않고 공백들이 겁나 많다. 따라서 슬라이싱해주고
strip()
을 사용하여 텍스트만 남겨준다.
전체 코드는 아래와 같다.
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://www.genie.co.kr/chart/top200?ditc=M&rtm=N&ymd=20230321',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')
# 순위 #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 :
rank = tr.select_one("td.number").text[0:2].strip()
title = tr.select_one("td.info > a.title.ellipsis").text.strip()
singer = tr.select_one("td.info > a.artist.ellipsis").text
print(rank, title, singer)
결과는 디토 체고