-
R 네이버 뉴스(Naver News) Selenium (셀레니움) + 기사 본문R + Crawling (크롤링) 2020. 5. 7. 21:26
출처 : www.dinos.com 크롤링에 필요한 패키지(package)와 라이브러리(library)는 아래와 같습니다
install.packages(c("dplyr", "httr", "jsonlite", "rJava", "RSelenium", "stringr")
- library(dplyr)
- library(httr)
- library(jsonlite)
- library(rJava)
- library(RSelenium)
- library(stringr)
셀레니움(Selenium)을 실행해봅시다
https://r-pyomega.tistory.com/7?category=873554
R 크롤링 RSelenium (셀레니움) 을 크롬에서 구동하기
R에서 Selenium을 구동하려면 Java를 설치해야 합니다. Java설치는 https://r-pyomega.tistory.com/6 를 참고해주시길 바랍니다 Java설치 이후에 C드라이브에 r-selenium폴더를 만들어 아래 3파일을 다운 받습니다..
r-pyomega.tistory.com
#### 네이버뉴스 검색 페이지
네이버 포탈에서 <다이노스>를 검색하고
기간 옵션을 설정하고
최신순으로 정렬한 페이지입니다
## URL 주소
URL을 살펴봅시다
다이노스 : 네이버 뉴스검색
'다이노스'의 네이버 뉴스검색 결과입니다.
search.naver.com
복잡한 URL를 분리해봅시다
main <- "https://search.naver.com/search.naver?&where=news&query="
검색어 <- "다이노스" ## 검색어입니다
mid1 <- "&sm=tab_srt&sort=1&photo=0&field=0&reporter_article=&pd=3&ds="
시작일1 <- "2020.01.01" ## 설정 기간 시작일입니다
부터1 <- "&de="
종료일1 <- "2020.03.31" ## 설정 기간 종료일입니다
mid2 <- "&docid=&nso=so%3Ar%2Cp%3Afrom"
시작일2 <- "20200101" ## 설정 기간 시작일입니다
부터2 <- "to"
종료일2 <- "20200331" ## 설정 기간 종료일입니다
mid4 <- "%2Ca%3Aall&mynews=0&refresh_start=0&related=0"## URL 이어붙이기
target <- paste(main, 검색어, sep = "")
target <- paste(target, mid1, sep = "")
target <- paste(target, 시작일1, sep = "")
target <- paste(target, 부터1, sep = "")
target <- paste(target, 종료일1, sep = "")
target <- paste(target, mid2, sep = "")
target <- paste(target, 시작일2, sep = "")
target <- paste(target, 부터2, sep = "")
target <- paste(target, 종료일2, sep = "")
target <- paste(target,mid4, sep = "")
remDr$navigate(target) ## 네이버 뉴스 검색 결과 페이지로 이동합니다※ 번외
포털사이트는 대부분의 언론사의 뉴스를 제공하여 이를 이용자가 모두 볼 수 있다는 장점도 있지만, 기사의 내용이 복붙형태로 재생산되면서 사실상 똑같은 기사가 범람하는 단점이 있습니다
GET / POST 형식에서는 언론사 필터링하는 방법을 못찾았습니다만... 셀레니움으로는 가능합니다
필요하신분은 참고하십시요
이와같은 방법으로 크롤링에 마우스 클릭이 필요할때 응용하실수 있습니다
## 언론사 선택 + 최신순 정렬
F12를 누르고 언론사를 클릭합니다
이를 바탕으로 언론사를 <클릭>하는 코딩을 해봅시다
element <- remDr$findElement("css", "#news_popup > ## id = news_popup을 선택하고 ">"를 이용하여 하위 카테고리 갑니다
a:nth-child(1)") ## 1번째 "a"를 가져옵니다
element$clickElement() ## element를 셀레니움으로 "클릭"(말 그대로 마우스로 클릭하듯이)합니다Sys.sleep(time = 0.5) ##(중요!) 셀레니움은 Sys.sleep을 중간중간 넣어주어야 에러를 줄일수 있습니다
일간지 언론사만 필터링 해보겠습니다
F12를 누르고 언론사를 클릭합니다
이를 바탕으로 언론사 중 일간지를 <클릭>하는 코딩을 해봅시다
element <- remDr$findElement("css", "#ca_p1") ## id = ca_p1을 선택
element$clickElement() ## element를 셀레니움으로 "클릭"(말 그대로 마우스로 클릭하듯이)합니다
Sys.sleep(time = 0.5) ##(중요!) 셀레니움은 Sys.sleep을 중간중간 넣어주어야 에러를 줄일수 있습니다"확인" 버튼을 누르고 언론사 필터링을 완료하겠습니다
F12를 누르고 확인을 클릭합니다
이를 바탕으로 확인을 <클릭>하는 코딩을 해봅시다
element <- remDr$findElement("css", "#_nx_option_media > ## id = _nx_option_media을 선택
div.con_bx >
div.view_btn >
button.impact._submit_btn")element$clickElement() ## element를 셀레니움으로 "클릭"(말 그대로 마우스로 클릭하듯이)합니다
Sys.sleep(time = 0.5) ##(중요!) 셀레니움은 Sys.sleep을 중간중간 넣어주어야 에러를 줄일수 있습니다언론사 필터링한 결과를 최신순으로 정렬하겠습니다
F12로 정보를 확인하고 코딩을 해봅시다
element <- remDr$findElement("css", "div.news_option >
ul.sort >
li:nth-child(2)") ## 2번째 "li"를 가져옵니다
element$clickElement() ## element를 셀레니움으로 "클릭"(말 그대로 마우스로 클릭하듯이)합니다
Sys.sleep(time = 0.5) ##(중요!) 셀레니움은 Sys.sleep을 중간중간 넣어주어야 에러를 줄일수 있습니다## 링크 수집
각 언론사 링크가 아닌 네이버 뉴스에서 서비스하는 링크를 수집하겠습니다
네이버뉴스 서비스로 연결하는 링크를 수집하겠습니다
네이버뉴스 서비스로 뉴스를 보는 링크의 element는 2가지입니다(제가 확인해본 결과는 그렇습니다..)
이를 모두 크롤링하는 코딩입니다
링크_nnews <- c()
for(i in 1:10){ ## 검색 결과는 총 8페이지로 구성되어 있습니다만 for문을 10번 돌려 줍니다
tryCatch({
cat('현재', i, '페이지 수집 중! \n')
frontpage <- remDr$getPageSource()[[1]]
body <- frontpage %>% read_html()
##링크
링크.tmp1 <- body %>%
html_nodes("dd.txt_inline") %>%
html_nodes("a._sp_each_url") %>%
html_attr("href")
링크.tmp2 <- body %>%
html_nodes("span.txt_sinfo") %>%
html_nodes("a._sp_each_url") %>%
html_attr("href")
링크.tmp <- append(링크.tmp1,링크.tmp2)
링크.tmp <- 링크.tmp %>% unique()
링크_nnews <- append(링크_nnews,링크.tmp)
if(i==10) break()
element <- remDr$findElement("css", "#main_pack >
div.news.mynews.section._prs_nws>
div.paging >
a.next")
element$clickElement() ## "다음페이지"를 클릭하는 명령어입니다
Sys.sleep(time = 0.5)
}, error = function(e) cat("불러올 수 없습니다!\n"))
}
링크_nnews <- 링크_nnews %>% unique() ## 혹시라도 모를 중복 결과를 제거하기 위해 실행합니다수집한 링크를 확인합니다
수집한 링크 구조가 다릅니다
1, 15, 29번째 링크는 https://news.naver.로 시작합니다
나머지 링크는 http://sports.news.naver.로 시작합니다
링크도 다른만큼 해당 링크의 페이지 구조도 다릅니다
각각에 대해 다른 코드를 짜야합니다
# https://news.naver. case
우선 https://news.naver.로 시작하는 링크부터 크롤링을 하겠습니다
전체 링크에서 https://news.naver.가 포함된 링크만 뽑아냅니다
news.naver <- grep("https://news.naver",링크_nnews)
링크_news.naver <- 링크_nnews[news.naver]링크_news.naver %>% head()
첫번째 링크를 타고 들어가 크롤링할 element를 확인합시다
remDr$navigate(링크_news.naver[1]) 이 문서에서 크롤링 할 element(빨간색 박스)와 뉴스 링크를 저장할 벡터공간을 만듭니다
언론사_news.naver <- c()
날짜_news.naver <- c()
제목_news.naver <- c()
본문_news.naver <- c()
주소_news.naver <- c()
좋아_news.naver <- c()
슬퍼_news.naver <- c()
화나_news.naver <- c()
팬이_news.naver <- c()
후속_news.naver <- c()벡터 공간에 element를 넣을 명령어를 작성합니다
for (i in 1:length(링크_news.naver)){
tryCatch({
remDr$navigate(링크_news.naver[i])
body <- remDr$getPageSource()[[1]]
cat('현재', i, '페이지 수집 중! \n')
body <- body %>% read_html()
##언론사(최종수정기사입력)
언론사.tmp2 <- body %>%
html_nodes("div.link_news") %>%
html_nodes("h3") %>%
html_text()
언론사.tmp2 <- str_sub(언론사.tmp2,end=5)
언론사.tmp2 <- 언론사.tmp2 %>% str_trim()
if (length(언론사.tmp2) != 0) {
언론사_news.naver <- append(언론사_news.naver, 언론사.tmp2)
} else {
언론사_news.naver <- append(언론사_news.naver, "수동확인")
}
##날짜(최종수정기사입력)
날짜.tmp2 <- body %>%
html_nodes("span.t11") %>%
html_text()
날짜.tmp2 <-날짜.tmp2[2]
if (length(날짜.tmp1) != 0) {
날짜_news.naver <- append(날짜_news.naver, 날짜.tmp1)
} else {
날짜_news.naver <- append(날짜_news.naver, "수동확인")
}
##제목
제목.tmp2 <- body %>%
html_nodes("h3.tts_head") %>%
html_text()
if (length(제목.tmp2) != 0) {
제목_news.naver <- append(제목_news.naver, 제목.tmp2)
} else {
제목_news.naver <- append(제목_news.naver, "수동확인")
}
##본문
본문.tmp2 <- body %>%
html_nodes("div#articleBodyContents") %>%
html_text()
if (length(본문.tmp2) != 0) {
본문_news.naver <- append(본문_news.naver, 본문.tmp2)
} else {
본문_news.naver <- append(본문_news.naver, "수동확인")
}
## 반응
반응.tmp1 <- body %>%
html_nodes("ul.u_likeit_layer") %>%
html_text()
반응.tmp1 <- 반응.tmp1[1]
반응.tmp1 <- str_replace_all(반응.tmp1,"\t","")
반응.tmp1 <- strsplit(반응.tmp1, split="\n")
#좋아
좋아.tmp11 <- 반응.tmp1[[1]][3]
좋아.tmp12 <- 반응.tmp1[[1]][4]
좋아.tmp1 <- paste0(좋아.tmp11,":",좋아.tmp12)
if (length(좋아.tmp1) != 0) {
좋아_news.naver <- append(좋아_news.naver, 좋아.tmp1)
} else {
좋아_news.naver <- append(좋아_news.naver, "수동확인")
}
#슬퍼
슬퍼.tmp11 <- 반응.tmp1[[1]][9]
슬퍼.tmp12 <- 반응.tmp1[[1]][10]
슬퍼.tmp1 <- paste0(슬퍼.tmp11,":",슬퍼.tmp12)
if (length(슬퍼.tmp1) != 0) {
슬퍼_news.naver <- append(슬퍼_news.naver, 슬퍼.tmp1)
} else {
슬퍼_news.naver <- append(슬퍼_news.naver, "수동확인")
}
#화나
화나.tmp11 <- 반응.tmp1[[1]][15]
화나.tmp12 <- 반응.tmp1[[1]][16]
화나.tmp1 <- paste0(화나.tmp11,":",화나.tmp12)
if (length(화나.tmp1) != 0) {
화나_news.naver <- append(화나_news.naver, 화나.tmp1)
} else {
화나_news.naver <- append(화나_news.naver, "수동확인")
}
#팬이
팬이.tmp11 <- 반응.tmp1[[1]][21]
팬이.tmp12 <- 반응.tmp1[[1]][22]
팬이.tmp1 <- paste0(팬이.tmp11,":",팬이.tmp12)
if (length(팬이.tmp1) != 0) {
팬이_news.naver <- append(팬이_news.naver, 팬이.tmp1)
} else {
팬이_news.naver <- append(팬이_news.naver, "수동확인")
}
#후속
후속.tmp11 <- 반응.tmp1[[1]][27]
후속.tmp12 <- 반응.tmp1[[1]][28]
후속.tmp1 <- paste0(후속.tmp11,":",후속.tmp12)
if (length(후속.tmp1) != 0) {
후속_news.naver <- append(후속_news.naver, 후속.tmp1)
} else {
후속_news.naver <- append(후속_news.naver, "수동확인")
}
##주소
주소_news.naver <- append(주소_news.naver , 링크_news.naver[i])
Sys.sleep(time = 1)
}, error = function(e) cat("불러올 수 없습니다!\n"))
}수집한 element의 길이를 확인합니다
length(날짜_news.naver)
length(제목_news.naver)
length(본문_news.naver)
length(주소_news.naver)
length(좋아_news.naver)
length(슬퍼_news.naver)
length(화나_news.naver)
length(팬이_news.naver)
length(후속_news.naver)수집한 element 모두 길이가 같습니다
# https://sports.news case
https://sports.news로 시작하는 링크도 https://news.naver.와 흐름은 같습니다
먼저 http://sports.news가 포함된 링크만 뽑아냅니다
sports.news <- grep("http://sports.news",링크_nnews)
링크_sports.news <- 링크_nnews[sports.news]
링크_sports.news %>% head()해당링크로 찾아가 크롤링 할 element와 뉴스 링크를 저장할 벡터공간을 만듭니다
언론사_sports.news <- c()
날짜_sports.news <- c()
제목_sports.news <- c()
본문_sports.news <- c()
주소_sports.news <- c()
좋아_sports.news <- c()
슬퍼_sports.news <- c()
화나_sports.news <- c()
팬이_sports.news <- c()
후속_sports.news <- c()벡터 공간에 element를 넣을 명령어를 작성합니다
for (i in 1:length(링크_sports.news)){
tryCatch({
remDr$navigate(링크_sports.news[i])
body <- remDr$getPageSource()[[1]]
cat('현재', i, '페이지 수집 중! \n')
body <- body %>% read_html()
##언론사(최종수정기사입력)
언론사.tmp1 <- body %>%
html_nodes("div.link_popular_news") %>%
html_nodes("span.logo") %>%
html_text()
if (length(언론사.tmp1) != 0) {
언론사_sports.news <- append(언론사_sports.news, 언론사.tmp1)
} else {
언론사_sports.news <- append(언론사_sports.news, "수동확인")
}
##날짜(최종수정기사입력)
날짜.tmp1 <- body %>%
html_nodes("div.info") %>%
html_nodes("span") %>%
html_text()
날짜.tmp1 <- 날짜.tmp1[2]
if (length(날짜.tmp1) != 0) {
날짜_sports.news <- append(날짜_sports.news, 날짜.tmp1)
} else {
날짜_sports.news <- append(날짜_sports.news, "수동확인")
}
##제목
제목.tmp1 <- body %>%
html_nodes("h4.title") %>%
html_text()
if (length(제목.tmp1) != 0) {
제목_sports.news <- append(제목_sports.news, 제목.tmp1)
} else {
제목_sports.news <- append(제목_sports.news, "수동확인")
}
##본문
본문.tmp1 <- body %>%
html_nodes("div#newsEndContents") %>%
html_text()
if (length(본문.tmp1) != 0) {
본문_sports.news <- append(본문_sports.news, 본문.tmp1)
} else {
본문_sports.news <- append(본문_sports.news, "수동확인")
}
## 반응
반응.tmp1 <- body %>%
html_nodes("ul.u_likeit_inline") %>%
html_text()
반응.tmp1 <- str_replace_all(반응.tmp1,"\t","")
반응.tmp1 <- strsplit(반응.tmp1, split="\n")
#좋아
좋아.tmp11 <- 반응.tmp1[[1]][3]
좋아.tmp12 <- 반응.tmp1[[1]][4]
좋아.tmp1 <- paste0(좋아.tmp11,":",좋아.tmp12)
if (length(좋아.tmp1) != 0) {
좋아_sports.news <- append(좋아_sports.news, 좋아.tmp1)
} else {
좋아_sports.news <- append(좋아_sports.news, "수동확인")
}
#슬퍼
슬퍼.tmp11 <- 반응.tmp1[[1]][9]
슬퍼.tmp12 <- 반응.tmp1[[1]][10]
슬퍼.tmp1 <- paste0(슬퍼.tmp11,":",슬퍼.tmp12)
if (length(슬퍼.tmp1) != 0) {
슬퍼_sports.news <- append(슬퍼_sports.news, 슬퍼.tmp1)
} else {
슬퍼_sports.news <- append(슬퍼_sports.news, "수동확인")
}
#화나
화나.tmp11 <- 반응.tmp1[[1]][15]
화나.tmp12 <- 반응.tmp1[[1]][16]
화나.tmp1 <- paste0(화나.tmp11,":",화나.tmp12)
if (length(화나.tmp1) != 0) {
화나_sports.news <- append(화나_sports.news, 화나.tmp1)
} else {
화나_sports.news <- append(화나_sports.news, "수동확인")
}
#팬이
팬이.tmp11 <- 반응.tmp1[[1]][21]
팬이.tmp12 <- 반응.tmp1[[1]][22]
팬이.tmp1 <- paste0(팬이.tmp11,":",팬이.tmp12)
if (length(팬이.tmp1) != 0) {
팬이_sports.news <- append(팬이_sports.news, 팬이.tmp1)
} else {
팬이_sports.news <- append(팬이_sports.news, "수동확인")
}
#후속
후속.tmp11 <- 반응.tmp1[[1]][27]
후속.tmp12 <- 반응.tmp1[[1]][28]
후속.tmp1 <- paste0(후속.tmp11,":",후속.tmp12)
if (length(후속.tmp1) != 0) {
후속_sports.news <- append(후속_sports.news, 후속.tmp1)
} else {
후속_sports.news <- append(후속_sports.news, "수동확인")
}
##주소
주소_sports.news <- append(주소_sports.news , 링크_sports.news[i])
Sys.sleep(time = 1)
}, error = function(e) cat("불러올 수 없습니다!\n"))
}수집한 element의 길이를 확인합니다
length(언론사_sports.news)
length(날짜_sports.news)
length(제목_sports.news)
length(본문_sports.news)
length(주소_sports.news)
length(좋아_sports.news)
length(슬퍼_sports.news)
length(화나_sports.news)
length(팬이_sports.news)
length(후속_sports.news)수집한 element 길이가 같습니다
## 데이터 전처리
데이터 전처리를 합니다
기사본문에 필요없는 데이터를 지우도록 합니다
본문_sports.news <- str_replace_all(본문_sports.news,"\n", "")
본문_sports.news <- str_replace_all(본문_sports.news,"\t", "")
본문_sports.news <- str_replace_all(본문_sports.news,"//", "")
본문_sports.news <- str_replace_all(본문_sports.news,"flash 오류를 우회하기 위한 함수 추가", "")
본문_sports.news <- str_replace_all(본문_sports.news,"function _flash_removeCallback()", "")
본문_sports.news <- str_replace_all(본문_sports.news,"\\()", "")
본문_sports.news <- str_replace_all(본문_sports.news,"\\{}", "")
본문_news.naver <- str_replace_all(본문_news.naver,"\n", "")
본문_news.naver <- str_replace_all(본문_news.naver,"\t", "")
본문_news.naver <- str_replace_all(본문_news.naver,"//", "")
본문_news.naver <- str_replace_all(본문_news.naver,"flash 오류를 우회하기 위한 함수 추가", "")
본문_news.naver <- str_replace_all(본문_news.naver,"function _flash_removeCallback()", "")
본문_news.naver <- str_replace_all(본문_news.naver,"\\()", "")
본문_news.naver <- str_replace_all(본문_news.naver,"\\{}", "")## 하나의 데이터프레임으로 합침
https://news.naver. case와 https://sports.news case 각각을 데이터프레임으로 만들고,
변수이름을 변경한 후,
두 데이터 프레임을 합치겠습니다
paper_sports.news <- data.frame(날짜_sports.news, 제목_sports.news, 본문_sports.news, 주소_sports.news, 좋아_sports.news, 슬퍼_sports.news, 화나_sports.news, 팬이_sports.news, 후속_sports.news)
paper_news.naver <- data.frame(날짜_news.naver, 제목_news.naver, 본문_news.naver, 주소_news.naver, 좋아_news.naver, 슬퍼_news.naver, 화나_news.naver, 팬이_news.naver, 후속_news.naver)
paper_sports.news <- rename(paper_sports.news, c("날짜" = 날짜_sports.news,
"제목" = 제목_sports.news,
"본문" = 본문_sports.news,
"주소" = 주소_sports.news,
"좋아요" = 좋아_sports.news,
"슬퍼요" = 슬퍼_sports.news,
"화나요" = 화나_sports.news,
"팬이에요" = 팬이_sports.news,
"후속기사" = 후속_sports.news))
paper_news.naver <- rename(paper_news.naver, c("날짜" = 날짜_news.naver,
"제목" = 제목_news.naver,
"본문" = 본문_news.naver,
"주소" = 주소_news.naver,
"좋아요" = 좋아_news.naver,
"슬퍼요" = 슬퍼_news.naver,
"화나요" = 화나_news.naver,
"팬이에요" = 팬이_news.naver,
"후속기사" = 후속_news.naver))
paper_nnews <- rbind(paper_sports.news,paper_news.naver)csv로 저장하여 결과를 확인합니다
www.write.csv(paper_nnews, file = "D:/paper_nnews_다이노스.csv", row.names=FALSE) 다음 포스팅은 네이버뉴스 댓글을 크롤링 하겠습니다
'R + Crawling (크롤링)' 카테고리의 다른 글
R 네이버 뉴스(Naver News) Selenium (셀레니움) + 기사 댓글 (0) 2020.05.08 R 크롤링 뽐뿌 (ppomppu) GET / POST (0) 2020.02.23 R 크롤링 뽐뿌 (ppomppu) GET / POST + Selenium (셀레니움) (0) 2020.02.23 R 크롤링 클리앙 (Clien) GET / POST 방식 (0) 2020.02.12 R 크롤링 클리앙(Clien) GET / POST + Selenium (셀레니움) (0) 2020.02.11