데이터 분석을 공부하는 도중 생각났다.
책으로 공부함과 동시에 뭐를 하나 만들어보면 어떨까?
프로야구 크롤링은 여기서 시작되었다.
실제로 그냥 책을 보면서 따라하는 것 보단 내가 하고 싶은걸 하면서 배우면 더 좋지 않을까 싶어서 시작했다.
어렸을 때부터 야구를 좋아하기도 했고, 시도하기에는 안성 맞춤이였다.
처음에 누가 시도한게 있을까 싶어서 여기저기 찾아보았고, 몇 몇 분들이 시도한 글을 읽고 참고하며 만들기 시작했다.
어떤분이 쓰신 글을 봤는데, 내가 크롤링을 해도 되는지 않되는지 확인을 먼저 해야 한다고 한다.
확인 방법은 링크 뒤에 /robots.txt를 붙이면 된다고 했다.
프로야구 공식 홈페이지인
여기 뒤에다가 /robots.txt를 붙이면 이렇게 나온다.
저기 쓰여있는 common, help, member, ws를 제외한 모두를 할 수 있다는 뜻이라고 한다.
이제 크롤링클 시작해보자
먼저 기록실로 들어갔다.
기록실로 들어가 봤는데, 크게 타자, 투수, 수비, 주루 4가지로 나뉘어 있다.
하지만 일단 하나라고 먼저 만들어보자는 생각에 타자를 먼저 크롤링을 시작했다.
import requests
# 접속하기 위한 가상의 pc
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'}
# 접속 링크
r = requests.get('https://www.koreabaseball.com/Record/Player/HitterBasic/BasicOld.aspx?sort=HRA_RT',headers=headers)
여기서 headers라는 부분이 있는데 headers를 추가하는 이유는 가끔 페이지를 크롤링을 하는데 차단당하는 경우가 있다.
이런 차단을 회피하기위한 편법인데, 다행이 선수 기록을 크롤링하는데 차단당하지 않아서 굳이 headers를 추가하지 않아도 된다.
requests를 통해 해당 홈페이지의 소스코드를 가져올 수 있다.
html의 코드를 보려면 뒤에 .content를 붙이면 되는데 그냥 .content만 붙이면 이렇게 우리가 보기 힘든 상태로 출력된다.
이것을 우리가 평소 html 소스코드 보듯이 바꿔줘야 하는데, 그럴때 쓰는 것이 BeautifulSoup이다.
from bs4 import BeautifulSoup
soup = BeautifulSoup(r.content, 'html.parser')
soup
html.parser은 r.content 즉 우리가 가져온 내용을 html에 맞게 변경시켜준다.
이제 여기서 우리가 원하는 태그를 골라서 원하는 내용을 가져오면 된다.
저기서 우리는 저 선수들의 기록을 가져오고 싶다.
그럼 저 내용이 html 소스코드에서 어디에 있는지 알아야 한다.
홈페이지를 들어간 상태에서 f12를 누르면 개발자 모드가 옆에 생겨난다.
여기서 우리는 저 표를 찾아야 한다.
코드에 마우스를 올리면 홈페이지에 해당하는 부분에 색깔이 들어오기 때문에 이런 방식으로 찾으면 된다.
더 쉬운 방법은 모드중
저 부분을 누루면 홈페이지에서 원하는 부분을 클릭했을 때 자동으로 해당 코드로 옮겨진다.
해당 테이블은 "record_result"라는 클래스 이름을 가진 div 태그 안에 들어가 있다.
그럼 BeautifulSoup의 select를 통해 헤당 태그로 이동한다.
player_html = soup.select('div.record_result > table > tbody > tr')
player_html
태그 속성이 class라면 .을 붙이고 id라면 #을 붙인다.
나는 한 줄 한 줄 불러들어야 하기 때문에 tr 태그 까지 갔다.
이렇게 하고 출력하면
이런식으로 tr 내용 즉, 표 내용이 모두 출력된다.
여기서 우리는 td 태그 안의 텍스트만 뽑아내면 된다.
나는 한 줄씩 뽑아서 쓰는 방법을 사용헀다.
리스트에 tr태그 하나씩 넣고 거기서 다시 td태그를 하나씩 뽑는 방법을 사용했다.
# 행 전체 저장
player_tr = []
# 행 한 줄 저장
player_td = []
# 행 한 줄씩 저장
for i in range(0,len(player_html)):
player_tr.append(player_html[i].select('td'))
# 모든 내용 뽑기
for i in range(0, len(player_tr)):
player_td = player_tr[i]
for j in range(0, len(player_td)):
print(player_td[j].text)
이 글을 썼을 당시 준플레이오프 경기를 하고 있었기 떄문에 14명의 선수만 기록되었다.
(오히려 적어서 하기 편했다)
이제 모든 원소를 뽑을 수 있으니 이걸 한 리스트에 한줄씩 묶어서 저장하면 된다.
# 전체 표
player_data = []
# 모든 내용 뽑기
for i in range(len(player_tr)):
# 한 행씩 저장
player_td = player_tr[i]
# 한 줄
player_line = []
for j in range(len(player_td)):
# 한 줄 만들기
player_line.append(player_td[j].text)
# 한 줄씩 넣어서 전체 표 만들기
player_data.append(player_line)
# 데이터 프레임 만들기
player = pd.DataFrame(player_data)
player
한 줄(행)을 저장할 player_line 배열을 만들었다.
이 배열은 한 행이 저장되고 사용되면 다시 초기화 시켜주어야 하기 때문에 전체 데이터 표에 들어가면 다시 초기화 시켜준다.
그리고 그렇게 만든 전제 데이터를 데이터 프레임으로 바꿔준다.
일단 여기까지 했을때 선수 기록이 제대로 들어가는 것을 확인 할 수 있다.
하지만 한가지 아쉬은 점은, index와 columns이 우리가 kbo 홈페이지에서 봤을때 처럼 이름이 정해져 있지 않았다.
이제 저 숫자들을 이해하기 쉽게 이름으로 정해주여야 한다.
먼저 저 부분의 이름을 찾아야 한다.
어차피 같은 테이블 안에 있기 때문에 찾기가 쉬웠다.
div > table > thead > tr > th 에 들어가 있으니 BeautifulSoup의 select를 통해 찾으면 된다.
# 타이틀 위치 찾기
player_thead = soup.select('div.record_result > table > thead > tr > th')
# 출력
for i in range(len(player_thead)):
print(player_thead[i].text)
이제 이것을 하나의 리스트로 만들고 데이터 프레임의 칼럼명으로 지정해 주면 된다.
그리고 순위 부분을 인덱스로 설정한다.
player_columns = []
for i in range(len(player_thead)):
player_columns.append(player_thead[i].text)
player.columns = player_columns
player = player.set_index('순위')
전체 코드
import requests
from bs4 import BeautifulSoup
import pandas as pd
# 접속하기 위한 암묵적인 코드
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'}
# 접속 링크
r = requests.get('https://www.koreabaseball.com/Record/Player/HitterBasic/BasicOld.aspx?sort=HRA_RT')
soup = BeautifulSoup(r.content, 'html.parser')
player_html = soup.select('div.record_result > table > tbody > tr')
player_thead = soup.select('div.record_result > table > thead > tr > th')
# 행 전체 저장
player_tr = []
# 행 한 줄 저장
player_td = []
# 행 한 줄씩 저장
for i in range(0,len(player_html)):
player_tr.append(player_html[i].select('td'))
# 전체 표
player_data = []
# 모든 내용 뽑기
for i in range(len(player_tr)):
player_td = player_tr[i]
# 한 줄
player_line = []
for j in range(len(player_td)):
# 한 줄 만들기
player_line.append(player_td[j].text)
# 한 줄씩 넣어서 전체 표 만들기
player_data.append(player_line)
# 데이터 프레임 만들기
player = pd.DataFrame(player_data)
player_columns = []
for i in range(len(player_thead)):
player_columns.append(player_thead[i].text)
player.columns = player_columns
player = player.set_index('순위')
player
'이것저것 개발' 카테고리의 다른 글
파이썬으로 프로야구 크롤링하기-2 (0) | 2022.10.25 |
---|