웹종합 - pymongo와 크롤링

soo's·2023년 3월 22일
0

TIL

목록 보기
23/53
post-thumbnail

𝟏. 크롤링

네이버 영화 페이지에서 크롤링을 진행해보겠다.
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)
  1. 받아온 데이터(soup)에서 필요한 값(= 영화 제목, 순위, 별점)이 담겨진 태그를 선택자로 지칭하여 그 안의 값들을 trs 변수로 받는다.

  2. <if title is not None>이 있는 이유는 네이버 영화 페이지에서 구분선도 <tr>로 처리했기 때문에 trs 리스트에 영화 값이 온전히 담긴 데이터만 있는것이 아니라서 title(=trs 리스트에서 셀렉한 태그 값)에 None이 있을 수 있으므로 데이터가 있는 녀석들만 거르기 위해 넣는다.

  3. db에 값을 넣을 때는 key : value 형태인 객체를 변수에 담아 insert 해주면 된다. collection은 DB에서 관련성 있는 데이터들을 모은 집합으로 내가 이름을 정의하여 값을 넣어주기만 하면 된다. https://cloud.mongodb.com/ 에서 확인 가능하다.



📌 pymongo에서 db 조작 방법 참고

# 저장 - 예시
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'})

📌 bs4에서 값 찾는 방법 참고

# 선택자를 사용하는 방법 (copy selector)
soup.select('태그명')
soup.select('.클래스명')
soup.select('#아이디명')

soup.select('상위태그명 > 하위태그명 > 하위태그명')
soup.select('상위태그명.클래스명 > 하위태그명.클래스명')

# 태그와 속성값으로 찾는 방법
soup.select('태그명[속성="값"]')

# 한 개만 가져오고 싶은 경우
soup.select_one('위와 동일')

# 혹은 크롬의 copy selector로 요소의 선택자를 텍스트로 뽑아올 수 있음


𝟐. 크롤링 응용 (feat.지니뮤직)

지니뮤직 홈페이지에서 순위, 가수, 곡을 크롤링 해보겠다.
위와 같은 방법으로
1. requestsbs4 설치
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)

결과는 디토 체고

0개의 댓글