크롤링(crawling) | 시각화
[웹 크롤링(web crawling)] 영화데이터수집
멈머이
2023. 12. 4. 22:49
728x90
크롤링(crawling)
웹상에 존재하는 데이터들을 수집하는 작업
(프로그래밍으로 자동화)
- 웹 페이지의 html 코드를 가져와서, HTML/CSS 등을 필요한 데이터만 추출하는 기법
- Open API(Rest API)를 제공하는 서비스에 Open API를 호출해서, 받은 데이터 중 필요한 데이터만 추출하는 기법
- Selenium 등 브라우저를 프로그래밍으로 조작해서, 필요한 데이터만 추출하는 기법
<다음 영화 사이트 웹크롤링>
- URL : https://movie.daum.net
- 다음영화 > 랭킹 > 박스오피스 > 월간 위치의 데이터 수집
- 수집데이터 : 영화제목, 평점, 댓글
- 생성할 데이터 : 긍정/부정
- 고려할 상황 : 평점에서 한 화면에서 보여주는 평점의 수가 10이다.
10 이상은 "평점 더 보기" 버튼을 눌러주어야 한다.
<웹크롤링 라이브러리>
* 정적페이지 * 동적페이지
BeautifulSoup selenium
하나의 페이지에 보이는 클릭과 같은 이벤트 등 페이지
부분만 수집할 때 사용 전환을 하면서 수집할 때 사용
# 동적 웹페이지 처리를 위한 라이브러리
from selenium import webdriver
# 웹페이지 내에 데이터 추출을 위한 라이브러리
from selenium.webdriver.common.by import By
# 시간 라이브러리 추가 브라우저가 로딩되는시간동안 시간을 기다려주기 위해
import time
- 설치 필요 : pip install selenium
try:
### 크롬브라우저 띄우기
# - 브라우저 컨트롤
driver = webdriver.Chrome()
### url을 이용하여 페이지 접근
# - get() : 페이지에 접근 후 해당 html코드 읽어 들이기
# - driver 객체가 모든정보를 가지고 있음
driver.get("https://movie.daum.net/ranking/boxoffice/monthly")
### 제목이 있는 부분의 html태그 경로(패스) 추출하기
# - 크롬브라우저 -> f12 -> 영화제목마우스우클륵 -> [검사]클릭 ->
# a태그에 마우스 위치 후 우클릭 -> copy -> copy selector 클릭
# - 해당 제목의 위치에 저장 됨
### 영화제목이 있는 a태그 위치 경로
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)
### ----------------------------------------------------------------------------------
### 수집데이터를 txt파일로 저장시키기
f = open("./data/movie_reviews.txt", "w", encoding="UTF-8")
# ------------------------------------------------------------------------------------
### 제목 10개만 추출하기
for i in range(10):
title = movie_elements[i].text.strip() # strip() : 공백제거
print(f"title[{i}] >>>> title[{title}]")
### 제목을 클릭시켜서 상세페이지로 접근
# - click() 이벤트 발생
movie_elements[i].click()
### 상세 페이지로 접근했다라는 정보를 받아오기
# - 실제 상세페이지에 접근
# - window_handles : 페이지가 열릴때 마다 리스트 타입으로 윈도우 정보를 순서대로 가지고 있는 객체
# -1은 마지막 접근한 페이지를 의미함
movie_handle = driver.window_handles[-1]
# - 새로열린 페이지로 전환하기
driver.switch_to.window(movie_handle)
# 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
### -----------------------------------------------
###[평점] 탭 클릭 이벤트 발생새키기
tab_score_path="#mainContent > div > div.box_detailinfo > div.tabmenu_wrap > ul > li:nth-child(4) > a"
### a태그 정보 가져오기
tab_score_element = driver.find_element(By.CSS_SELECTOR, tab_score_path)
### [평점] 탭, 즉 a태그 클릭이벤트 발생시키기
tab_score_element.click()
tab_score_handle = driver.window_handles[-1]
# - 새로열린 페이지로 전환하기
driver.switch_to.window(tab_score_handle)
# 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
### -------------------------------------
### [평점] 더보기 보튼을 클릭하여 모두 펼치기
# - 펼친 갯수 확인 변수
more_view_cnt = 0
### 모두 펼치기(더보기) 수행
while True:
try:
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)
more_view_element.click()
### 상세 페이지로 접근했다라는 정보를 받아오기
more_view_handle = driver.window_handles[-1]
# - 새로열린 페이지로 전환하기
driver.switch_to.window(more_view_handle)
# 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)
### 더보기 클릿 횟수 확인을 위해 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)
### ---------------------------------------------------------------------
### 평점, 리뷰 추출하기
### 평점을 이용하여 긍정/부정값 생성하기4
### 평점 또는 리뷰데이터가 없을 수 있기에 두개 리스트의 갯수 중 작은 값을 사용
### 평점 또는 리뷰가 없으면, 수집에서 제외
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):
### 평점추출하기
score = score_lists[j].text.strip()
### 리뷰 추출하기
comment = comment_lists[j].text.strip().replace("\n", "")
### 평점을 이용하여 긍정 / 부정 데이터 생성
# - 긍정 : 평점이 8이상인 경우로, 긍정값은 1사용
# - 부정 : 평점이 4이하인 경우로 , 부정값은 0사용
# - 기타 : 나머지, 기타값은 2 사용
lable = 0
if int(score) >= 8:
lable = 1
elif int(score) <= 4:
lable = 0
else:
lable = 2
### 각 영화별 확인하기
print(f"{title} \t{score} \t{comment} \t{lable} \n")
### 파일에 쓰기
f.write(f"{title}\t{score}\t{comment}\t{lable}\n")
# tab으로 구분한 이유 : 댓글안에 , 가 있으면
### --------------------------------------------------------------------------------
### 영화 한편에 대한 정보 수집이 끝나면 다시 메인으로 이용
driver.execute_script("window.history.go(-2)")
time.sleep(1)
except Exception as e:
print(e)
### 파일 자원 닫기
f.close()
### 웹크롤링 처리가 모두 왼료되면, driver를 꼭 종료해야 한다.
driver.quit()
finally:
### 파일 자원 닫기
f.close()
### 웹크롤링 처리가 모두 왼료되면, driver를 꼭 종료해야 한다.
driver.quit()
결과 :
.
.
.
728x90