[기업 이미지 파악을 위한 소비자 후기 키워드 분석]

 (바로가기를 클릭하시면 해당 게시글로 넘어갑니다.)



Ⅰ 웹 페이지 크롤링


1. 크롬 드라이버 실행 (바로가기)


2. 웹 페이지 크롤링  (바로가기)



Ⅱ 키워드 추출


3. 명사 추출 및 카운팅 (바로가기)


# 1-1. 크롬 드라이버 실행


ch = wdman::chrome(port=4567L)


> ch = wdman::chrome(port=4567L)

checking chromedriver versions:

BEGIN: PREDOWNLOAD

BEGIN: DOWNLOAD

BEGIN: POSTDOWNLOAD



chrome <- remoteDriver(remoteServerAddr = "localhost", port=4567L, browserName='chrome')

chrome$open()


> chrome$open()


'wdman' 패키지에 있는 'chrome'를 이용하여 크롬 드라이버에 포트를 배정해 주었습니다. 배정한 포트를 이용하여 원격접속 설정을 하고 'open'함수를 사용하면 다음과 같이 원격 조종되는 크롬 창이 실행됩니다. 'chrome'으로 여러가지 기능을 사용할 수 있는데, 대표적으로는 특정 사이트에 접속하는 'navigate'가 있습니다. 사용 방법은 아래와 같습니다.



chrome$navigate("https://www.google.com")


> chrome$navigate("https://www.google.com")


# 2-1. URL 구조 파악



국내 포털사이트 중 하나인 네이버에서 블로그 검색을 하면 한 페이지당 10개의 글이 노출됩니다. 페이지를 변경할 때 주소가 어떻게 달라지는 지를 확인하니 다음과 같았습니다.


https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start=1


https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start=11


https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start=21


https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start=31


앞 부분은 동일하므로 별도의 변수로 저장해주고 뒤의 숫자만 'for문'을 이용해서 변화시켜 주소를 한번에 담아주겠습니다.




# 2-2. URL 저장


target_url <- 'https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start='


urls <- NULL

for (i in 0:99){

 urls[i+1] <- paste0(target_url, i*10+1)

}
head(urls, 5)

> head(urls, 5)

 [1] "https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start=1"  

 [2] "https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start=11"

 [3] "https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start=21"

 [4] "https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start=31"

 [5] "https://search.naver.com/search.naver?date_from=&date_option=0&date_to=&dup_remove=1&nso=&post_blogurl=&post_blogurl_without=&query=%EC%A0%9C%EC%A3%BC%ED%95%AD%EA%B3%B5&sm=tab_pge&srchby=all&st=sim&where=post&start=41"


 'paste0'를 이용해 고정된 부분과 변화하는 부분을 더해 주소 리스트를 만들어 주었습니다. 'head'만 출력해본 결과 제대로 생성되었음을 확인할 수 있었습니다.


# 2-3. 사이트 원격 접속 및 HTML 페이지 저장


 크롬 드라이버 실행 시 사용해 보았던 'navigate'를 사용하면 페이지에 접속할 수 있습니다. 접속 후 개발자 도구를 이용하여 태그 정보를 확인, HTML 소스를 불러오겠습니다. '태그 명'은 노란 박스를 참조해주세요.


for (i in 0:99){

 chrome$navigate(urls[i+1])

html_txt <- read_html(urls[i+1])

}




html_class <- html_nodes(html_txt, '.blog.section._blogBase')

html_content <- html_nodes(html_class, '.sh_blog_top')  




html_titles <- html_nodes(html_content, '.sh_blog_title._sp_each_url._sp_each_title')




html_contents <- html_nodes(html_content, '.sh_blog_passage')



불러올 정보는 타이틀과 검색 화면에서 노출된 텍스트입니다. 이 정보가 담긴 부분은 개발자 도구를 사용하면 쉽게 확인할 수 있습니다. 먼저 큰 클래스에 접근한 뒤 작은 클래스로 접근하면 다음과 같이 깔끔하게 필요한 부분이 담긴 것을 확인할 수 있습니다.



head(html_titles)


> head(html_titles)

{xml_nodeset (6)}

[1] <a class="sh_blog_title _sp_each_url _sp_each_title" href="https://blog.naver.com/ssangcopi335?Redirect=Log&amp;lo ...

[2] <a class="sh_blog_title _sp_each_url _sp_each_title" href="https://blog.naver.com/jennyan1117?Redirect=Log&amp;log ...

[3] <a class="sh_blog_title _sp_each_url _sp_each_title" href="https://blog.naver.com/hoorayhm?Redirect=Log&amp;logNo= ...

[4] <a class="sh_blog_title _sp_each_url _sp_each_title" href="https://blog.naver.com/starapplesand?Redirect=Log&amp;l ...

[5] <a class="sh_blog_title _sp_each_url _sp_each_title" href="https://blog.naver.com/kol8321?Redirect=Log&amp;logNo=2 ...

[6] <a class="sh_blog_title _sp_each_url _sp_each_title" href="https://blog.naver.com/gayoun3?Redirect=Log&amp;logNo=2 ...



head(html_contents)


>   head(html_contents)

{xml_nodeset (6)}

[1] <dd class="sh_blog_passage">\n<strong class="hl">제주 항공</strong> 면접 블라우스 당신의 꿈에 날개를 달아드립니다. 면접 복장 전문 드림윙즈입니다. <stro ...

[2] <dd class="sh_blog_passage">\n<strong class="hl">제주항공</strong> JJ 멤버스 위크 7월 출발 항공권 <strong class="hl">제주항공</strong ...

[3] <dd class="sh_blog_passage">\n<strong class="hl">제주항공</strong>을 타고 사이판을 가면 얻게되는 혜택들이 엄청난데요! 바로... <strong class="h ...

[4] <dd class="sh_blog_passage">안녕하세요 충순입니다 오늘은 <strong class="hl">제주항공</strong>의 회원 등급과 리프레시 포인트에 대해 알려드리려고 해요 ▲ <str ...

[5] <dd class="sh_blog_passage">\n<strong class="hl">제주항공</strong> 서포터즈 ː 제주에이터 캠퍼스어택 '신촌 연세대학교' 에 가다! 안녕하세요! #<strong ...

[6] <dd class="sh_blog_passage">나름 저렴하게 <strong class="hl">제주항공</strong>으로 왕복/Tax포함 1인 26만원 정도에 다녀왔다. 항공편명 : 인천-사이판 7C ...




# 2-4. TEXT 저장


text_titles <- str_replace_all(html_text(html_titles), "\\W", " ")

text_contents <- str_replace_all(html_text(html_contents), "\\W", " ")


추출한 html 소스를 'html_text'를 이용해 텍스트로 저장했습니다. 저장 시 필요없는 특수문자(정규표현식: '\\W')를 'str_replace_all'을 이용하여 제거해주었습니다. 'head'를 이용해 일부를 출력해보면 다음과 같이 html 코드 부분을 제외한 텍스트만 남아있는 것을 알 수 있습니다.



head(text_titles)


> head(text_titles)

[1] "제주 항공 면접 블라우스 디테일을 살려 구매하기"             

[2] "제주항공 JJ멤버스 위크 특가 7월 출발 항공권"                

[3] " 조이버  사이판갈때는 제주항공타고 할인 혜택받자 "          

[4] "정보  제주항공 회원 등급 리프레시 포인트"                   

[5] " 조이버 14기  제주항공 서포터즈 ː 제주에이터 캠퍼스어택   "

[6] " 사이판  제주항공 사이판 밤비행 이용 후기   ESTA 이스타 "



head(text_contents)


>   head(text_contents)

[1] "제주 항공 면접 블라우스 당신의 꿈에 날개를 달아드립니다  면접 복장 전문 드림윙즈입니다 제주 항공 면접 블라우스 서류 발표가 나면 면접까지 준비기간이 짧기   "

[2] "제주항공 JJ 멤버스 위크 7월 출발 항공권 제주항공 얼리버드 특가 JJ멤버스 위크 시작합니다 판매기간 2018년 3월 7일 오전 10시부터 3월 13일까지 출발기간 2018년   "

[3] "제주항공을 타고 사이판을 가면 얻게되는 혜택들이 엄청난데요  바로 제주항공을 타고 사이판에서 켄싱턴 호텔에서 숙박하게 되면 객실료1박당 20불 할인   "

[4] "안녕하세요 충순입니다 오늘은 제주항공의 회원 등급과 리프레시 포인트에 대해 알려드리려고 해요   제주항공 JEJU AIR 제주항공 리프레시 포인트란 리프레시 "

[5] "제주항공 서포터즈 ː 제주에이터 캠퍼스어택  신촌 연세대학교 에 가다 안녕하세요 제주항공 서포터즈  조이버 14기 애리입니다 오늘은 저희 팀 제주에이터 "         

[6] "나름 저렴하게 제주항공으로 왕복 Tax포함 1인 26만원 정도에 다녀왔다  항공편명 인천 사이판 7C3404 사이판 인천 7C3403 제주항공은 여러번 이용해본 적 있는 터라      "


# 3-1. 명사 추출


nount <- extractNoun(text_titles)

nounc <- extractNoun(text_contents)


head(nount, 3)


> head(nount, 3)

[[1]]

[1] "제주"     "항공" "면접"     "블라우스" "디테일" "구매"     "하" "기"


[[2]]

[1] "제주"     "항공" "JJ멤버스" "위크"     "특가" "7" "월"    "출발" "항공" "권"


[[3]]

[1] "조이버" "사이판" "갈"     "제주" "항공" "타고" "할인"   "혜택받"



head(nounc, 3)


> head(nounc, 3)

[[1]]

[1] "제주"           "항공" "면접"          "블라우스" "당신" "꿈"            

[7] "날개"           "면접" "복장"          "전문" "드림윙즈입니다" "제주"         

[13] "항공"           "면접" "블라우스"       "서류" "발표"  "나"

[19] "면접"           "준비" "기간"          "짧" "기"


[[2]]

[1] "제주"     "항공" "JJ"      "멤버스" "위크" "7"        "월" "출발" "항공권" "제주"    

[11] "항공"     "얼리버드" "특가"  "JJ멤버스" "위크" "시작"     "판매" "기간" "2018"   "년"

[21] "3"        "월" "7"     "오전" "10" "시"       "3" "월" "13"  "일"

[31] "출발"     "기간" "2018"     "년"


[[3]]

[1] "제주"        "항공" "사"        "이" "판" "혜택"        "들이" "제주"

[9] "항공"        "사" "이"         "판" "켄싱턴" "호텔"        "숙박" "하"

[17] "객실료1박당" "20"          "불" "인"


명사 추출을 위해서 'KoNLP'에 있는 'useNIADic()'을 사용하였습니다. 또한 n행 1열의 데이터 프레임 형태로 만들어 주기 위해 아래와 같이 'for문'을 이용하였습니다.



df_nount <- NULL

df_nounc <- NULL


for (i in 0:9){

  df_nount_b <- as.data.frame(nount[i+1])

  names(df_nount_b) <- c('keywords')

  df_nount <- rbind(df_nount, df_nount_b)  

  df_nounc_b <- as.data.frame(nounc[i+1])

  names(df_nounc_b) <- c('keywords')

  df_nounc <- rbind(df_nounc, df_nounc_b)

}


jkeywords <- rbind(df_nount, df_nounc)

head(jkeywords)


> head(jkeywords)

 keywords

1     제주

2     항공

3     국제

4       선

5   파일럿

6   기내식




# 3-2. 카운팅 (빈도 확인)


추출된 키워드는 'group_by'를 이용해 동일 키워드를 기준으로 묶고 'summarise'와 'n()'을 사용해 카운팅했습니다. 'order'를 이용하여 내림차순 정렬하면 빈도수가 높은 단어 순으로 확인할 수 있습니다.



jkeywords$keywords <- as.character(jkeywords$keywords)

count_key <- jkeywords %>% filter(nchar(keywords)>=2 & nchar(keywords)<=9) %>% group_by(keywords) %>% summarise(n=n())

keywords <- count_key[order(-count_key$n), ]


head(keywords, 10)


> head(keywords, 10)

# A tibble: 10 x 2

  keywords     n

  <chr>    <int>

1 제주            3174

2 항공            2913

3 여행            586

4 특가            302

5 항공권         301

6 이용            170

7 출발            164

8 항공우주    164

9 2018           138

10 시간           135



+ Recent posts