728x90
반응형

영화 데이터수집 웹크롤링

크롤링 Crawling
소프트웨어 따위가 웹을 돌아다니며 유용한 정보를 찾아 특정 데이터베이스로 수집해 오는 작업. 또는 그러한 기술

다음 영화 사이트 웹크롤링

  • URL : http://movie.daum.net
  • 다음영화 > 랭킹 > 박스오피스 > 월간 위치의 데이터 수집
  • 수집데이터 : 영화제목, 평점, 댓글
  • 생성할 데이터 : 긍정/부정 ( 별점 점수 별 긍정인지 부정인지 판단하는 데이터 생성 )
  • 프로그램에서 https://movie.daum.net/ranking/boxoffice/monthly 주소를 열어서 크롬에서 제어

웹크롤링 라이브러리

  • 정적인 웹크롤링을 할 경우
    • BeautifulSoup : 하나의 페이지에 보이는 부분만 수집할 때 사용
  • 동적인 웹크롤링을 할 경우
    • selenium : 클릭과 같은 이벤트 등 페이지 전환을 하면서 수집할 때 사용
  • 동적 웹페이지 처리를 위한 라이브러리
    • Prompt에서 설치 필요 : pip install selenium
    • from selenium import webdriver
    • webdriver : 브라우저 자체를 컨트롤 함
  • 웹페이지 내에 데이터 추출을 위한 라이브러리
    • from selenium.webdriver.common.by import By
    • By : 페이지 안에 있는 html을 컨트롤 함
  • 시간 라이브러리
    • import time
    • 웹브라우저에 접근 할 때 페이지에 클릭이라는 동적 이벤트를 발생시킨다. 이때  네트워크 사양에 따라 느리게 실행 될 수 있고  다른 pc보다 빠르게 실행 될 수 있다. 즉, 사양에 따라 페이지 로딩 시간이 다르게 나타난다다. 그 로딩시간에 다른 행동을 하지 못하도록 즉, 외부에서 읽어들일 수 있는 시간을 주기 위해 time 사용

1. 크롬 브라우저 띄우기

  • 브라우저 컨트롤
driver = webdriver.Chrome()
  • url을 이용하여 페이지 접근
    • get() : 페이지에 접근 후 해당 html 코드 읽어 들이기
    • driver 객체가 모든 정보를 가지고 있음
driver.get("https://movie.daum.net/ranking/boxoffice/monthly")

 

2. 제목이 있는 부분의 html 태그 경로(패스) 추출하기

  • 크롬브라우저 → F12(개발자도구) → 영화제목 마우스 우클릭 → [검사] 클릭 → a 태그에 마우스 위치 후 우클릭 → copy → copy selector 클릭 → 해당 제목의 위치 저장

  • 영화 제목이 있는 a 태그 위치 경로 확인
    • li:nth-child(1)에서 :nth-child(1) 이걸 빼면 ol아래 모든 li가 해당 된다.
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로 처리하기
try:
    driver = webdriver.Chrome()

    driver.get("https://movie.daum.net/ranking/boxoffice/monthly")

    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)
    print(f"movie_elements length = {len(movie_elements)}")
    print(f"title[0] =>> {movie_elements[0].text}")
    print(f"movie_elements(제목) = {movie_elements}")

except Exception as e:
    print(e)
    driver.quit()

finally:
    driver.quit()

 

 

3. Click ( ) 이벤트 발생시키기 (1) - 상세 페이지

아래 코드는 모두 for i 문 안에 작성된 코드

  • 제목을 클릭 시켜서 상세 페이지로 이동하기
    • 마우스로 제목을 클릭하는 행위와 동일한 코드
    • click() 이벤트 발생
# 제목 10개만 추출하기
    for i in range(10) : 
        title = movie_elements[i].text.strip()
        print(f"No[{i}] / title[{title}] Start----------------")

        ### 제목을 클릭 시켜서 상세 페이지로 이동하기
        movie_elements[i].click()

 

  • 상세페이지로 접근했다라는 정보를 받아오기
    • 실제 상세페이지에 접근
    • window_handles : 페이지가 열릴때 마다 리스트타입으로 윈도우 정보를 순서대로 가지고 있는 객체이다. -1 은 마지막에 접근한 페이지를 의미한다.
      movie_handle = driver.window_handles[-1]
        # - 새로 열린 페이지로 전환하기
        driver.switch_to.window(movie_handle)

 

  • 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)

 

→ 여기까지 실행하면 웹 페이지 열리고 영화 '서울의 봄' 상세페이지까지 들어갔다가 종료됨


4. Click ( ) 이벤트 발생시키기 (2) - [평점] 

  • [평점] 탭 클릭 이벤트 발생 시키기

   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_handle = driver.window_handles[-1]
        # - 새로 열린 페이지로 전환하기
        driver.switch_to.window(tap_score_handle)

 

  • 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
        time.sleep(1)

 

5. 모든 평점 / 리뷰 데이터 추출하기

  • 모든 평점 데이터 추출하기
        score_path = "ul.list_comment div.ratings"
        score_lists = driver.find_elements(By.CSS_SELECTOR, score_path)
        print(f"평점 갯수 : {len(score_lists)}")

 

  • 모든 리뷰 데이터 추출하기
        comment_path = "ul.list_comment p.desc_txt"
        comment_lists = driver.find_elements(By.CSS_SELECTOR, comment_path)
        print(f"리뷰 갯수 : {len(comment_lists)}")

 

6. 평점을 이용하여 긍정 / 부정 값 생성하기

  • 평점 또는 리뷰 데이터가 없을 수 있기에 두개 리스트의 갯수 중 작은 값을 사용
  • 평점 또는 리뷰가 없으면, 수집에서 제외
  • 기존의  for j in range(len(score_lists))으로 for문을 돌릴 때, 리뷰가 없을 경우 len(comment_lists)는  len(score_lists)와 길이가 다르기 때문에 오류가 난다.
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 문 안에 작성된 코드

  • 평점, 리뷰 추출하기
 for j in range(for_cnt) : 
            ### 평점 추출하기
            score = score_lists[j].text.strip()
            
            ### 리뷰 추출하기
            comment = comment_lists[j].text.strip().replace("\n", "")
            
            print(f"{title}  \t{score}  \t{comment} \n")

 

  • 평점을 이용해서 긍정/ 부정 데이터 생성
    • 긍정 : 평점이 8이상인 경우로, 긍정값은 1 사용
    • 부정 : 평점이 4이하인 경우로, 부정값은 0 사용
    • 기타 : 나머지, 기타값은 2 사용
   label = 0
            if  int(score) >= 8 :
                label = 1
            elif int(score) <= 4 :
                label = 0
            else :
                label = 2
                
    print(f"{title}  \t{score}  \t{comment} \t{label} \n")

 

7. 다시 메인으로 이동

아래 코드는 for j 문 밖에 작성된 코드

  • 영화 한편에 대한 정보수집이 끝나면 다시 메인으로 이동
  • execute_script() : 자바스크립트 문법 처리 함수
	driver.execute_script("window.history.go(-2)")
        time.sleep(1)

 

→ 여기까지 실행하면 영화 10개의 제목, 평점, 리뷰, 긍정/부정 데이터가 출력된다

 

8. 수집 데이터 저장하기

  • 수집데이터 txt 파일로 저장시키기 ( 아래 코드는 for i 문 위에 작성된 코드)
 f = open("./data/movie_reviews.txt", "w", encoding="UTF-8")
  • 파일에 쓰기  ( 아래 코드는 for j문 에 작성된 코드)
  f.write(f"{title}\t{score}\t{comment}\t{label}\n")
  • 파일 자원 닫기 (아래 코드는 except 문에 작성된 코드)
f.close()

9. 모두 펼치기(더보기) 수행한 뒤 데이터 추출

아래 코드는 for i 문 안에서 모든 평점 데이터 추출하기 전에 작성된 코드

  • [평점] 더보기 버튼 클릭하여 모든 평점 보이게 펼치기
  • 처음에 실행했다가 오류난 이유는 영화의 평점 중에 리뷰가 적히지 않은게 있었음. 6번으로 가서  if 문 추가.
	### - 펼친 갯수 확인 변수
        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()
                
                ### 상세페이지로 접근했다라는 정보를 받아오기
                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}]")

 

→ 여기까지 실행하면 영화 10개의 제목과  더보기를 눌러 모두 펼쳤을 때의 평점, 리뷰, 긍정/부정 데이터가 출력된다

728x90
반응형

+ Recent posts