예측 모델을 만들어보려고 하는데 기존에 모았던 데이터로는 모델을 만들기에 적합하지 않다고 판단했다.
그래서 경기 관련 데이터를 추가로 수집했는데 이번 포스트에서는 그 내용을 담아보려고 한다.
자세한 크롤링 방법은 이전 포스트를 참고하면 된다.
(1) 수집할 데이터 담은 태그 찾기
저번과 같은 방식으로 크롤링을 할 것이기 때문에 먼저 url과 태그를 살펴보도록 하겠다.
크롤링을 수행할 페이지는 다음과 같다. KOVO 공식 홈페이지의 경기 결과 페이지이다.
페이지를 살펴보면 경기 날짜, 경기 번호(순번), 경기를 치른 두 팀, 경기 결과, 경기가 진행된 라운드(정규리그는 총 6라운드로 구성된다.)의 데이터를 볼 수 있다.
url은 "https://www.kovo.co.kr/game/v-league/(생략)season=018&team=&s_part=2&yymm=&r_round=1"으로,
라운드 별로 데이터를 수집하기 위해서 라운드 조건을 설정한 것이 url에 반영된 것을 볼 수 있다.
이어서 태그를 보기 위해 개발자 도구 창을 열었다.
저번 경우와 마찬가지로 데이터가 테이블 안에 저장되어 있고 그 아래 tbody, tr, td 순으로 하위로 뻗어나가는 것을 확인할 수 있었다.
(2) 코드 작성
이제 찾은 클래스와 태그를 바탕으로 크롤러 코드를 작성하도록 하겠다.
저번처럼 크롤러를 돌릴 때마다 input 메소드로 수집할 라운드를 설정한 후 크롤링하는 방법과 반복 범위를 지정한 후 크롤링하는 방법을 선택할 수 있다.
정규리그 전체가 6라운드이기 때문에 이번에는 반복 횟수를 정해서 크롤링했다.
for i in range(1,7):
search_url = "https://www.kovo.co.kr/game/v-league/11110_schedule_list.asp?season=018&team=&s_part=2&yymm=&r_round="+str(i)
browser.get(search_url)
browser.implicitly_wait(2)
# 크롤링 할 데이터 테이블,태그 찾기 - 경기 정보 (날짜, 홈팀, 원정팀, 경기결과, 라운드)
table = browser.find_element_by_class_name('wrp_lst') # div.wrp_lst
tbody = table.find_element_by_tag_name("tbody")
rows = tbody.find_elements_by_tag_name("tr")
...
이번에도 table 을 찾을 때 table 태그 위의 div 태그의 클래스명을 사용했는데, 테이블 클래스명을 지정했을 때 오류가 발생했기 때문이다.
코드에 적용하진 않았지만 tbody 나 rows 처럼 tag_name 으로 table 을 찾는 방법도 가능한데, 정확하게 수행하기 위해서 table을 찾을 때는 클래스명을 사용했다.
이번에는 tr 안의 데이터들을 저장하는 과정이 길어졌는데, 하나씩 살펴보도록 하겠다.
위의 웹 페이지를 보면 테이블 안에 중간 중간 경기가 없는 날이 있다.
하지만 크롤링을 수행하다보면 경기가 없는 날의 데이터도 rows 에 포함되었기 때문에 조건문을 통해 해당 경우를 제외했다.
tr 안의 데이터를 통해 수집할 데이터는 총 7가지로 [날짜, 경기번호, 홈팀, 원정팀, 스코어, 승리팀, (경기한)세트 수] 이다.
하지만 원래의 데이터를 그대로 저장할 수는 없고 약간의 가공을 거쳐야 한다.
10월 16일의 데이터를 예시로 설명하면
date 데이터는 가공 과정을 거치면 '10. 16 (토)'의 형태에서 '1016' 의 형태로 바뀌고
teamH 데이터는 'GS칼텍스 3 :' 에서 'GS칼텍스' 형태로, teamA 데이터는 '0 흥국생명' 에서 '흥국생명'으로 바뀐다.
score 데이터는 초기의 teamH, teamA 데이터를 합한 후 숫자와 ':' 문자를 리스트로 추출한 후 하나의 문자열로 바꾸고
경기를 이기는 조건인 3세트를 따낸 팀이 홈팀이면(index 0) win 데이터에 홈팀을, 그 외에는 원정팀을 저장한다.
score 데이터를 리스트로 변환할 때 ':' 문자가 포함되었기 때문에 총 세트 수를 구할 때는 숫자만 추출해서 더한다.
(데이터를 리스트에 추가하는 과정은 코드에 포함하지 않았다. *이전 포스트 참고)
for value in rows:
d = value.find_elements_by_tag_name("td")
if len(d)>3:
date = d[0].text
ndate = re.findall('[0-9]',date)
ndate = "".join(date)
gamenum = d[1].text
teamH = d[3].text
teamA = d[4].text
score = re.findall('[0-9:]',teamH+teamA)
teamH = re.sub('[0-9: ]', '', teamH)
teamA = re.sub('[0-9: ]', '', teamA)
if score.index('3')==0:
win = teamH
else:
win = teamA
score = "".join(score)
setnum = re.findall('[0-9]',teamH+teamA)
setcnt = 0
for s in setnum:
setcnt += int(s)
...
(3) 데이터 저장
크롤링이 끝난 후에는 마찬가지로 csv 파일로 데이터를 저장한다.
수집한 데이터 중 날짜, 홈팀, 원정팀, 스코어, 라운드, 승리팀을 하나의 데이터프레임으로 변환한 모습이다.
위 데이터는 자세히 보면 날짜가 가공한 형태가 아닌 원래의 형태인데 그렇다면 가공한 날짜 데이터와 함께 수집한 경기 번호, 총 세트 수 데이터는 왜 수집한 걸까?
세 데이터는 다음 포스트에서 사용할 예정인데 위 데이터는 경기의 대략적인 데이터를 만든 것이고, 다른 웹 페이지를 통해 경기 세부 데이터를 추가로 모을 예정이기 때문에 그것에 필요한 새 날짜, 경기 번호, 세트 수 데이터를 함께 모은 것이다.
어쩌다보니 크롤링 관련해서 게시글을 세 개나 작성하게 되었는데,
그만큼 관련 내용도 많이 찾아보고 수행해보면서 많은 것을 깨달아가고 있어서 뿌듯하긴 하다.
그럼 이어지는 포스트에서는 경기 세부 데이터를 수집해보도록 하겠다.
'프로젝트 > [DA] 데이터 분석 : 배구' 카테고리의 다른 글
데이터 수집 (웹 크롤링) (3) - 경기 세부 데이터 (0) | 2022.03.27 |
---|---|
데이터 전처리 - 결측값 처리 (0) | 2022.03.13 |
데이터 전처리 - PySpark에서 SQL 사용하기 (0) | 2022.03.12 |
프로젝트 설명 & 데이터 수집 (웹 크롤링), 저장 - 선수 데이터 (0) | 2022.03.11 |