ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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을 살펴봅시다

    https://search.naver.com/search.naver?where=news&query=%EB%8B%A4%EC%9D%B4%EB%85%B8%EC%8A%A4&sm=tab_srt&sort=1&photo=0&field=0&reporter_article=&pd=3&ds=2020.01.01&de=2020.03.31&docid=&nso=so%3Add%2Cp%3Afrom20200101to20200331%2Ca%3Aall&mynews=0&refresh_start=0&related=0 

     

    다이노스 : 네이버 뉴스검색

    '다이노스'의 네이버 뉴스검색 결과입니다.

    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/Python은 겉치레가 아니야