1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | import time from time import sleep import re from tqdm import tqdm from random import randint import requests from bs4 import BeautifulSoup as bs import random import json import csv from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By watcha_url = 'https://watcha.com/ko-KR/contents/mdRL9gW/comments' #친절한 금자씨 코멘트 주소 headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; InteSl Mac O X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} response = requests.get(watcha_url,headers= headers) #왓챠에서 친절한 금자씨 크롤링할 예정임! #로그인하고 하는 과정은 수동으로 했음. #왓챠는 robots.txt해본결과 크롤링 가능! browser = webdriver.Chrome() browser.get(watcha_url) # Get scroll height last_height = browser.execute_script("return document.body.scrollHeight") ## 스크롤 down하는건 구글링해서 코드를 참조했고 출처 링크! while True: # Scroll down to bottom browser.execute_script("window.scrollTo(0, document.body.scrollHeight);") # Wait to load page time.sleep(0.5) # Calculate new scroll height and compare with last scroll height new_height = browser.execute_script("return document.body.scrollHeight") if new_height == last_height: break last_height = new_height #출처 : https://cnpnote.tistory.com/entry/PYTHON-%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%97%90%EC%84%9C-selenium-webdriver%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-%EC%9B%B9-%ED%8E%98%EC%9D%B4%EC%A7%80%EB%A5%BC-%EC%8A%A4%ED%81%AC%EB%A1%A4%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C sub = browser.find_elements_by_css_selector('#root > div > div.css-d3s16q-NavContainer.ebsyszu0 > section > section > div > div > div > ul > div ') # Comment_sub로 평점 및 평가가 모두 들어간 데이터 자료! # 일단 이걸 다 긁어 온 다음에 여기서 평점과 평가를 같이 추출할 생각 grad_list =[] comment_list =[] from tqdm import tnrange for item in sub: #평점이 없으면 그냥 None을 달고 아니면 평점을 넣기 try: grad_list.append(item.find_element_by_css_selector('div > div.css-6j702-TitleContainer.e1oskw6f1 > div.css-1eyufz5-UserActionStatus.e1oskw6f4 > span')) except: grad_list.append(None) try: comment_list.append(item.find_element_by_css_selector('div.css-103yoki-TextBlock.e1oskw6f3 > div > span')) except: comment_list.append(None) list_5 = [] list_4 = [] list_3 = [] list_2 = [] list_1 = [] # 각 별점별 리스트 5는 4.5~ 5점 # 4는 3.5~4점같은식이다. from tqdm import tnrange for i in tnrange(len(sub)): if grad_list[i] != None: if grad_list[i].text == '5.0' or grad_list[i].text =='4.5': list_5.append(comment_list[i].text) elif grad_list[i].text == '4.0' or grad_list[i].text =='3.5': list_4.append(comment_list[i].text) elif grad_list[i].text == '3.0' or grad_list[i].text =='2.5': list_3.append(comment_list[i].text) elif grad_list[i].text == '2.0' or grad_list[i].text =='1.5': list_2.append(comment_list[i].text) elif grad_list[i].text == '1.0' or grad_list[i].text =='0.5': list_1.append(comment_list[i].text) import numpy as np import pandas as pd from konlpy.tag import * twitter = Okt() komoran = Komoran() kkma = Kkma() hannanum = Hannanum() print(len(list_1)) print(len(list_2)) print(len(list_3)) print(len(list_4)) print(len(list_5)) #1 2는 너무 작으므로 쓰지 않기로 결정 # list_3 4 5만으로 분석해봐야겠다. 그런데 지금생각해보면 그냥 1 2 3을 묶어서 했어도 괜찮았을 듯! twitter = Okt() # 조사 부분 제거 코드는 그대로 쓰되, 구두점도 같이 제거, 실제 구두점도 넣어서해보면 결과가 왜곡됨. def make_corpus_rm_stopwords(text): corpus = [] for s in text.split('\n'): corpus.append(['/'.join(p) for p in twitter.pos(s) if (p[1] != "Josa") and (p[1] != "Punctuation")]) return corpus from tqdm import tqdm corpus_3= [] corpus_4= [] corpus_5= [] for i in range(len(list_3)): temp = make_corpus_rm_stopwords(list_3[i]) for item in temp: corpus_3.append(item) for i in range(len(list_4)): temp = make_corpus_rm_stopwords(list_4[i]) for item in temp: corpus_4.append(item) for i in range(len(list_5)): temp = make_corpus_rm_stopwords(list_5[i]) for item in temp: corpus_5.append(item) # 각 별점별로 말꾸러미 만드는 코드! from gensim.models import Word2Vec, FastText import matplotlib.pyplot as plt from sklearn.manifold import TSNE # tsne로 만들어서 plot하는 코드.. 이건 구글링해서 출처 표시! # tsne로 만든 이유는 단어의 관계를 보기에 가장 적합한 것이라고 생각했기 때문. def tsne_plot(model): "Creates and TSNE model and plots it" labels = [] tokens = [] for word in model.wv.vocab: tokens.append(model[word]) labels.append(word) tsne_model = TSNE(perplexity=40, n_components=2, init='pca', n_iter=2500, random_state=23) new_values = tsne_model.fit_transform(tokens) plt.rc('font', family='NanumGothic') x = [] y = [] for value in new_values: x.append(value[0]) y.append(value[1]) plt.figure(figsize=(16, 16)) for i in range(len(x)): plt.scatter(x[i],y[i]) plt.annotate(labels[i], xy=(x[i], y[i]), xytext=(5, 2), textcoords='offset points', ha='right', va='bottom') plt.show() #https://www.kaggle.com/jeffd23/visualizing-word-vectors-with-t-sne FT_SG_model_3 = FastText(corpus_3, size=10, window=3, min_count=4, workers=4, iter=1000, sg=1) # SKip gram이랑 CBOW를 사용해볼 예정!, Word2Vec은 잘 안쓰이니 굳이 시도해볼 필요는 없을 듯 # 그리고 parameter의 경우 일단 window는 3으로 했고(보통 2를 쓰지만 평점이므로 조금 더 길게 써 봄! size는 계산속도를 고려해서 골랐고 # min_count는 내가 눈에 잘 보이는 정도의 양이 나올때까지 바꿔가면서 사용함!) tsne_plot(FT_SG_model_3) # 3일때 FT_SG_model_4 = FastText(corpus_4, size=10, window=3, min_count=24, workers=4, iter=1000, sg=1) tsne_plot(FT_SG_model_4) #4 일때 #min_count는 아무래도 표본 데이터수가 압도적으로 많으므로 꽤나 많이 올려야 비슷하게 나옴 FT_SG_model_5 = FastText(corpus_5, size=10, window=3, min_count=24, workers=4, iter=1000, sg=1) #5일 때 tsne_plot(FT_SG_model_5) FT_SG_model_3_1 = FastText(corpus_3, size=10, window=3, min_count=4, workers=4, iter=1000, sg=0) # 이건 3인데 Tombow인 경우! tsne_plot(FT_SG_model_3_1) FT_SG_model_4_1 = FastText(corpus_4, size=10, window=3, min_count=24, workers=4, iter=1000, sg=0) #4인경우 tsne_plot(FT_SG_model_4_1) FT_SG_model_5_1 = FastText(corpus_5, size=10, window=3, min_count=24, workers=4, iter=1000, sg=0) #5인경우 tsne_plot(FT_SG_model_5_1) # Insight ! # 두 가지 모델을 모두 돌려본결과 저는 CBOW가 더 제가 원하는 결과를 잘 도출해 준것 같아 CBOW를 선택했습니다. # 저는 평점별로 친절한 금자씨 평을 마이닝해서 높은 점수 보통점수를 준사람들이 각각 어떤 부분에 더 집중했는 지를 보고자 했습니다. # 1. 평점을 2.5~3점으로 준 사람의 경우 : '최고'라는 단어가 취향이라는 단어와 연관이 깊다는 것으로 나왔습니다. 즉 최고의 작품이라고 볼 수도 # 있지만 본인에게는 취향을 탄다거나 호불호가 갈릴 수 있는 영화라는 점을 썼던 것이 아닐까라고 생각합니다. # 이것을 뒷받침 해주는 것이 '나'라는 명사와 '별로'라는 명사가 같이 등장했다는 것입니다. 즉, 나에게는 별로였다라고 한 사람들이 많았다는거죠. # 잘보면 이 외에도 '역시' '그렇게' '모르겠다' 등의 단어가 군집되어있습니다. # 그 외에도 특유의 미쟝셴 등의 단어가 나타나기는 하지만, 다른 단어와의 연관성이 커 보이지는 않습니다. # 3부작 이라는 단어가 등장했습니다. 그런데 여기서 특이한 점은 3부작 이라는 단어와 2라는 단어가 같이 등장한다는건데요. # 유일하게 3점대에서만 2라는 숫자가 등장합니다! # 거기다 올드보이라는 단어가 최고라는 단어와 같이 3부작 쪽에 있습니다. # 즉, 올드보이 다음 작품으로 인식한 사람이 많았다는 걸로 해석할 수 있다고 생각됩니다. # 2. 평점을 3.5~4점으로 준 사람의 경우 : #그리고 이영애 연기 연출 느낌 등이라는 단어가 비슷하게 위치한 것으로 보아 # 이 영화를 전반적으로 이영애가 준 연기와 그 느낌에 감동한 사람이 많을 것이라고 생각됩니다. # 그리고 여기서는 두부, 하얀 이라는 단어가 군집되어있는 것을 볼 수 있는데요. 사실, 두부와 하얀색은 # 이 영화를 깊게 보지않으면 잘 느끼기 힘든 부분입니다. 즉 4점에 가까운 점수를 준 사람들은 영화의 숨은 의미를 찾기 시작했다는 거죠! # 또한 미장셴 이라는 단어에 매력 가장 잘 느낌 등의 단어가 등장하며 멀지않은 곳에 이영애 음악 영상 등의 키워드가 추가로 군집돼있습니다. # 즉 4점대 이상을 택한 사람들은 이 영화의 미쟝셴에 조금씩 영향을 받기 시작했다고 할 수 있다고 생각합니다. # 3. 평점을 4.5~5점으로 준 사람의 경우 : 확실히 단어 표현이 풍부해졌습니다. 3.5~4점과 비교해서 같은 양의 min_count를 사용하였는데도 # 훨씬 더 풍부한 어휘가 나온 것으로봐서는, 훨씬 더 평이 길어졌다고 생각할 수 있을 것입니다. # 그만큼 이 영화를 다양한 관점에서 바라볼 수 있는 배경이 있었다는 뜻으로도 볼 수 있겠죠. # 그리고 여기서는 미쟝셴을 중심으로 한 단어가 훨씬 풍부해졌습니다. 연기 연출 표정 음악 분위기 배우 등 훨씬 더 다양한 표현이 # 미쟝셴과 같이 언급되었는데요. 5점대 사람들의 경우 이 영화의 모든 미쟝셴에 만족했다고 볼 수 있을 것입니다. 그런데 변태가 같이 언급되네요. # 저는 이 영화를 보면서 변태와 미쟝셴이 연결되는 느낌을 받지는 못했습니다. 그래서 제가 5점을 주지 못한걸까요? # 그리고 굉장히 특이한 점은 하나 본 듯 이라는 군집이 눈에 띕니다. 하나 본 듯, 어디서 많이 본 표현이죠? # 제 생각에는 뛰어난 ~를 본 듯 뛰어난 뮤지컬을 한 편 본 듯과 같이 비유적인 표현, 걸작이라는 표현을 하기 위해 사용했다고 생각합니다. # 그리고 한국 여성 캐릭터 중 최고 등의 어휘가 군집이 되어있습니다. 여성이 주인공이 되어 서사를 이끌어나간 포인트에 집중한 # 사람이 많다고 생각됩니다. 또 하얀이라는 단어가 붉은이라는 단어와 더욱 밀접하게 연관되어 있습니다. # 이것은 4점과 다른 점인데 저는 붉은 립스틱과 하얀 눈 등의 관계를 영화를 보면서 느끼지 못했고 오히려 # 하얀 두부 등에 더욱 집중했는데, 5점을 준 사람은 이런 부분에 더욱 집중한 것 같네요. # 그리고 전반적으로 너나 잘하세요 라는 군집이 꽤 많이 나오는데요. 저는 이 단어가 주로 어디와 연결되는지 보고 싶은마음에 # 따로 제외하지는 않았습니다. 그런데 약간 뚝 떨어져있는 경향이 평점대에 관계없이 보이네요. # 그렇다는 이야기는 그냥 마지막에 이 단어를 썼다는거겠죠? 그런데 CBOW 5점대 의경우 '하세요'가 떨어져있습니다. # 이것은 전 분석에서 이 부분만의 특이점이라고 생각됩니다. # 그런데 SG를 0으로 하나 1로 하냐에 따라 약간 군집이 다르게 되어있습니다. 저는 전반적으로 두 번째 결과가 더 군집화가 잘 되어 있다고 # 판단되어 두번째 것을 썼지만, 오히려 첫 번째 것도 군집이 깔끔하게 되어 있는 부분도 꽤 있습니다. # 두 가지를 모두 활용해서 인사이트를 도출해내는 것도 괜찮을 것 같네요! | cs |
Designed by sketchbooks.co.kr / sketchbook5 board skin
Sketchbook5, 스케치북5
Sketchbook5, 스케치북5
Sketchbook5, 스케치북5
Sketchbook5, 스케치북5