또자의 코딩교실

[스마트인재개발원]-1차 프로젝트를 진행하며-(2) 본문

코딩공부/프로젝트 진행

[스마트인재개발원]-1차 프로젝트를 진행하며-(2)

또자자 2021. 11. 16. 22:37

썸네일

기획 발표 이후, 1차 프로젝트는 DB요구사항 정의서와 역할 최종분 배 사항을 정해 DB멘토링을 받는다.

 

그다음부터의 프로젝트 진행사항은 테이블 명세서와 요구사항 정의서와 함께 진행된다.

우리 조는 전문가 선생님께서 봐주셨는데, IT업계에는 DB설계를 맡는 사람은 그 분야에서의 최고 숙련자가

보통 맡는 직무라고 한다. 왜냐하면 모든 프로그래밍 지식이 기반이 되어있어야 DB에서 데이터가 쓰이는

부분과 보다 효율적인 배치를 할 수 있기 때문이다. 

 

나 또한 그 말을 절절히 느낄 수 있었다. 우리 조가 2주간 열심히 머리를 싸매고 생각한 기능을 테이블 명세서에

적어갔었을 때, 우리조의 테이블 명세서를 읽어보시고는, 필요한 기능에 맞춰 테이블들의 구조를

일목요연하게 정리하고 요약하시는 것을 보며 신기하고 놀라운 감정을 느낄 수 있었다. 

 

 

 

요구사항 정의서
DB테이블 명세서. 필요한 데이터들의 내용과 테이블간의 관계를 기술한다.

 

멘토님께서는 Aquerytool이라는 서비스를 활용하여 데이터의 시각화에 특화된 웹 DB설계 툴을 이용하여 멘토링을 진행하셨다.

 

멘토링 결과로 나오는 ERD. DB data table과 참조되는 Pk와 Fk의 관계또한 알기쉽게 나올 수 있다.

 

멘토링 이후 ERD로 한눈에 DB를 확인할 수도 있지만, Aquerytool에서 MySQL Workbench에 적용 가능하도록 바로 테스트 데이터와 생성 query문 또한 export 할 수 있었다. DB멘토링 이후, 우리 팀은

각각 홈페이지 프런트엔드 HTML/CSS 디자인 팀과 크롤링 데이터 수집팀으로 나뉘어 작업을 진행했다.

 

HTML/CSS팀은 인터넷에 copyright free HTML Templete을 사용해 css를 수정하며 홈페이지의 기틀을 닦기 시작했다.

그리고 데이터 수집팀은 Python Jupyter Notebook에서 크게 네이버 영화 페이지와 다음 영화 페이지, 개봉 예정작들과 종료 예정작들의 정보들을 크롤링하기 시작했다. 

 

네이버 영화 리뷰 페이지 크롤링하기

 

Lib로는 pandas, selenium, beautiful Soup, tqdm 등을 사용했다. 각각 표 형태의 데이터를 다루는 라이브러리, 응답받은 문서를 파싱 하는 라이브러리, 현재 진행 현황을 시각화시켜주는 라이브러리 등을 설치했다. 

 

네이버 영화 세부 iframe 영화 리뷰 사이트

크롤링해야 하는 사이트. iframe의 형태로 리뷰들이 등록되어 있어 선택자의 혼동을 줄이기 위해

iframe의 원본 사이트를 크롤링할 것이다.

크롤링의 단계는 이렇다. 

1. Selenium Web Driver로 chrome을 지정한다.
<while문>
2. while 반복문에 크롤링 코드를 작성한다. 더 이상 페이지가 없으면 에러를 띄워 멈추도록 하게 위함이다. 
3. movie_code함수를 지정한다.
4. page_id 변수는 각 페이지별 고유 id와 page_num을 통해 code 내부에 들어갈 경로를 지정한다. 각 페이지의 url의 이동할 쿼리 스트링(세부 경로)을 지정한다.
5. BASE_URL = 'https://movie.naver.com/movie/bi/mi/pointWriteFormList.naver?code={}&type=after&onlyActualPointYn=Y&onlySpoilerPointYn=N&order=sympathyScore&page='.format(movie_code)
6. 네이버 영화 주소의 BASE_URL에 movie_code를 문자열 포맷팅 시킨다.  movie_code는 네이버 영화 페이지에서 주소창의 쿼리 스트링에서 가져오는 식으로 movie_code만 변경하여 영화를 변경하고 크롤링한다.

<for문>
7. 각 페이지당 10개의 댓글을 가져온다.
8. html에서 리뷰의 선택자를 가져오고 댓글 부분을 추출하되 한글이 아닌 데이터는 삭제한다. 이후 모아진 댓글 데이터는 content list에 append 한다.
9. html에서 리뷰에 매긴 평점의 선택자를 가져오고 star_score list에 append 한다. 
10. 모든 append과정이 끝나면 page_num을 변수에 누적 증가시켜 while문에서 페이지가 없을 때까지 크롤링을 진행한다.
</for문>
</while문>

<def 사용자 지정 함수>
11. 별점의 7점을 기준으로 7점 이상일 경우 1(=긍정)이란 결괏값을 change_star list에 append 한다. 미만일 경우에는 0(=부정)이란 결과값을 change_star list에 append한다. 
12. 
</def 사용자 지정 함수>

<결과 확인 count문>
13. change_star list에 count함수를 사용하여 1(=긍정)의 결괏값을 전체 비율에 맞춰 퍼센트를 매긴다. 
14. 퍼센트가 70% 이상일 경우 print("긍정")
</결과 확인 count문>

<DataFrame 생성 및 CSV 파일로 저장>
15. column에 들어갈 변수들의 이름을 지정한다.
16. 15번에서 만든 리스트를 column에 넣어주고 pandas라이브러리를 이용해 DataFrame을 생성한다.
17. data_frame.to_csv 함수를 이용해 DataFrame을 CSV 파일로 export한다. 한글 인코딩은 필수이다.
</DataFrame 생성 및 CSV파일로 저장>
from selenium import webdriver as wb
from selenium.webdriver.common.by import By 
import time 
import pandas as pd 
import re 
#url 
!pip install requests
!pip install bs4
!pip install tqdm

import requests as req
# requests 모듈은 서버에 요청을 보내는 라이브리
from bs4 import BeautifulSoup as bs # 응답받은 문서를 파싱하는 라이브러리
import pandas as pd # 표 형태의 데이터를 다루는 라이브러리
pd.set_option('display.max_colwidth', None) #컴럼의 너버 제약해제
from tqdm import tqdm # 반족 진행 현황을 시각화 시켜주는 라이브러리

#ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

movie_code = 204768 ##여기만 영화 쿼리스트링에 맞춰 변경

#ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
BASE_URL = 'https://movie.naver.com/movie/bi/mi/pointWriteFormList.naver?code={}&type=after&onlyActualPointYn=Y&onlySpoilerPointYn=N&order=sympathyScore&page='.format(movie_code)

page_num = 1
id = 'pagerTagAnchor' #각 페이지별 고유 id 
driver = wb.Chrome()
star_score=[] #별점이 들어갈 List
content = [] #댓글이 들어갈 List 



while True: #무한루프
     #try except에 넣은 이유는 더이상 페이지가 없으면 에러를 띄워 멈추도록 하기위해서임
    try: 
        URL = BASE_URL+str(page_num) #url과 page_num 을 통해 각 페이지의 url 을 만들어줌
        page_id = id + str(page_num) 
        driver.get(URL) #크롬드라이버 사용
        driver.find_element(By.ID,page_id)#find가 실패하면 페이지가 없는것이므로 error 발생 break 

        for num in range(10): #각페이지에 10개의 댓글이있음 
            id_name='_filtered_ment_'+str(num) #id 의 id값
            comment = driver.find_element_by_id(id_name).text #댓글부분 추출 
            comment = re.sub('[^ㄱ-ㅎㅏ-ㅣ가-힣 ]','',comment) #한글을 제외하고 삭제 
            if comment != '': #삭제를 했을때 공백이 아니라면 list 에 추가 
                content.append(comment) 
                star_score.append(int(driver.find_element_by_css_selector('body > div > div > div.score_result > ul > li:nth-child('+str(num+1)+') > div.star_score > em').text)) #별점도 list 에 추가 
        
        page_num+=1 #페이지 번호 1 상승 
#         print(page_num)


    except: 
        break 
driver.quit() 

def star_score_eval(star_score): #별점을 통해 긍정부정 판단해주기
    change_star = [] 
    for star in star_score: 
        if star >= 7: #7점 이상인경우 
            change_star.append(1)
        else: #7점 미만인경우
            change_star.append(0)
    print(change_star)
    return change_star 
change_star = star_score_eval(star_score)
replys = list(zip(star_score,content,change_star)) 

c1=change_star.count(1)

c2=change_star.count(0)

c3=(c1 / (c1+c2))*100

if(c3>=70):
    print("긍정")
else:
    print("부정")
    
#pandas 를 사용해서 csv 파일로 만들어주기
col = ['star_score','document','label'] 
data_frame = pd.DataFrame(replys, columns=col) 
data_frame.to_csv('data.csv',sep=',',header=True, encoding="euc-kr")
print('work it')
display(data_frame)

# change_star의 1의 갯수 / 163 * 100 >= 70 >> print 긍정

c1=change_star.count(1)

c2=change_star.count(0)

c3=(c1 / (c1+c2))*100

new_list = []
if(c3>=70):
    
    new = "긍정"
    #print("긍정")
else:
    
    new = "부정"
    #print("부정")

new_list = ['0','0']
new_list.append(new)

cname = ['star_score','document','label']
pdf3 = pd.DataFrame([new_list],columns=cname)                     
data_frame=data_frame.append(pdf3,ignore_index=True)

display(data_frame)

data_frame.to_csv('그린나이트.csv',sep=',',header=True, encoding='euc-kr')

 

이런 식으로 네이버 영화의 크롤링을 진행했다. 다음은 다음 영화사이트 현재 상영 중인 영화 사이트의 크롤링이다.

 

이 사이트를 크롤링 할 예정이다.

 

크롤링의 단계는 이렇다. 

1. Selenium Web Driver로 chrome을 지정한다.
2. daum 영화 사이트 중 현재 상영중인 영화의 주소를 가져오고 제목의 선택자를 지정한 변수를 지정한다.
+) range는 상영 중인 영화 중 (약 54개) 중 크롤링할 영화의 개수를 지정한다. 현재는 코드의 실행 부담을 덜기 위해 2개로 설정해 놓은 상태이다. 
<for문>
3. 다음 영화에는 현재 상영 중인 제목에 href로 영화 상세보기 페이지를 들어갈 수 있다. 해당하는 선택자를 지정한 후 클릭시킨다.
4. 탭 중 3번째의 리뷰와 평점이 적힌 탭에 해당하는 선택자를 지정한 후 클릭시킨다. 
<try&except문>
5.  더 이상 출력해야 할 댓글 데이터가 없으면 에러를 띄워 멈추도록하게 위해 try&except문을 사용했다. 현재 페이지는 리뷰와 평점이 적힌 탭에 들어가 있는 상태이다. 
6. 페이지 내에서 body태그 내에서 전체 리뷰들을 모두 크롤링하기 위해 pagedown을 누르면서 내용을 탐색한 후 더보기 버튼에 해당하는 선택자를 지정한 후 클릭시킨다. 
7. 더이상 출력해야할 댓글 데이터가 없을 경우 print("완료")
</try&except문>

8. 이후 원하는 데이터가 모두 표시된 웹페이지에서 파싱을 진행한 후, re_list에 리뷰 내용을 append 한다. for문을 활용하여 re값(=실질적인 리뷰 내용)을 append한다.  
9. for문에서 지정했던 딕셔너리에 title을 키값으로 만들고 value값에 re_list값을 넣는다. 
10. 이후 딕셔너리를 Pandas 라이브러리를 활용하여 DataFrame으로 만든 뒤, CSV 파일 형태로 저장한다. 
</for문>
from bs4 import BeautifulSoup as bs
from selenium import webdriver as wb
from selenium.webdriver.common.keys import Keys
import time
import pandas as pd

driver = wb.Chrome()
time.sleep(0.7)
driver.get("https://movie.daum.net/premovie/theater")
time.sleep(0.7)
movie = driver.find_elements_by_css_selector("a.link_txt")

cnt = 0
for i in range(2) :
    dic = {}
    cnt = cnt+1
    time.sleep(1)
    driver.find_elements_by_css_selector("a.link_txt")[i].click()
    time.sleep(1)
    driver.find_element_by_css_selector("div.tabmenu_wrap > ul > li:nth-child(4) > a > span").click()
    try :
        for i in range(2) :
            time.sleep(2)
            body = driver.find_element_by_tag_name("body")
            body.send_keys(Keys.PAGE_DOWN)           
            body.send_keys(Keys.PAGE_DOWN)           
            time.sleep(1)
            more = driver.find_element_by_css_selector("button.link_fold")
            time.sleep(1)
            more.click()
        
    except :
        print("완료")

    title = driver.find_element_by_css_selector("h3 > span.txt_tit").text
    re = driver.find_elements_by_css_selector("li > div > p")
    re_list = []
    for i in re :
        re_list.append(i.text)

    dic[title] = re_list
    csvData = pd.DataFrame(dic)
    time.sleep(1)
    csvData.to_csv("review"+str(cnt)+".csv", encoding = "utf-8-sig")
    time.sleep(1)
    csvData = ""
    time.sleep(1)
    driver.back()
    driver.back()
    time.sleep(1)

 

이상으로 크롤링에 사용했던 코드들을 다시 짚어보았다. 다음 시간에는 실질적으로 DB에 크롤링한 파이썬 데이터들을 json 확장자로 DB에 추가하는 과정과 HTML/CSS의 기본 뼈대들에 관하여 포스팅하겠다. 

Comments