Web scraping in practice

library(XML)
library(rvest)
## Loading required package: xml2
## 
## Attaching package: 'rvest'
## The following object is masked from 'package:XML':
## 
##     xml
library(stringr)
page <- readLines("https://news.daum.net/ranking/popular")
page_parsed <- htmlParse(page)

First Headline XPath: ‘//[@id="mArticle"]/div[2]/ul[3]/li[1]/div[2]/strong/a’ Second Headline XPath: ’//[@id="mArticle"]/div[2]/ul[3]/li[2]/div[2]/strong/a’

First Company XPath: ‘//[@id="mArticle"]/div[2]/ul[3]/li[1]/div[2]/strong/span’ Second Company XPath: ’//[@id="mArticle"]/div[2]/ul[3]/li[2]/div[2]/strong/span’

headline_xpath <- '//*[@id="mArticle"]/div[2]/ul[3]/li/div[2]/strong/a'
company_xpath <- '//*[@id="mArticle"]/div[2]/ul[3]/li/div[2]/strong/span'

headlines <- xpathSApply(page_parsed, headline_xpath, xmlValue)
headlines
##  [1] "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""                                                
##  [2] "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"                                   
##  [3] "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"                                               
##  [4] "\"토종 '칡소' 좀 살려주소\""                                                                  
##  [5] "화이자 백신 호재에 세계 증시·유가 일제히 폭등"                                               
##  [6] "손바닥에 거미 다리 모양 붉은 반점 생겼다면 \"간 검사 받으세요\""                              
##  [7] "검찰 '뇌물·횡령 혐의' 홍문종 징역9년 구형..洪 \"조작극\"(종합)"                              
##  [8] "무기 싣고 개표소로 돌진.. 펜실베이니아는 전쟁터였다"                                          
##  [9] "일제강점기 '명륜학원 졸업사진'..전주 최고 유교 기록물 선정"                                   
## [10] "세계인구 3분의 1 거대 경제권 탄생 임박..RCEP 협상 타결"                                       
## [11] "몸살 앓는 국토 대동맥 경부고속도로..수혈 위해 도심지역 입체화 시급"                           
## [12] "'돈세탁 혐의' 손정우, 구속영장 기각..\"도주우려 없어\""                                       
## [13] "박지원 만난 日집권당 2인자 \"신뢰 확신\"..한일관계 기대 발언"                                 
## [14] "철책 넘은 北 주민에 놀란 육군, 후방지역 대침투작전 점검"                                      
## [15] "\"언성 높이지 마세요\"..평택교육청, 의원 질의에 맞불 '행감 중지'"                             
## [16] "'어제의 동지' 트럼프에 일격..伊 베를루스코니 \"너무 거만했다\""                               
## [17] "'태움' 고통받다 극단적 선택..故 서지윤 간호사 산재 인정"                                      
## [18] "트럼프 '계산된 버티기', 2024년 대선 재출마 노리나"                                            
## [19] "'마지막 여행' 다녀온 김철민 \"다시 항암치료..끝까지 버틸 것\""                                
## [20] "윤석열, 차장들에게 '국민의 검찰' 강조..\"현안 언급 없었다\"(종합)"                            
## [21] "'코로나 이후 도시 공간' 제언, 유현준 교수 \"사람 많이 모일수록 좋은 도시란 공식 끝났다\""     
## [22] "[바이든 시대] 트럼프 지명 조달청장 요지부동..인수 지연"                                       
## [23] "[바이든 시대] 미 잡지가 본 '루저' 트럼프, 필사적으로 버티는 이유"                             
## [24] "'하늘의 응급실' 의무후송 전용헬기 軍 최초 도입"                                               
## [25] "난치성 파킨슨 증후군 치료 가능성 열렸다"                                                      
## [26] "푸틴이 바이든 축하 안하는 이유..크렘린 \"공식개표결과 나와야\""                               
## [27] "첫 '영구제명' 변호사, 또 실형..해임 경찰관에게 뇌물수수"                                      
## [28] "갓난 아기 때리고 던지고..CCTV에 '쿵' 소리까지"                                                
## [29] "여동생 밸러리가 이방카 역할하나..'바이든 패밀리' 눈길"                                        
## [30] "'웰컴 투 비디오' 손정우, 구속영장 기각..\"구속 사유 인정 어려워\""                            
## [31] "[단독] HDC현산 아시아나 포기안했나 \"금호리조트 매각말라\""                                   
## [32] "홍준표 \"전셋집 구했나\"..홍남기 \"개인적 상황이니 나중에\""                                  
## [33] "[바이든 시대] 트럼프에 누가 직언할까..\"측근들, 패배 알지만 조용\""                           
## [34] "만화계 오스카상 '쾌거'..세계가 격찬한 한국의 '그래픽 노블'"                                   
## [35] "바이든 코로나 부터 잡아라!..한국 언급한 측근 주목"                                            
## [36] "[바이든 시대] 일본 신문 \"바이든, 트럼프보다 한미관계 중시할 것\""                            
## [37] "성윤모 \"월성1호기 관련 압수수색에 매우 당혹\""                                               
## [38] "울산 남구 아파트 11층서 불..3천만원 피해"                                                     
## [39] "문 대통령, '바이든 시대' 공식화..\"바이든 사람들과 다방면 소통할 것\""                        
## [40] "물만 먹어도 살쪄? 기초대사량 늘리는 7가지 팁"                                                 
## [41] "코로나19 국내 확진자, 5주 연속 증가세..거리 두기 1.5단계 '경고등'"                            
## [42] "고개부터 숙인 민주당..국민의힘은 줄 잇는 출사표"                                              
## [43] "한번에 2,300억 줄여..학교 현장 비상"                                                          
## [44] "정품 마스크라더니..쿠팡, 뒤늦게 '무허가 마스크' 환불조치"                                     
## [45] "삼부토건, '이낙연 민주당 대표 동생' 이계연씨 대표 선임"                                       
## [46] "황상무 전 앵커, KBS에 사의 표명 \"공영방송, 한쪽 진영 서면 안 돼\""                           
## [47] "[바이든 시대] 트럼프 언급 한 마디 없이.. 메르켈 獨 총리, 바이든 당선 축하 성명"               
## [48] "국민의힘, 보궐선거 예선에 '여론조사 100% 적용' 가닥(종합)"                                    
## [49] "\"호수가 보이는 주택 갖고 싶어서\" 할아버지 살해한 美 20대 손녀"                              
## [50] "[주진우 라이브] 정세현 전 장관 \"바이든 정권 출범 후 복잡한 북핵 문제 셈법, 종전선언이 입구\""
companies <- xpathSApply(page_parsed, company_xpath, xmlValue)
companies
##  [1] "한국일보"   "한국일보"   "국민일보"   "경향신문"   "뉴스1"     
##  [6] "주간동아"   "뉴스1"      "오마이뉴스" "연합뉴스"   "연합뉴스"  
## [11] "노컷뉴스"   "뉴시스"     "연합뉴스"   "뉴시스"     "뉴스1"     
## [16] "연합뉴스"   "세계일보"   "한겨레"     "이데일리"   "뉴시스"    
## [21] "경향신문"   "연합뉴스"   "연합뉴스"   "KBS"        "뉴시스"    
## [26] "연합뉴스"   "KBS"        "MBC"        "채널A"      "이데일리"  
## [31] "조선일보"   "연합뉴스"   "연합뉴스"   "KBS"        "KBS"       
## [36] "연합뉴스"   "한겨레"     "연합뉴스"   "한국일보"   "코메디닷컴"
## [41] "경향신문"   "YTN"        "KBS"        "SBSCNBC"    "연합뉴스"  
## [46] "뉴스1"      "한국일보"   "뉴시스"     "머니투데이" "KBS"

Five steps of web scraping

  1. We identify the running mechanism in the URL syntax.
  2. We retrieve links to the running pages.
  3. We download the running pages.
  4. We retrieve links to the entries on the running pages.
  5. We download the single entries.

Manipulating URLs to access multiple pages

baseurl <- "https://news.daum.net/ranking/popular?regDate="
dates <- seq(from=20201025, to=20201031, by=1)
urls <- str_c(baseurl, dates)
urls
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
## [2] "https://news.daum.net/ranking/popular?regDate=20201026"
## [3] "https://news.daum.net/ranking/popular?regDate=20201027"
## [4] "https://news.daum.net/ranking/popular?regDate=20201028"
## [5] "https://news.daum.net/ranking/popular?regDate=20201029"
## [6] "https://news.daum.net/ranking/popular?regDate=20201030"
## [7] "https://news.daum.net/ranking/popular?regDate=20201031"

What is a function? What is the function, lapply()?

Function

Function

urls
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
## [2] "https://news.daum.net/ranking/popular?regDate=20201026"
## [3] "https://news.daum.net/ranking/popular?regDate=20201027"
## [4] "https://news.daum.net/ranking/popular?regDate=20201028"
## [5] "https://news.daum.net/ranking/popular?regDate=20201029"
## [6] "https://news.daum.net/ranking/popular?regDate=20201030"
## [7] "https://news.daum.net/ranking/popular?regDate=20201031"
remove_numbers <- function(x){
  library(stringr)
  y <- str_remove(x, "[[:digit:]]+")
  return(y)
}

?lapply
## starting httpd help server ... done
class(lapply(urls, remove_numbers))
## [1] "list"
lapply(urls, remove_numbers)
## [[1]]
## [1] "https://news.daum.net/ranking/popular?regDate="
## 
## [[2]]
## [1] "https://news.daum.net/ranking/popular?regDate="
## 
## [[3]]
## [1] "https://news.daum.net/ranking/popular?regDate="
## 
## [[4]]
## [1] "https://news.daum.net/ranking/popular?regDate="
## 
## [[5]]
## [1] "https://news.daum.net/ranking/popular?regDate="
## 
## [[6]]
## [1] "https://news.daum.net/ranking/popular?regDate="
## 
## [[7]]
## [1] "https://news.daum.net/ranking/popular?regDate="

R Basics for Web Scraping

Creating vectors

A sequence of numbers/integers, characters, or Booleans

c(1,3,5) # Join elements into a vector 
## [1] 1 3 5
1:5 # An integer sequence
## [1] 1 2 3 4 5
seq(1, 5, by=2) # A sequence of integers from 1 to 5, increasing by 2
## [1] 1 3 5
rep(1:5, times=3) # Repeat an integer sequence 1:5 three times
##  [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
rep(1:5, each=3) # Repeat each element of an integer sequence 1:5 three times
##  [1] 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5

Vector functions

# R is an object-oriented programming language; everything can be assigned to an object
headlines
##  [1] "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""                                                
##  [2] "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"                                   
##  [3] "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"                                               
##  [4] "\"토종 '칡소' 좀 살려주소\""                                                                  
##  [5] "화이자 백신 호재에 세계 증시·유가 일제히 폭등"                                               
##  [6] "손바닥에 거미 다리 모양 붉은 반점 생겼다면 \"간 검사 받으세요\""                              
##  [7] "검찰 '뇌물·횡령 혐의' 홍문종 징역9년 구형..洪 \"조작극\"(종합)"                              
##  [8] "무기 싣고 개표소로 돌진.. 펜실베이니아는 전쟁터였다"                                          
##  [9] "일제강점기 '명륜학원 졸업사진'..전주 최고 유교 기록물 선정"                                   
## [10] "세계인구 3분의 1 거대 경제권 탄생 임박..RCEP 협상 타결"                                       
## [11] "몸살 앓는 국토 대동맥 경부고속도로..수혈 위해 도심지역 입체화 시급"                           
## [12] "'돈세탁 혐의' 손정우, 구속영장 기각..\"도주우려 없어\""                                       
## [13] "박지원 만난 日집권당 2인자 \"신뢰 확신\"..한일관계 기대 발언"                                 
## [14] "철책 넘은 北 주민에 놀란 육군, 후방지역 대침투작전 점검"                                      
## [15] "\"언성 높이지 마세요\"..평택교육청, 의원 질의에 맞불 '행감 중지'"                             
## [16] "'어제의 동지' 트럼프에 일격..伊 베를루스코니 \"너무 거만했다\""                               
## [17] "'태움' 고통받다 극단적 선택..故 서지윤 간호사 산재 인정"                                      
## [18] "트럼프 '계산된 버티기', 2024년 대선 재출마 노리나"                                            
## [19] "'마지막 여행' 다녀온 김철민 \"다시 항암치료..끝까지 버틸 것\""                                
## [20] "윤석열, 차장들에게 '국민의 검찰' 강조..\"현안 언급 없었다\"(종합)"                            
## [21] "'코로나 이후 도시 공간' 제언, 유현준 교수 \"사람 많이 모일수록 좋은 도시란 공식 끝났다\""     
## [22] "[바이든 시대] 트럼프 지명 조달청장 요지부동..인수 지연"                                       
## [23] "[바이든 시대] 미 잡지가 본 '루저' 트럼프, 필사적으로 버티는 이유"                             
## [24] "'하늘의 응급실' 의무후송 전용헬기 軍 최초 도입"                                               
## [25] "난치성 파킨슨 증후군 치료 가능성 열렸다"                                                      
## [26] "푸틴이 바이든 축하 안하는 이유..크렘린 \"공식개표결과 나와야\""                               
## [27] "첫 '영구제명' 변호사, 또 실형..해임 경찰관에게 뇌물수수"                                      
## [28] "갓난 아기 때리고 던지고..CCTV에 '쿵' 소리까지"                                                
## [29] "여동생 밸러리가 이방카 역할하나..'바이든 패밀리' 눈길"                                        
## [30] "'웰컴 투 비디오' 손정우, 구속영장 기각..\"구속 사유 인정 어려워\""                            
## [31] "[단독] HDC현산 아시아나 포기안했나 \"금호리조트 매각말라\""                                   
## [32] "홍준표 \"전셋집 구했나\"..홍남기 \"개인적 상황이니 나중에\""                                  
## [33] "[바이든 시대] 트럼프에 누가 직언할까..\"측근들, 패배 알지만 조용\""                           
## [34] "만화계 오스카상 '쾌거'..세계가 격찬한 한국의 '그래픽 노블'"                                   
## [35] "바이든 코로나 부터 잡아라!..한국 언급한 측근 주목"                                            
## [36] "[바이든 시대] 일본 신문 \"바이든, 트럼프보다 한미관계 중시할 것\""                            
## [37] "성윤모 \"월성1호기 관련 압수수색에 매우 당혹\""                                               
## [38] "울산 남구 아파트 11층서 불..3천만원 피해"                                                     
## [39] "문 대통령, '바이든 시대' 공식화..\"바이든 사람들과 다방면 소통할 것\""                        
## [40] "물만 먹어도 살쪄? 기초대사량 늘리는 7가지 팁"                                                 
## [41] "코로나19 국내 확진자, 5주 연속 증가세..거리 두기 1.5단계 '경고등'"                            
## [42] "고개부터 숙인 민주당..국민의힘은 줄 잇는 출사표"                                              
## [43] "한번에 2,300억 줄여..학교 현장 비상"                                                          
## [44] "정품 마스크라더니..쿠팡, 뒤늦게 '무허가 마스크' 환불조치"                                     
## [45] "삼부토건, '이낙연 민주당 대표 동생' 이계연씨 대표 선임"                                       
## [46] "황상무 전 앵커, KBS에 사의 표명 \"공영방송, 한쪽 진영 서면 안 돼\""                           
## [47] "[바이든 시대] 트럼프 언급 한 마디 없이.. 메르켈 獨 총리, 바이든 당선 축하 성명"               
## [48] "국민의힘, 보궐선거 예선에 '여론조사 100% 적용' 가닥(종합)"                                    
## [49] "\"호수가 보이는 주택 갖고 싶어서\" 할아버지 살해한 美 20대 손녀"                              
## [50] "[주진우 라이브] 정세현 전 장관 \"바이든 정권 출범 후 복잡한 북핵 문제 셈법, 종전선언이 입구\""
h_vector <- headlines[1:5]
h_vector
## [1] "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""             
## [2] "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"
## [3] "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"            
## [4] "\"토종 '칡소' 좀 살려주소\""                               
## [5] "화이자 백신 호재에 세계 증시·유가 일제히 폭등"
companies
##  [1] "한국일보"   "한국일보"   "국민일보"   "경향신문"   "뉴스1"     
##  [6] "주간동아"   "뉴스1"      "오마이뉴스" "연합뉴스"   "연합뉴스"  
## [11] "노컷뉴스"   "뉴시스"     "연합뉴스"   "뉴시스"     "뉴스1"     
## [16] "연합뉴스"   "세계일보"   "한겨레"     "이데일리"   "뉴시스"    
## [21] "경향신문"   "연합뉴스"   "연합뉴스"   "KBS"        "뉴시스"    
## [26] "연합뉴스"   "KBS"        "MBC"        "채널A"      "이데일리"  
## [31] "조선일보"   "연합뉴스"   "연합뉴스"   "KBS"        "KBS"       
## [36] "연합뉴스"   "한겨레"     "연합뉴스"   "한국일보"   "코메디닷컴"
## [41] "경향신문"   "YTN"        "KBS"        "SBSCNBC"    "연합뉴스"  
## [46] "뉴스1"      "한국일보"   "뉴시스"     "머니투데이" "KBS"
c_vector <- companies[1:5]
c_vector
## [1] "한국일보" "한국일보" "국민일보" "경향신문" "뉴스1"
dates
## [1] 20201025 20201026 20201027 20201028 20201029 20201030 20201031
d_vector <- c(rep(dates[1],3),rep(dates[2],2))
d_vector
## [1] 20201025 20201025 20201025 20201026 20201026

list( )

What is a vector object? A collection of ordered elements in the same nature.

Ex) a vector of headlines; a vector of company names; a vector of dates …

What is a list object?

A vector with possible heterogeneous elements. That is, a list is collection of elements which can be of different contents or types.

The elements of a list can include character vectors and numeric vectors at once.

Let say we want to generate a list object that contains the above three vector objects all together.

We can use a function list( ) here.

List1 <- list(headline=h_vector, company=c_vector, date=d_vector) # Generate a list object, List1, to contain all the elements that are named "headline", "company", and "date"
List1
## $headline
## [1] "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""             
## [2] "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"
## [3] "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"            
## [4] "\"토종 '칡소' 좀 살려주소\""                               
## [5] "화이자 백신 호재에 세계 증시·유가 일제히 폭등"            
## 
## $company
## [1] "한국일보" "한국일보" "국민일보" "경향신문" "뉴스1"   
## 
## $date
## [1] 20201025 20201025 20201025 20201026 20201026
length(List1) # The function, length, calculates how many elements are in any R object (vectors, lists, & factors).
## [1] 3
class(List1) # R is an object-oriented style of programming. The function, class, allows us to know what type an object belongs to. It can be numeric, character, logical, list, and so on...
## [1] "list"
names(List1) # To get or set the names of an object; Here, elements' names are "headline", "company", and "date"
## [1] "headline" "company"  "date"
List1[1:2] # returns a new list object that contains the first and the second elements. What is length(List1[1:2])?
## $headline
## [1] "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""             
## [2] "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"
## [3] "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"            
## [4] "\"토종 '칡소' 좀 살려주소\""                               
## [5] "화이자 백신 호재에 세계 증시·유가 일제히 폭등"            
## 
## $company
## [1] "한국일보" "한국일보" "국민일보" "경향신문" "뉴스1"
List1[2] # returns a new list object that contains the second element only. What is length(List1[2])?
## $company
## [1] "한국일보" "한국일보" "국민일보" "경향신문" "뉴스1"
length(List1[2])
## [1] 1
List1[[2]] # returns a vector object that contains five elements of company names in the second element of List1. What is length(List1[[2]])? 
## [1] "한국일보" "한국일보" "국민일보" "경향신문" "뉴스1"
length(List1[[2]])
## [1] 5
List1['headline'] # returns a new list with the element named 'headline' only
## $headline
## [1] "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""             
## [2] "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"
## [3] "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"            
## [4] "\"토종 '칡소' 좀 살려주소\""                               
## [5] "화이자 백신 호재에 세계 증시·유가 일제히 폭등"
List1[['headline']] # returns a vector with the elements of the list element named 'headline'
## [1] "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""             
## [2] "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"
## [3] "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"            
## [4] "\"토종 '칡소' 좀 살려주소\""                               
## [5] "화이자 백신 호재에 세계 증시·유가 일제히 폭등"

Why is list( ) important in web scraping?

Web data are structured at multiple levels. The list( ) function is useful for dealing with hierarchical data.

Ex) DAUM News > Ranking News > Popular News > Top 50 List on Oct/25, Top 50 List on Oct/26, Top 50 List on Oct/27 …

Let say we have a list of ten URLs for popular news at DAUM on different dates

# Example
urls
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
## [2] "https://news.daum.net/ranking/popular?regDate=20201026"
## [3] "https://news.daum.net/ranking/popular?regDate=20201027"
## [4] "https://news.daum.net/ranking/popular?regDate=20201028"
## [5] "https://news.daum.net/ranking/popular?regDate=20201029"
## [6] "https://news.daum.net/ranking/popular?regDate=20201030"
## [7] "https://news.daum.net/ranking/popular?regDate=20201031"
class(urls)
## [1] "character"
urls[1]
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
urls_list <- as.list(urls)
urls_list
## [[1]]
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
## 
## [[2]]
## [1] "https://news.daum.net/ranking/popular?regDate=20201026"
## 
## [[3]]
## [1] "https://news.daum.net/ranking/popular?regDate=20201027"
## 
## [[4]]
## [1] "https://news.daum.net/ranking/popular?regDate=20201028"
## 
## [[5]]
## [1] "https://news.daum.net/ranking/popular?regDate=20201029"
## 
## [[6]]
## [1] "https://news.daum.net/ranking/popular?regDate=20201030"
## 
## [[7]]
## [1] "https://news.daum.net/ranking/popular?regDate=20201031"
class(urls_list)
## [1] "list"
urls_list[[1]] # URL for popular news at DAUM on 10/25
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
urls_list[[2]] # URL for popular news at DAUM on 10/26
## [1] "https://news.daum.net/ranking/popular?regDate=20201026"

How to turn a list into a vector

#unlist( ) is a function to turn a list object into a vector object
#be cautious about using the unlist function
class(urls_list)
## [1] "list"
unlist(urls_list) # turn a list object into a vector object
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
## [2] "https://news.daum.net/ranking/popular?regDate=20201026"
## [3] "https://news.daum.net/ranking/popular?regDate=20201027"
## [4] "https://news.daum.net/ranking/popular?regDate=20201028"
## [5] "https://news.daum.net/ranking/popular?regDate=20201029"
## [6] "https://news.daum.net/ranking/popular?regDate=20201030"
## [7] "https://news.daum.net/ranking/popular?regDate=20201031"
class(unlist(urls_list))
## [1] "character"
urls_list[[2]]
## [1] "https://news.daum.net/ranking/popular?regDate=20201026"
unlist(urls_list)
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
## [2] "https://news.daum.net/ranking/popular?regDate=20201026"
## [3] "https://news.daum.net/ranking/popular?regDate=20201027"
## [4] "https://news.daum.net/ranking/popular?regDate=20201028"
## [5] "https://news.daum.net/ranking/popular?regDate=20201029"
## [6] "https://news.daum.net/ranking/popular?regDate=20201030"
## [7] "https://news.daum.net/ranking/popular?regDate=20201031"

unlist( ) allows us to combine a list object’s elements into a vector object

The apply() Family

apply() and its derivative functions allow crossing the data in a number of ways and avoid explicit use of loop constructs. They act on an input list, matrix or array and apply a named function with one or several optional arguments.

lapply( ): Applies a function to a list and returns a list object

lapply( ) applies a specified function to each element of a list and returns a new list object of the same length as the input list object. Each element of which is the result of applying a function to the corresponding element of the input list.

l in lapply( ) stands for list

List2 <- list(1:3,4:6,7:9)
List2
## [[1]]
## [1] 1 2 3
## 
## [[2]]
## [1] 4 5 6
## 
## [[3]]
## [1] 7 8 9
add_two <- function(x){
  y <- x + 2
  return(y)
}

lapply(List2, add_two) # returns a list object of results from applying a function "mean" to each element of List2 
## [[1]]
## [1] 3 4 5
## 
## [[2]]
## [1] 6 7 8
## 
## [[3]]
## [1]  9 10 11

sapply( ): Applies a function to a list and returns a vector (or matrix) object

sapply( ) applies a specified function to each element of a list and returns a vector object when possible. It is the same as applying the function unlist( ) to the result of lapply( ).

List2
## [[1]]
## [1] 1 2 3
## 
## [[2]]
## [1] 4 5 6
## 
## [[3]]
## [1] 7 8 9
sapply(List2, add_two) # applies a function "add_two" to elements as vectors in List2 as a list
##      [,1] [,2] [,3]
## [1,]    3    6    9
## [2,]    4    7   10
## [3,]    5    8   11

sapply( ) is also applicable to elements in different formats.

List1
## $headline
## [1] "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""             
## [2] "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"
## [3] "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"            
## [4] "\"토종 '칡소' 좀 살려주소\""                               
## [5] "화이자 백신 호재에 세계 증시·유가 일제히 폭등"            
## 
## $company
## [1] "한국일보" "한국일보" "국민일보" "경향신문" "뉴스1"   
## 
## $date
## [1] 20201025 20201025 20201025 20201026 20201026
sapply(List1, str_length)
##      headline company date
## [1,]       28       4    8
## [2,]       36       4    8
## [3,]       27       4    8
## [4,]       16       4    8
## [5,]       26       3    8

tapply( ): Useful in applying to table

tapply( ) is used for applying a specified function to each element of a vector, grouped by another vector.

library(tidyverse)
## -- Attaching packages ---------------------------------- tidyverse 1.3.0 --
## √ ggplot2 3.3.0     √ purrr   0.3.4
## √ tibble  3.0.0     √ dplyr   1.0.1
## √ tidyr   1.0.2     √ forcats 0.5.0
## √ readr   1.3.1
## -- Conflicts ------------------------------------- tidyverse_conflicts() --
## x dplyr::filter()         masks stats::filter()
## x readr::guess_encoding() masks rvest::guess_encoding()
## x dplyr::lag()            masks stats::lag()
## x purrr::pluck()          masks rvest::pluck()
## x rvest::xml()            masks XML::xml()
mytable <- tibble(headline=h_vector, company=c_vector, date=d_vector) # Create a tibble object (dataframe) with three variables
mytable # returns a table with the three vectors
## # A tibble: 5 x 3
##   headline                                                     company      date
##   <chr>                                                        <chr>       <dbl>
## 1 "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""              한국일보 20201025
## 2 "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나" 한국일보 20201025
## 3 "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"             국민일보 20201025
## 4 "\"토종 '칡소' 좀 살려주소\""                                경향신문 20201026
## 5 "화이자 백신 호재에 세계 증시·유가 일제히 폭등"              뉴스1    20201026
mytable$headline # $ sign selects a column of a data frame named "headline"
## [1] "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""             
## [2] "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"
## [3] "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"            
## [4] "\"토종 '칡소' 좀 살려주소\""                               
## [5] "화이자 백신 호재에 세계 증시·유가 일제히 폭등"
mytable$company
## [1] "한국일보" "한국일보" "국민일보" "경향신문" "뉴스1"
mytable$date
## [1] 20201025 20201025 20201025 20201026 20201026

Say we want to count how many times each word appears in doc1 and doc2. Here each word can be grouped by the variable wordlist. tapply(x,y,length): Applies the function length() to x as a vector of frequency in each doc, grouped by y as another vector of words.

tapply(mytable$headline, mytable$date, str_length) # applies the function length to mytable$headline, grouped by mytable$date, and returns the result: the number of characters in each headline
## $`20201025`
## [1] 28 36 27
## 
## $`20201026`
## [1] 16 26

tapply(x,y,length): Applies the function str_length() to x as a vector of character length in each headline, grouped by y as another vector of dates.

Let’s practice on tapply( )

Let’s calculate how many headlines are in each company and how many characters are in the headlines, using the function tapply( ).

headline_df <- tibble(headlines, companies) # creates a data frame including two vectors as columns
headline_df
## # A tibble: 50 x 2
##    headlines                                                         companies 
##    <chr>                                                             <chr>     
##  1 "화이자 \"임상 중인 백신, 90% 넘게 효과 있다\""                   한국일보  
##  2 "'대권 도전' 시동 건 박용진, 與 대선 레이스 '다크호스' 되나"      한국일보  
##  3 "소화불량 7년 시달린 그녀.. 원인은 편두통이었다"                  국민일보  
##  4 "\"토종 '칡소' 좀 살려주소\""                                     경향신문  
##  5 "화이자 백신 호재에 세계 증시·유가 일제히 폭등"                   뉴스1     
##  6 "손바닥에 거미 다리 모양 붉은 반점 생겼다면 \"간 검사 받으세요\"" 주간동아  
##  7 "검찰 '뇌물·횡령 혐의' 홍문종 징역9년 구형..洪 \"조작극\"(종합)"  뉴스1     
##  8 "무기 싣고 개표소로 돌진.. 펜실베이니아는 전쟁터였다"             오마이뉴스
##  9 "일제강점기 '명륜학원 졸업사진'..전주 최고 유교 기록물 선정"      연합뉴스  
## 10 "세계인구 3분의 1 거대 경제권 탄생 임박..RCEP 협상 타결"          연합뉴스  
## # ... with 40 more rows
# length() & str_length() apply to headline_df$headlines, grouped by headline_df$companies
tapply(headline_df$headlines, headline_df$companies, length) # returns a table
##        KBS        MBC    SBSCNBC        YTN   경향신문   국민일보   노컷뉴스 
##          6          1          1          1          3          1          1 
##      뉴스1     뉴시스 머니투데이   세계일보   연합뉴스 오마이뉴스   이데일리 
##          4          5          1          1         12          1          2 
##   조선일보   주간동아      채널A 코메디닷컴     한겨레   한국일보 
##          1          1          1          1          2          4
tapply(headline_df$headlines, headline_df$companies, str_length)
## $KBS
## [1] 27 33 35 29 23 55
## 
## $MBC
## [1] 29
## 
## $SBSCNBC
## [1] 33
## 
## $YTN
## [1] 27
## 
## $경향신문
## [1] 16 52 42
## 
## $국민일보
## [1] 27
## 
## $노컷뉴스
## [1] 38
## 
## $뉴스1
## [1] 26 38 38 41
## 
## $뉴시스
## [1] 32 32 39 22 36
## 
## $머니투데이
## [1] 37
## 
## $세계일보
## [1] 33
## 
## $연합뉴스
##  [1] 34 35 35 36 32 39 35 33 39 38 25 32
## 
## $오마이뉴스
## [1] 29
## 
## $이데일리
## [1] 36 39
## 
## $조선일보
## [1] 34
## 
## $주간동아
## [1] 36
## 
## $채널A
## [1] 31
## 
## $코메디닷컴
## [1] 26
## 
## $한겨레
## [1] 31 26
## 
## $한국일보
## [1] 28 36 41 48

Let’s apply the function for extracting headlines and companies from the URLs

urls
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
## [2] "https://news.daum.net/ranking/popular?regDate=20201026"
## [3] "https://news.daum.net/ranking/popular?regDate=20201027"
## [4] "https://news.daum.net/ranking/popular?regDate=20201028"
## [5] "https://news.daum.net/ranking/popular?regDate=20201029"
## [6] "https://news.daum.net/ranking/popular?regDate=20201030"
## [7] "https://news.daum.net/ranking/popular?regDate=20201031"
headline_extractor <- function(pageurl) {
  page <- readLines(pageurl)
  page_parsed <- htmlParse(page)
  headlines <- xpathSApply(page_parsed, headline_xpath, xmlValue)
  return(headlines)
}

headline_list <- lapply(urls, headline_extractor)
class(headline_list)
## [1] "list"
length(headline_list)
## [1] 7
company_extractor <- function(pageurl) {
  page <- readLines(pageurl)
  page_parsed <- htmlParse(page)
  companies <- xpathSApply(page_parsed, company_xpath, xmlValue)
  return(companies)
}

company_list <- lapply(urls, company_extractor)
length(company_list)
## [1] 7