그저 내가 되었고
항해99) 웹종 3주차 웹스크랩핑(크롤링) 본문
※ 스파르타피디아에 OpenAPI 붙여보기 vs 스파르타피디아 POST 크롤링?!!?!?!?!
전자: 스파르타가 미리 만들어둔 OpenAPI를 갖고와서 보여주기'만' 하는 것
후자: 사용자가 아예 새로운 것 만들어서 붙이려고 네이버 영화에서 정보 긁어오는 것
* 크롤링
1. 두 개 설치 : 주소 찍고 그 웹페이지 html 가져오는 것(requests로 할 것) & 그 안에서 제목 등 필요한 정보 찾는 것(beautifulsoup)
2. 파이썬 파일 준비: 크롤링 기본 세팅 app.py에 붙여넣기
3. 크롤링 시작: 기본 세팅에서, url만 내가 긁을 페이지로 바꿔 가면서 사용하면 됨.
4. mongodb 저장하려면 인터프리터 dnspython, pymongo 설치 필요
* 크롤링을 하려면?(beautifulsoup 라이브러리 사용법)
1) 크롤링 기본 세팅:
주소창에 요청해서 html을 가져오는 것. data = resquests.get('http://~로 주소를 가져옴!)
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')
#############################
# (입맛에 맞게 코딩)
#############################
2) html을 가져와서 제목을 찾는 법:
beautifulsoup 이용.
1)의 코드 보셈. 맨 윗부터 두 줄 import requests이랑 from bs4 import BeautifulSoup이게 requests를 쓸거고, beautifulsoup 쓰겠다고 하는 것.
그 밑 줄의 headers는 뭐? 우리가 코드로 콜을 날리는건데 마치 브라우저인양ㅋ 사람인양 하는 것.
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')
|
다른 부분은 다 똑같고, 빨간 부분(url)만 바꿔서 사용하면 됨.
3) select/select_one 사용법:
✔영화 제목을 가져 올 것
✔태그 안의 텍스트를 찍고 싶을 땐 → 태그.text
✔태그 안의 속성을 찍고 싶을 땐 → 태그['속성']
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 = BeautifulSoup(data.text, 'html.parser')
# select를 이용해서, tr들을 불러오기
movies = soup.select('#old_content > table > tbody > tr')
# movies (tr들) 의 반복문을 돌리기
for movie in movies:
# movie 안에 a 가 있으면,
a_tag = movie.select_one('td.title > div > a')
if a_tag is not None:
# a의 text를 찍어본다.
print (a_tag.text)
+) beautifulsoup 내 select에 미리 정의된 다른 방법
# 선택자를 사용하는 방법 (copy selector)
soup.select('태그명')
soup.select('.클래스명')
soup.select('#아이디명')
soup.select('상위태그명 > 하위태그명 > 하위태그명')
soup.select('상위태그명.클래스명 > 하위태그명.클래스명')
# 태그와 속성값으로 찾는 방법
soup.select('태그명[속성="값"]')
# 한 개만 가져오고 싶은 경우
soup.select_one('위와 동일')
* 웹스크래핑 해보기(네이버 영화에서 영화 제목)
: 파이썬 문법 아니고 뷰티풀슾 사용법!!!!!!
1) '영화 제목'을 찍어 보려면, 아래 그림처럼 제목(밥정) 위에서 우클릭>검사>블럭처리된부분에서 우클릭>카피>카피셀렉터 클릭
2) 파이참에서 맨 밑줄에 title = 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')
title = soup.select_one('#old_content > table > tbody > tr:nth-child(2) > td.title > div > a')
여기서 print(title) 찍으면 아래처럼 태그가 쭉~ 나옴.
<a href="/movie/bi/mi/basic.naver?code=186114" title="밥정">밥정</a>
여기서 다시 print(title.text) 찍으면 밥정만 딸랑 나옴ㅎㅋ
만약 "/movie/bi/mi/basic.naver?code=186114" 이 부분을 찾고싶으면? print(title['href'])찍는다.
방금까지 select_one 즉 하나만 찍어봤고, 여러개를 select 할 수도 있어. how?
3) 밥정은 볼장 다 봤고~ 그린 북 위에서 검사해서 다시 카피 셀렉터ㄱ & 가버나움에서도 똑같이 카피셀렉터 ㄱ
4) 밥정 내용만 싹 지워주고, 복사한거 둘 다 갖다 붙여봐봐.
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')
#old_content > table > tbody > tr:nth-child(3) > td.title > div > a
#old_content > table > tbody > tr:nth-child(4) > td.title > div > a
그러면 위처럼 나오거덩. 보면
앞쪽에 #old_content > table > tbody > tr
이거랑
뒷쪽에 td.title > div > a
이거는 같고 중간에만 좀 다르네! 그러면
앞쪽에 같은 부분! 저기를 셀렉할꺼야. 이번엔 select_one(한 개) 아니고 select(전부)👇🏻👇🏻
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')
#old_content > table > tbody > tr:nth-child(3) > td.title > div > a
#old_content > table > tbody > tr:nth-child(4) > td.title > div > a
movies = soup.select('#old_content > table > tbody > tr')
이렇게 적어주고 print(movies) 찍어보면 영화 목록이 쭉~~~~~ 태그로 잘 들어오는 것 확인 가능!!!
근데 저기.. tr이 뭔지 궁금쓰? 그건 아까처럼 영화 제목에서 검사 클릭하면 자료들이 리스트 형태로 <tr>..</tr>이렇게 쭉~~~~적혀있는 것 확인할 수 있음. 즉, 저 위의 코드의 마지막줄은 select를 이용해서, tr들을 불러오기임~~!
5) 여기서 영화 제목만 찍어보는 법?
👉🏻for문 돌릴거고, h태그(걍 아무 의미 없음... a든 b든 맘대로 하ㅋ셈ㅋ) 잡아서 일단 print 돌려보자. 아래 코드처럼.
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')
#old_content > table > tbody > tr:nth-child(3) > td.title > div > a
#old_content > table > tbody > tr:nth-child(4) > td.title > div > a
movies = soup.select('#old_content > table > tbody > tr')
for movie in movies:
h = movie.select_one('td.title > div > a')
print(h)
이렇게 하면 결과가
None <a href="/movie/bi/mi/basic.naver?code=186114" title="밥정">밥정</a>
<a href="/movie/bi/mi/basic.naver?code=171539" title="그린 북">그린 북</a>
........
|
위처럼 쭉쭉쭉 나오거덩. 이때 None이 뭐냐?! 얘들은 구ㅋ분ㅋ선ㅋ 그러니까 쟤들을 제외해줄거임. 어케? if문👇🏻👇🏻
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')
#old_content > table > tbody > tr:nth-child(3) > td.title > div > a
#old_content > table > tbody > tr:nth-child(4) > td.title > div > a
movies = soup.select('#old_content > table > tbody > tr')
for movie in movies:
h = movie.select_one('td.title > div > a')
if h is not None:
print(h)
이렇게 찍어보면 none 없이 쭉쭉 잘 나옴.
<a href="/movie/bi/mi/basic.naver?code=186114" title="밥정">밥정</a>
<a href="/movie/bi/mi/basic.naver?code=171539" title="그린 북">그린 북</a>
........
|
근데 위에 박스 보면 뭐 군놈들이 너무 많아... 제목만 보여줘. how? text 사용(파이썬 문법 ㄴㄴ 뷰티풀숲)
👉🏻 태그 안의 텍스트를 찍고 싶을 땐 → (태그).text -e.g. star = movie.select_one('td.point').text / print(a.text)
👉🏻 태그 안의 속성을 찍고 싶을 땐 → (태그)['속성'] -e.g. rank = movie.select_one('td:nth-child(1) > img')['alt']
|
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')
#old_content > table > tbody > tr:nth-child(3) > td.title > div > a
#old_content > table > tbody > tr:nth-child(4) > td.title > div > a
movies = soup.select('#old_content > table > tbody > tr')
for movie in movies:
h = movie.select_one('td.title > div > a')
if h is not None:
print(h.text)
이러면? 아래처럼 제목만 쭉쭉 잘 찍힘ㅋ
밥정
그린 북
.......
|
* 웹스크래핑 더 해보기 (순위, 제목, 별점)
1) '영화 제목'을 찍어본 두 줄.. 거기 밑에다가, 순위랑 별점 똑같이 카피셀렉터 후 붙여넣어보셈.
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')
#old_content > table > tbody > tr:nth-child(3) > td.title > div > a
#old_content > table > tbody > tr:nth-child(4) > td.title > div > a
#old_content > table > tbody > tr:nth-child(2) > td:nth-child(1) > img
#old_content > table > tbody > tr:nth-child(2) > td.point
movies = soup.select('#old_content > table > tbody > tr')
for movie in movies:
h = movie.select_one('td.title > div > a')
if h is not None:
print(h.text)
위처럼 나오는데, 공식으로 생각할 것 말해줄게.
#old_content > table > tbody > tr:nth-child(2) > td:nth-child(1) > img
#old_content > table > tbody > tr:nth-child(2) > td.point
여기 이거, 위에꺼가 순위, 밑에꺼가 별점에서 각각 긁어온건데,
굵게 처리된 tr:nth-child(2)부분 뒤에 td:nth-child(1) > img랑 td.point만 써먹을겨. 그래서
2) 이렇~~~~~게 써주면 됩니다~~~~~~~~~~~!(?)
👉🏻 태그 안의 텍스트를 찍고 싶을 땐 → (태그).text -e.g. star = movie.select_one('td.point').text / print(a.text)
👉🏻 태그 안의 속성을 찍고 싶을 땐 → (태그)['속성'] -e.g. rank = movie.select_one('td:nth-child(1) > img')['alt']
|
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')
#old_content > table > tbody > tr:nth-child(3) > td.title > div > a
#old_content > table > tbody > tr:nth-child(4) > td.title > div > a
#old_content > table > tbody > tr:nth-child(2) > td:nth-child(1) > img
#old_content > table > tbody > tr:nth-child(2) > td.point
movies = soup.select('#old_content > table > tbody > tr')
for movie in movies:
h = movie.select_one('td.title > div > a')
if h is not None:
rank = movie.select_one('td:nth-child(1) > img')['alt']
title = h.text
star = movie.select_one(' td.point').text
print(rank, title, star)
저 rank = movie.select_one('td:nth-child(1) > img')['alt']에서 빌어먹을 ['alt']는 어디서 왔냐고?ㅋ
저거 없이 찍어보면 앎ㅋ
걍 rank = movie.select_one('td:nth-child(1) > img')까지만 찍고 print(rank)하면
<img alt="01" height="13" src="https://ssl.pstatic.net/imgmovie/2007/img/common/bullet_r_r01.gif" width="14"/> 밥정 9.64
.....
|
걍 이렇게 줄줄이 나오거던.
(또는 아까 웹페이지에서 순위(숫자) 위에서 우클릭>검사> 보면 'alt'속성이 숫자 나타내고 있는 것 알 수 있기도 하고.)
저것들중에 내가 필요한건 딱!!!!! 01이라는 숫자 딱 저거잖아? 그러니까 ['alt']까지(속성까지) 같이 찍어주면 아래처럼 존나 깔끔-하게나옴(속-시-원-)
01 밥정 9.64
02 그린 북 9.59
03 가버나움 9.59
.......
|
* 웹스크래핑 결과 저장하기
: insert 연습하기 - 웹스크래핑(크롤링) 결과를 DB에 저장하기
네가 지난시간에 했던 순위, 제목, 별점 찍어준거 그걸 한번 파이몽고(?)DB에 저장해볼게.
네가 아까 다 했던거!!에다가 위의 꼭 적어줘야된다는 쟤만 추가한 것.
- 아래의 pymongo 기본 셋팅에서
import requests
from bs4 import BeautifulSoup
from pymongo import MongoClient
client = MongoClient('mongodb+srv://test:sparta@cluster0.55vah.mongodb.net/Cluster0?retryWrites=true&w=majority')
db = client.dbsparta
# 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 = BeautifulSoup(data.text, 'html.parser')
# select를 이용해서, tr들을 불러오기
movies = soup.select('#old_content > table > tbody > tr')
# movies (tr들) 의 반복문을 돌리기
for movie in movies:
# movie 안에 a 가 있으면,
a_tag = movie.select_one('td.title > div > a')
if a_tag is not None:
rank = movie.select_one('td:nth-child(1) > img')['alt'] # img 태그의 alt 속성값을 가져오기
title = a_tag.text # a 태그 사이의 텍스트를 가져오기
star = movie.select_one('td.point').text # td 태그 사이의 텍스트를 가져오기
print(rank,title,star)
- doc 만들어 하나씩 insert 해보자
import requests
from bs4 import BeautifulSoup
from pymongo import MongoClient
client = MongoClient('mongodb+srv://test:sparta@cluster0.55vah.mongodb.net/Cluster0?retryWrites=true&w=majority')
db = client.dbsparta
# 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 = BeautifulSoup(data.text, 'html.parser')
# select를 이용해서, tr들을 불러오기
movies = soup.select('#old_content > table > tbody > tr')
# movies (tr들) 의 반복문을 돌리기
for movie in movies:
# movie 안에 a 가 있으면,
a_tag = movie.select_one('td.title > div > a')
if a_tag is not None:
rank = movie.select_one('td:nth-child(1) > img')['alt'] # img 태그의 alt 속성값을 가져오기
title = a_tag.text # a 태그 사이의 텍스트를 가져오기
star = movie.select_one('td.point').text # td 태그 사이의 텍스트를 가져오기
doc = {
'rank': rank,
'title': title,
'star': star
}
db.movies.insert_one(doc)
* Quiz_웹스크래핑 결과 이용하기
(1) 영화제목 '가버나움'의 평점을 가져오기
target_movie = db.movies.find_one({'title':'가버나움'})
print(target_movie['star'])
(2) '가버나움'의 평점과 같은 평점의 영화 제목들을 가져오기
target_movie = db.movies.find_one({'title':'가버나움'})
target_star = target_movie['star']
movies = list(db.movies.find({'star':target_star}))
for movie in movies:
print(movie['title'])
(3) '가버나움' 영화의 평점을 0으로 만들기
db.movies.update_one({'title':'가버나움'},{'$set':{'star':'0'}})
(4) 지니뮤직의 1~50위 곡을 스크래핑(순위 / 곡 제목 / 가수)
: 지니뮤직 사이트 https://www.genie.co.kr/chart/top200?ditc=M&rtm=N&ymd=20210701
✨힌트:
0) 출력 할 때는 print(rank, title, artist) 하면 됩니다!
1) 앞에서 두 글자만 끊기! text[0:2] 를 써보세요!
2) 순위와 곡제목이 깔끔하게 나오지 않을 거예요. 옆에 여백이 있다던가, 다른 글씨도 나온다던가.. 파이썬 내장 함수인 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=20210701',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')
trs = soup.select('#body-content > div.newest-list > div > table > tbody > tr')
for tr in trs:
title = tr.select_one('td.info > a.title.ellipsis').text.strip()
rank = tr.select_one('td.number').text[0:2].strip()
artist = tr.select_one('td.info > a.artist.ellipsis').text
print(rank, title, artist)
'개발 > 항해99 9기' 카테고리의 다른 글
항해99) 웹종 4주차 [화성땅 공동구매] POST 연습 (0) | 2022.09.05 |
---|---|
항해99) 웹종 3주차 DB (0) | 2022.09.05 |
항해99) 웹종 3주차 Python (0) | 2022.09.05 |
항해99) 웹종 2주차 jQuery+Javascript 연습 & jQuery+Ajax 연습 (0) | 2022.09.05 |
항해99) 웹종 2주차 jQuery (0) | 2022.09.04 |