아무것도 모르고 시작하는 코딩

야구 순위 웹 스크래핑(a.k.a 크롤링 in Korea) | 아무것도 모르고 시작하는 코딩

ZNOS 2020. 9. 19. 11:32
반응형

지난시간에 네이버영화에서 영화제목을 스크랩하는 코드를 연습했다

오늘은 그 코드를 이용하여 다른 것들을 스크래핑 해보겠다

 

네이버 영화 제목 가져오기(지난 시간의 코드)

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.nhn?sel=cur&date=20200917', 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('위와 동일')

내가 가져오고 싶은 부분이 있다면 select를 통해 잘 가져오면 된다

 

연습1) 네이버영화 순위,제목,별점 가져오기

주소 : movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cur&date=20200917

 

순위,제목,별점 위치 확인

우리가 찾고자 하는 순위,제목,별점을 검사창에서 selector로 클릭한 후 마우스 오른쪽 - copy selector를 해보자

파이참에 붙여넣기를 해보면 아래와 같이 나온다(copy selector 가 틀릴수도 있기 때문에 확인은 해야 한다)

순위 : #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

지난 코드에서 select를 이용하여 tr까지 불러왔는데, 순위,제목,별점 역시 tr까지는 모두 위치가 같으므로 똑같이 사용한다. 그리고 for문에서 각각을 rank, title, point라는 이름으로 정의하여 print 해보겠다

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.nhn?sel=cur&date=20200917', headers=headers)

# HTML을 BeautifulSoup이라는 라이브러리를 활용해 검색하기 용이한 상태로 만듦
soup = BeautifulSoup(data.content, 'html.parser')

# select를 이용해서, tr들을 불러오기
movies = soup.select('#old_content > table > tbody > tr')

# movies (tr들) 의 반복문을 돌리기
for movie in movies:
    rank = movie.select_one('td:nth-child(1) > img') #img 태그의 값 가져오기
    title = movie.select_one('td.title > div > a') #a 태그의 값 가져오기
    point = movie.select_one('td.point') #td.point 태그의 값 가져오기
    if title is not None:
        print(rank['alt'], title.text, point.text)

만약에 print(rank, title, point)를 한다면 아래와 같이 출력된다

print(rank, title, point)

우리가 필요한 것은 img 태그 안에 alt값, a태그에서 text값, td.point태그에서 text값이기 때문에

rank['alt'], title.text, point.text를 출력한다

 

 

연습2) 네이버 한국 야구 순위,승률 가져오기

주소 : sports.news.naver.com/kbaseball/record/index.nhn?category=kbo

순위, 팀명, 승률 확인

이번에도 copy-selector를 이용하여 순위,팀명,승률의 위치를 먼저 확인해보자

순위 : #regularTeamRecordList_table > tr:nth-child(1) > th
팀명 : #team_NC       #regularTeamRecordList_table > tr > span
승률 : #regularTeamRecordList_table > tr:nth-child(1) > td:nth-child(7) > strong

팀명은 copy selector로 선택하면 id명이 나오고, 이는 팀명에 따라 고유 id가 부여된 것으로 보여지기 때문에 for문에서 사용하기 위해선 태그 span을 기준으로 잡아야 한다

팀명의 위치

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://sports.news.naver.com/kbaseball/record/index.nhn?category=kbo', headers=headers)

# HTML을 BeautifulSoup이라는 라이브러리를 활용해 검색하기 용이한 상태로 만듦
soup = BeautifulSoup(data.content, 'html.parser')

# select를 이용해서, tr들을 불러오기
baseball = soup.select('#regularTeamRecordList_table > tr')

# movies (tr들) 의 반복문을 돌리기
for baseballteam in baseball:
    rank = baseballteam.select_one('th') #th태그의 값 가져오기
    title = baseballteam.select_one('span') #span태그 사이의 값 가져오기
    point = baseballteam.select_one('td:nth-child(7) > strong') #strong 태그 사이의 값 가져오기
    if title is not None:
        print(rank.text, title.text, point.text)

data에서 받을 주소를 변경해주고, rank, title, point 를 정의해준 뒤 출력하면

결과값

위와 같은 결과가 나온다

 

 

만약 승률이 0.5 이상인 팀만 출력하고 싶다!

"만약 point가 0.5보다 크면 출력해라" 라는 명령을 실행하야 한다. 그러기 위해선

1) point 문자열을 가지고 온다 (#strong 태그 사이의 값 중 문자열만 가지고 온다)
2) 문자열을 부동소숫점형으로 변환한다 (float 이용)
3) if문 이용하여 출력

1)을 위해선 .text를 print 말고 point에 붙여주면 된다.

    rank = baseballteam.select_one('th').text #th태그의 문자열 가져오기
    title = baseballteam.select_one('span').text #span태그 사이의 문자열 가져오기
    point = baseballteam.select_one('td:nth-child(7) > strong').text #strong 태그 사이의 문자열 가져오기

2),3)은 float을 이용하여 if문을 바꾼다

if float(point) > 0.5:  # 문자열(string) 을 부동소숫점형(float)으로 강제 형변환

for문 

for baseballteam in baseball:
    rank = baseballteam.select_one('th') #th태그의 값 가져오기
    title = baseballteam.select_one('span') #span태그 사이의 값 가져오기
    point = baseballteam.select_one('td:nth-child(7) > strong') #strong 태그 사이의 값 가져오기
    if float(point) > 0.5:  # 문자열(string) 을 부동소숫점형(float)으로 강제 형변환
        print(rank, title, point)

그러면 print를 할 때 .text를 붙이지 않고 출력해주면 된다

승률 0.5 이상만 출력

 

이를 응용하면 축구 순귀, 음악차트 순위 등 여러 데이터들을 스크래핑 할 수 있다

 

끝.

 

공감 부탁 드려요 :) 

반응형