웹크롤링 준비
<다음 영화 사이트 웹크롤링>
- URL : http://movie.daum.net
- 다음영화 > 랭킹 > 박스오피스 > 월간 위치의 데이터 수집
- 수집데이터 : 영화 제목, 평점, 댓글
- 생성할 데이터 : 긍정/부정
<웹크롤링 라이브러리>
- 정적인 웹크롤링을 할 경우 : BeautifulSoup
: 하나의 페이지에 보이는 부분만 수집할 때 사용
- 동적인 웹크롤링을 할 경우 : selenium
: 클릭과 같은 이벤트 등 페이지 전환을 하면서 수집할 때 사용
🐤설치 필요 : pip install selenium
- 동적 웹페이지 처리를 위한 라이브러리(페이지를 컨트롤하는 라이브러리)
from selenium import webdriver
- 웹페이지 내에 데이터 추출을 위한 라이브러리()
from selenium.webdriver.common.by import By
- 시간 라이브러리 추가
(특정 url가지고 접근할 때 시간이 걸리는 경우가 있는데 이때 읽는 시간을 주기 위해 프로그램을 wait하는 라이브러리)
import time
웹크롤링 - 페이지 제어
🐤 크롬브라우저 띄우기
- 브라우저 컨트롤
driver = webdriver.Chrome()
🐤 url을 이용하여 페이지 접근
- get() : 페이지에 접근 후 해당 html 코드 읽어 들이기
- driver 객체가 모든 정보를 가지고 있음
driver.get("https://movie.daum.net/ranking/boxoffice/monthly")

웹크롤링 - 데이터 수집 ①영화제목
🐤 제목이 있는 부분의 HTML 태그 경로(패스) 추출하기
- 크롬브라우저 > F12(개발자 모드) > 영화 제목 마우스 우클릭 > [검사] 클릭 > a 태그에 마우스 위치 후 우클릭 > Copy > Copy selector 클릭
☆해당 제목의 위치(경로) 저장됨 ☆
- a 태그 위치 경로 ( # : id, . : class, 띄어쓰기 : 자식들, > : 바로 아래 자식)
movie_path = "#mainContent > div > div.box_boxoffice > ol > li:nth-child(1) > div > div.thumb_cont > strong > a"
→ 모든 정보 가져오고 싶으면 ":nth-child(1)"를 제거
movie_path = "#mainContent > div > div.box_boxoffice > ol > li > div > div.thumb_cont > strong > a"

🐤 현재 크롬브라우저에 보이는 영화제목 모두 추출하기
- find_element(): 한건 조회
- find_elements(): 여러건 조회(리스트 타입으로 반환)
- By.CSS_SELECTOR : CSS 스타일 경로를 인식할 수 있도록 지정
movie_elements = driver.find_elements(By.CSS_SELECTOR, movie_path)
#확인
print(f"movie_elements length = {len(movie_elements)}")
# 리스트 타입 0번째 제목 , 태그와 태그 사이에 text가 들어있다.( .text로 접근 )
print(f"title[0] =>> {movie_elements[0].text}")
print(f"movie_elements(제목) = {movie_elements}")

🐤 웹크롤링 처리가 모두 완료되면, driver 종료해야 함(꼭!!)
driver.quit
최종 코드
- try-except 예외처리로 driver 종료해주기!!
try:
# 브라우저 컨트롤
driver = webdriver.Chrome()
# url을 이용하여 페이지 접근
driver.get("https://movie.daum.net/ranking/boxoffice/monthly")
### 영화제목이 있는 -> a 태그 위치 경로
movie_path = "#mainContent > div > div.box_boxoffice > ol > li > div > div.thumb_cont > strong > a"
# 현재 크롬브라우저에 보이는 영화제목 모두 추출하기
movie_elements = driver.find_elements(By.CSS_SELECTOR, movie_path)
except Exception as e:
print(e)
# 웹크롤링 처리가 모두 완료되면, driver 종료!
driver.quit
finally:
# 웹크롤링 처리가 모두 완료되면, driver 종료! (가끔 except가 실행 안될 때가 있어서 두번 넣어줌)
driver.quit
웹크롤링 - 데이터 수집 ②페이지 이동
🐤 페이지 전환시 꼭 써야하는 세 줄 코드!!
● 상세페이지로 접근했다라는 정보를 받아오기 (핸들링을 잃어버려서 1건만 작동함)
① 실제 상세페이지에 접근
- window_handles : 페이지가 열릴때마다 리스트타입으로 윈도우 정보를 순서대로 가지고 있는 객체
- [-1]은 마지막에 접근한 페이지를 의미함
- 자바스크립트 : window.history.back() 와 비슷
movie_handle = driver.window_handles[-1]
② 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
③ 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
- time라이브러리 // sleep(초)
time.sleep(1)
🐤 제목 10개만 추출하기
- 가끔 a 태그사이에 공백있는 경우들이 있음 >> strip()
- 마우스로 제목을 클릭하는 행위와 동일한 코드
- click() 이벤트 발생
for i in range(10):
print(f"No[{i}] - title[{movie_elements[i].text.strip()}]")
movie_elements[i].click()
🐤 영화 한편에 대한 정보 수집이 끝나면 다시 메인으로 이동
- execute_script() : 자바스크립트 문법 처리 함수
driver.execute_script("window.history.go(-1)")
time.sleep(1)
최종 코드
- 페이지 전환하면서 영화제목 10개 추출
try:
# 브라우저 컨트롤
driver = webdriver.Chrome()
# url을 이용하여 페이지 접근
driver.get("https://movie.daum.net/ranking/boxoffice/monthly")
### 영화제목이 있는 -> a 태그 위치 경로
movie_path = "#mainContent > div > div.box_boxoffice > ol > li > div > div.thumb_cont > strong > a"
# 현재 크롬브라우저에 보이는 영화제목 모두 추출하기
movie_elements = driver.find_elements(By.CSS_SELECTOR, movie_path)
for i in range(10):
title = movie_elements[i].text.strip()
print(f"No[{i}] - title[{title}]")
### 제목을 클릭 시켜서 상세 페이지로 이동하기
movie_elements[i].click()
### 상세페이지로 접근했다라는 정보를 받아오기 (핸들링을 잃어버려서 1건만 작동함)
movie_handle = driver.window_handles[-1]
# 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
#페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
### 영화 한편에 대한 정보 수집이 끝나면 다시 메인으로 이동
driver.execute_script("window.history.go(-1)")
time.sleep(1)
except Exception as e:
print(e)
# 웹크롤링 처리가 모두 완료되면, driver 종료!
driver.quit
finally:
# 웹크롤링 처리가 모두 완료되면, driver 종료! (가끔 except가 실행 안될 때가 있어서 두번 넣어줌)
driver.quit

웹크롤링 - 데이터 수집 ③평점, 리뷰 추출
🐤 탭 클릭 이벤트 발생 시키기
① [평점] 탭 클릭 이벤트 발생 시키기
tap_score_path= "#mainContent > div > div.box_detailinfo > div.tabmenu_wrap > ul > li:nth-child(4) > a"
② a태그 정보 가지고 오기
tap_score_element = driver.find_element(By.CSS_SELECTOR, tap_score_path)
③ [평점] 탭, 즉 a태그 클릭 이벤트 발생시키기
tap_score_element.click()
🐤 [평점] 페이지로 전환
① [평점] 페이지로 접근했다라는 정보를 받아오기
tap_score_handle = driver.window_handles[-1]
② 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
③ 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
🐤 모든 평점 데이터 추출하기
① [평점] 경로 설정
score_path = "ul.list_comment div.ratings"
② [평점] 데이터 수집
score_lists = driver.find_elements(By.CSS_SELECTOR, score_path)
③ 확인
print(f"평점 갯수 =>> {len(score_lists)}")
print(f"score[0] =>> {score_lists[0].text}")
🐤 모든 리뷰 데이터 추출하기
① [평점] 경로 설정
comment_path = "ul.list_comment p.desc_txt"
② [평점] 데이터 수집
comment_lists = driver.find_elements(By.CSS_SELECTOR, comment_path)
③ 확인
print(f"리뷰 갯수 =>> {len(comment_lists)}")
print(f"comment[0] =>> {comment_lists[0].text}")
🐤 평점을 이용하여 긍정/부정 값 생성하기
● 평점을 이용해서 긍정/부정 데이터 생성
- 긍정 : 평점이 8이상인 경우, 긍정값은 1 사용
- 부정 : 평점이 4이하인 경우, 부정값은 0 사용
- 기타 : 나머지, 기타값은 2 사용
for j in range(len(score_lists)):
### 평점 추출하기
score = score_lists[j].text.strip()
### 리뷰 추출하기
comment = comment_lists[j].text.strip().replace("\n","")
### 라벨링 하기
label = 0
if int(score) >= 8:
label = 1
elif int(score) <= 4:
label = 0
else:
label = 2
### 각 영화별 확인하기
# \t : 탭
print(f"{title} \t{score} \t{label} \t{comment} \n")
최종 코드
- 평점과 리뷰추출
try:
# 브라우저 컨트롤
driver = webdriver.Chrome()
# url을 이용하여 페이지 접근
driver.get("https://movie.daum.net/ranking/boxoffice/monthly")
### 영화제목이 있는 -> a 태그 위치 경로
movie_path = "#mainContent > div > div.box_boxoffice > ol > li > div > div.thumb_cont > strong > a"
# 현재 크롬브라우저에 보이는 영화제목 모두 추출하기
movie_elements = driver.find_elements(By.CSS_SELECTOR, movie_path)
for i in range(10):
title = movie_elements[i].text.strip()
print(f"No[{i}] - title[{title}]")
### 제목을 클릭 시켜서 상세 페이지로 이동하기
movie_elements[i].click()
### 상세페이지로 접근했다라는 정보를 받아오기 (핸들링을 잃어버려서 1건만 작동함)
movie_handle = driver.window_handles[-1]
# 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
#페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
###-------------------------------------------------------
### [평점] 탭 클릭 이벤트 발생 시키기
tap_score_path= "#mainContent > div > div.box_detailinfo > div.tabmenu_wrap > ul > li:nth-child(4) > a"
### a태그 정보 가지고 오기
tap_score_element = driver.find_element(By.CSS_SELECTOR, tap_score_path)
### [평점] 탭, 즉 a태그 클릭 이벤트 발생시키기
tap_score_element.click()
### [평점] 페이지로 접근했다라는 정보를 받아오기
tap_score_handle = driver.window_handles[-1]
### 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
### 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
###-----------------------------------------------------------
### 모든 평점 데이터 추출하기
score_path = "ul.list_comment div.ratings"
score_lists = driver.find_elements(By.CSS_SELECTOR, score_path)
### 모든 리뷰 데이터 추출하기
comment_path = "ul.list_comment p.desc_txt"
comment_lists = driver.find_elements(By.CSS_SELECTOR, comment_path)
###-----------------------------------------------------------
### 평점, 리뷰 추출하기
# 평점을 이용하여 긍정/부정 값 생성하기
for j in range(len(score_lists)):
### 평점 추출하기
score = score_lists[j].text.strip()
### 리뷰 추출하기
comment = comment_lists[j].text.strip().replace("\n","")
label = 0
if int(score) >= 8:
label = 1
elif int(score) <= 4:
label = 0
else:
label = 2
### 각 영화별 확인하기
print(f"{title} \t{score} \t{label} \t{comment} \n")
###-------------------------------------------------------
### 영화 한편에 대한 정보 수집이 끝나면 다시 메인으로 이동
driver.execute_script("window.history.go(-2)")
time.sleep(1)
except Exception as e:
print(e)
# 웹크롤링 처리가 모두 완료되면, driver 종료!
driver.quit
finally:
# 웹크롤링 처리가 모두 완료되면, driver 종료! (가끔 except가 실행 안될 때가 있어서 두번 넣어줌)
driver.quit

웹크롤링 - 데이터 수집 ④파일에 저장하기
🐤 수집데이터 txt파일로 저장시키기
① 파일 저장하기 (자동으로 파일 생성)
f = open("./data/movie_reviews.txt", "w", encoding="UTF-8")
② 파일에 쓰기 (단, 띄어쓰기없이!!! \t를 구분자로 사용)
f.write(f"{title}\t{score}\t{label}\t{comment}\n")
③ 파일 닫기
f.close()
최종 코드
- 파일에 저장하기
try:
# 브라우저 컨트롤
driver = webdriver.Chrome()
# url을 이용하여 페이지 접근
driver.get("https://movie.daum.net/ranking/boxoffice/monthly")
### 영화제목이 있는 -> a 태그 위치 경로
movie_path = "#mainContent > div > div.box_boxoffice > ol > li > div > div.thumb_cont > strong > a"
# 현재 크롬브라우저에 보이는 영화제목 모두 추출하기
movie_elements = driver.find_elements(By.CSS_SELECTOR, movie_path)
###-----------------------------------------------------------
### 수집데이터 txt파일로 저장시키기
f = open("./data/movie_reviews.txt", "w", encoding="UTF-8")
###-----------------------------------------------------------
for i in range(10):
title = movie_elements[i].text.strip()
print(f"No[{i}] - title[{title}]")
### 제목을 클릭 시켜서 상세 페이지로 이동하기
movie_elements[i].click()
### 상세페이지로 접근했다라는 정보를 받아오기 (핸들링을 잃어버려서 1건만 작동함)
movie_handle = driver.window_handles[-1]
# 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
#페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
###-------------------------------------------------------
### [평점] 탭 클릭 이벤트 발생 시키기
tap_score_path= "#mainContent > div > div.box_detailinfo > div.tabmenu_wrap > ul > li:nth-child(4) > a"
### a태그 정보 가지고 오기
tap_score_element = driver.find_element(By.CSS_SELECTOR, tap_score_path)
### [평점] 탭, 즉 a태그 클릭 이벤트 발생시키기
tap_score_element.click()
### [평점] 페이지로 접근했다라는 정보를 받아오기
tap_score_handle = driver.window_handles[-1]
### 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
### 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
###---------------------------------------------------------
### 모든 평점 데이터 추출하기
score_path = "ul.list_comment div.ratings"
score_lists = driver.find_elements(By.CSS_SELECTOR, score_path)
### 모든 리뷰 데이터 추출하기
comment_path = "ul.list_comment p.desc_txt"
comment_lists = driver.find_elements(By.CSS_SELECTOR, comment_path)
###--------------------------------------------------------
### 평점, 리뷰 추출하기
# 평점을 이용하여 긍정/부정 값 생성하기
for j in range(len(score_lists)):
### 평점 추출하기
score = score_lists[j].text.strip()
### 리뷰 추출하기
comment = comment_lists[j].text.strip().replace("\n","")
label = 0
if int(score) >= 8:
label = 1
elif int(score) <= 4:
label = 0
else:
label = 2
### 각 영화별 확인하기
print(f"{title} \t{score} \t{label} \t{comment} \n")
###-------------------------------------------------------
### 파일에 쓰기
f.write(f"{title}\t{score}\t{label}\t{comment}\n")
###--------------------------------------------------------
### 영화 한편에 대한 정보 수집이 끝나면 다시 메인으로 이동
driver.execute_script("window.history.go(-2)")
time.sleep(1)
except Exception as e:
print(e)
# 웹크롤링 처리가 모두 완료되면, driver 종료!
driver.quit
finally:
### 파일 자원 닫기
f.close()
# 웹크롤링 처리가 모두 완료되면, driver 종료! (가끔 except가 실행 안될 때가 있어서 두번 넣어줌)
driver.quit

웹크롤링 - 데이터 수집 ⑤펼치기[더보기] 진행
🐤 [평점] 더보기 버튼을 클릭하여 모두 펼치기
① 펼친 갯수 확인 변수
more_view_cnt = 0
② 모두 펼치기(더보기) 수행 -> 반복문 실행 (있을 때까지 무한 반복시키고 더이상 없으면 오류발생시키기)
while True:
try:
# 1. 경로 가져오기
more_view_path = "#alex-area > div > div > div > div.cmt_box > div.alex_more > button"
more_view_element = driver.find_element(By.CSS_SELECTOR, more_view_path)
# 2. 클릭 이벤트
more_view_element.click()
# 3. 더보기 클릭 후 -> 접근했다라는 정보 받아오기
movie_handle = driver.window_handles[-1]
# 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
# 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
### 임시로 2번만 반복 처리 후 break 처리!!!!
if more_view_cnt == 2:
break
### 더보기 클릭 횟수 확인을 위해 1씩 증가
more_view_cnt += 1
except Exception as e:
### 더이상 더보기 버튼이 보이지 않으면 오류 발생
# 오류 발생 시점이 더보기 버튼이 끝나는 시점
break
③ 더보기 클릭 횟수 확인
print(f"더보기 클릭 횟수 : [{more_view_cnt}]")
④ 평점 또는 리뷰 데이터가 없을 수 있기에 두개 리스트의 갯수 중 작은 값을 사용
- 평점 또는 리뷰가 없으면, 수집에서 제외
for_cnt = 0
if len(score_lists) < len(comment_lists) :
for_cnt = len(score_lists)
elif len(score_lists) > len(comment_lists) :
for_cnt = len(comment_lists)
else :
for_cnt = len(score_lists)
###여기도 수정!!!
for j in range(for_cnt):
최종 코드
- 파일에 저장하기
try:
# 브라우저 컨트롤
driver = webdriver.Chrome()
# url을 이용하여 페이지 접근
driver.get("https://movie.daum.net/ranking/boxoffice/monthly")
### 영화제목이 있는 -> a 태그 위치 경로
movie_path = "#mainContent > div > div.box_boxoffice > ol > li > div > div.thumb_cont > strong > a"
# 현재 크롬브라우저에 보이는 영화제목 모두 추출하기
movie_elements = driver.find_elements(By.CSS_SELECTOR, movie_path)
###------------------------------------------------------------------------------
### 수집데이터 txt파일로 저장시키기
f = open("./data/movie_reviews.txt", "w", encoding="UTF-8")
###------------------------------------------------------------------------------
for i in range(10):
title = movie_elements[i].text.strip()
print(f"No[{i}] - title[{title}]")
### 제목을 클릭 시켜서 상세 페이지로 이동하기
movie_elements[i].click()
### 상세페이지로 접근했다라는 정보를 받아오기 (핸들링을 잃어버려서 1건만 작동함)
movie_handle = driver.window_handles[-1]
# 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
#페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
###--------------------------------------------------------------------
### [평점] 탭 클릭 이벤트 발생 시키기
tap_score_path= "#mainContent > div > div.box_detailinfo > div.tabmenu_wrap > ul > li:nth-child(4) > a"
### a태그 정보 가지고 오기
tap_score_element = driver.find_element(By.CSS_SELECTOR, tap_score_path)
### [평점] 탭, 즉 a태그 클릭 이벤트 발생시키기
tap_score_element.click()
### [평점] 페이지로 접근했다라는 정보를 받아오기
tap_score_handle = driver.window_handles[-1]
### 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
### 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
###--------------------------------------------------------------------
### [평점] 더보기 버튼을 클릭하여 모두 펼치기
### 1. 펼친 갯수 확인 변수
more_view_cnt = 0
### 2. 모두 펼치기(더보기) 수행 -> 반복문 실행
while True:
try:
# 1. 경로 가져오기
more_view_path = "#alex-area > div > div > div > div.cmt_box > div.alex_more > button"
more_view_element = driver.find_element(By.CSS_SELECTOR, more_view_path)
# 2. 클릭 이벤트
more_view_element.click()
# 3. 더보기 클릭 후 -> 접근했다라는 정보 받아오기
movie_handle = driver.window_handles[-1]
# 새로 열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
# 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
### 임시로 2번만 반복 처리 후 break 처리
if more_view_cnt == 2:
break
### 더보기 클릭 횟수 확인을 위해 1씩 증가
more_view_cnt += 1
except Exception as e:
### 더이상 더보기 버튼이 보이지 않으면 오류 발생
# 오류 발생 시점이 더보기 버튼이 끝나는 시점
break
### 더보기 클릭 횟수 확인
print(f"더보기 클릭 횟수 : [{more_view_cnt}]")
###------------------------------------------------------------------
### 모든 평점 데이터 추출하기
score_path = "ul.list_comment div.ratings"
score_lists = driver.find_elements(By.CSS_SELECTOR, score_path)
### 모든 리뷰 데이터 추출하기
comment_path = "ul.list_comment p.desc_txt"
comment_lists = driver.find_elements(By.CSS_SELECTOR, comment_path)
###----------------------------------------------------------------
### 평점, 리뷰 추출하기
# 평점을 이용하여 긍정/부정 값 생성하기
for j in range(len(score_lists)):
### 평점 추출하기
score = score_lists[j].text.strip()
### 리뷰 추출하기
comment = comment_lists[j].text.strip().replace("\n","")
label = 0
if int(score) >= 8:
label = 1
elif int(score) <= 4:
label = 0
else:
label = 2
### 각 영화별 확인하기
print(f"{title} \t{score} \t{label} \t{comment} \n")
###-------------------------------------------------------------------
### 파일에 쓰기
f.write(f"{title}\t{score}\t{label}\t{comment}\n")
###--------------------------------------------------------------------
### 영화 한편에 대한 정보 수집이 끝나면 다시 메인으로 이동
driver.execute_script("window.history.go(-2)")
time.sleep(1)
except Exception as e:
print(e)
# 웹크롤링 처리가 모두 완료되면, driver 종료!
driver.quit
finally:
### 파일 자원 닫기
f.close()
# 웹크롤링 처리가 모두 완료되면, driver 종료! (가끔 except가 실행 안될 때가 있어서 두번 넣어줌)
driver.quit


'Back-End > 데이터베이스' 카테고리의 다른 글
[DB] 워드클라우드 시각화 - KoNLPY, Okt, Counter, WordCloud (6) | 2023.12.05 |
---|---|
[DB] 데이터 전처리 및 시각화 - 웹크롤링(selenium), 점(분포) 그래프, 원형 그래프 (10) | 2023.12.04 |
[DB] 데이터베이스 실습 - 버스교통카드 데이터 전처리 시각화(히트맵, 막대그래프, 선그래프) (2) | 2023.11.30 |
[DB] 데이터베이스 실습 - 버스교통카드 데이터 수집 가공 (0) | 2023.11.29 |
[DB] 데이터베이스 연결 - pymysql 라이브러리 사용 (3) | 2023.11.29 |