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] "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""     
##  [2] "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"                    
##  [3] "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"              
##  [4] "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"                    
##  [5] "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"                       
##  [6] "네 살 아이 두 눈에 시퍼런 피멍 들 때까지 때린 40대"                          
##  [7] "\"한국은 늘 혁신적\" 투자귀재 짐 로저스가 찍은 '기적의 물질'은?"             
##  [8] "[현장영상] 서울 하늘에 처음 뜬 '드론택시'..누가 탔나? 요금은?"               
##  [9] "윤석열 부인 회사 과세자료 확보..\"무리한 수사\" vs \"원칙대로\""             
## [10] "\"확산세 계속되면 거리두기 격상\"..1.5단계 뭐가 달라지나?"                   
## [11] "美펜실베이니아 \"선거 마감 후 도착 표, 1만개\"..승패 뒤집기 역부족"          
## [12] "[단독] 제넥신, 내년 9월 화이자 넘어서는 백신 출시"                           
## [13] "'화이자 백신' 日 1억 회분 '선주문' 했는데..한국 \"협상 중\""                 
## [14] "제트기 동원해 독일로 환자 이송..\"의료붕괴 위기\""                           
## [15] "\"차라리 경기도 집 사자\"..서울사람 경기도 매입 '역대 최다'"                 
## [16] "[단독] 주요수사 목록서 '조국·정경심' 쏙 뺀 檢.. 정치논리 작용 비판"         
## [17] "[단독]\"위험하다고 말렸는데..\" 음주운전 차량에 23살 배달원 다리 절단"       
## [18] "'술집부터 미행 음주차에 고의 사고' 돈 뜯어낸 20대"                           
## [19] "\"10년 전 헤어진 딸 보고파\" 임종 앞두고 상봉 도운 경찰"                     
## [20] "해남에서 길이 50m 대규모 '진흙가마' 발견..\"해남이 청자 생산지 가능성\""     
## [21] "\"음주운전 안 된다\" 말리던 노모, 아들 차에 참변"                            
## [22] "\"싸우다가 몸값만 키워줬다\"..與, 윤석열 급부상에 속내복잡"                  
## [23] "\"하루 한 끼로 버텨요\"..20대 청년들이 추락한다"                             
## [24] "\"주 52시간 피하자\"..사장님은 회사를 8개로 쪼갰다"                          
## [25] "'추-윤' 갈등 격화..\"윤석열 사퇴하고 정치해라\""                             
## [26] "국민의힘·정의당 손잡자 화들짝 놀란 與..\"중대재해법 우리도 발의\""          
## [27] "'공수처장 후보' 줄줄이 검증대..과거 행적까지 '현미경'(종합)"                 
## [28] "한밤 8천만명 시선을 한 곳에..중국서 대세가 된 '1인 홈쇼핑'"                  
## [29] "익산 사망일가족 가장 \"제가 아내·아들·딸 죽였습니다\" 시인"                
## [30] "바이든 사람들은 읽씹 중인데..방미 강경화의 '난센스 외교'"                    
## [31] "[단독] '학대 동영상' 또 있었다..'두 얼굴의 엄마' 구속"                       
## [32] "26년 전 쫓겨난 서의현, 또다시 조계종을 뒤흔들다"                             
## [33] "새벽 걸려온 소리없는 신고전화, 10대 살린 소방관 집념"                        
## [34] "세입자 내보낸 실거주 집주인..2년간 집팔지도 못한다고?"                       
## [35] "540만원 있던 이만희 통장..어떻게 수십억원 쌓였나?"                           
## [36] "윤석열 부인 회사 과세자료 확보..\"보복 수사 NO\""                            
## [37] "쌍용양회 우선주 '폭탄돌리기' 끝나..37억원 '휴지' 됐다(종합2보)"              
## [38] "'시속 21km' 양재IC 교통체증 뚫리나..12일 매헌지하차도 수서방향 개통"         
## [39] "검찰 '자녀 입시비리 의혹' 나경원 딸 다닌 성신여대 압수수색"                  
## [40] "바이든 측 만난 강경화 \"북미대화, 정상 차원의 관심 필요\""                   
## [41] "\"교수 출신은 처음..민주노총, 확 바꾸겠다\""                                 
## [42] "\"김현미 한마디에 거지 아파트 됐다\" 일산 주민들 '부글부글'"                 
## [43] "[단독]검찰, '자녀 특혜 의혹' 나경원 딸이 다닌 대학 압수수색"                 
## [44] "아침에 '이것' 한 잔.. 체중감량, 콜레스테롤 배출에 도움"                      
## [45] "하루 10여명 방문..포항 이명박 전 대통령 기념관 운영 논란"                    
## [46] "교사들 \"코로나19 장기화, 대면수업 늘려야 .. 교육부 예산은 '원격수업' 치중\""
## [47] "秋, '지지율 1위' 尹 맹공..\"사퇴하고 정치하라\"(종합)"                       
## [48] "중부고속도로 증평IC 인근 7중 추돌..1명 사망·3명 부상(종합)"                 
## [49] "유통기한 지난 음식 버리지 마세요..우유 50일까지 'OK'"                        
## [50] "한국인 中 오려고? 40만원 검사 받아라..중국인 韓올땐 \"공짜\""
companies <- xpathSApply(page_parsed, company_xpath, xmlValue)
companies
##  [1] "뉴스1"      "오마이뉴스" "매일경제"   "시사저널"   "중앙일보"  
##  [6] "연합뉴스"   "머니투데이" "KBS"        "KBS"        "KBS"       
## [11] "뉴시스"     "매일경제"   "채널A"      "MBC"        "뉴시스"    
## [16] "세계일보"   "동아일보"   "뉴시스"     "연합뉴스"   "KBS"       
## [21] "SBS"        "연합뉴스"   "MBC"        "한국경제"   "MBC"       
## [26] "서울신문"   "연합뉴스"   "연합뉴스"   "세계일보"   "중앙일보"  
## [31] "MBC"        "한국일보"   "뉴시스"     "매일경제"   "노컷뉴스"  
## [36] "SBS"        "연합뉴스"   "중앙일보"   "뉴스1"      "뉴시스"    
## [41] "노컷뉴스"   "뉴시스"     "머니투데이" "헬스조선"   "연합뉴스"  
## [46] "서울신문"   "연합뉴스"   "연합뉴스"   "이데일리"   "중앙일보"

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

library(stringr)
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()?

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){
  y <- str_remove(x, "[[:digit:]]+")
  return(y)
}

?lapply
## starting httpd help server ... done
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
class(headlines)
## [1] "character"
class(c(1,3,5))
## [1] "numeric"

Vector functions

# R is an object-oriented programming language; everything can be assigned to an object
headlines
##  [1] "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""     
##  [2] "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"                    
##  [3] "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"              
##  [4] "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"                    
##  [5] "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"                       
##  [6] "네 살 아이 두 눈에 시퍼런 피멍 들 때까지 때린 40대"                          
##  [7] "\"한국은 늘 혁신적\" 투자귀재 짐 로저스가 찍은 '기적의 물질'은?"             
##  [8] "[현장영상] 서울 하늘에 처음 뜬 '드론택시'..누가 탔나? 요금은?"               
##  [9] "윤석열 부인 회사 과세자료 확보..\"무리한 수사\" vs \"원칙대로\""             
## [10] "\"확산세 계속되면 거리두기 격상\"..1.5단계 뭐가 달라지나?"                   
## [11] "美펜실베이니아 \"선거 마감 후 도착 표, 1만개\"..승패 뒤집기 역부족"          
## [12] "[단독] 제넥신, 내년 9월 화이자 넘어서는 백신 출시"                           
## [13] "'화이자 백신' 日 1억 회분 '선주문' 했는데..한국 \"협상 중\""                 
## [14] "제트기 동원해 독일로 환자 이송..\"의료붕괴 위기\""                           
## [15] "\"차라리 경기도 집 사자\"..서울사람 경기도 매입 '역대 최다'"                 
## [16] "[단독] 주요수사 목록서 '조국·정경심' 쏙 뺀 檢.. 정치논리 작용 비판"         
## [17] "[단독]\"위험하다고 말렸는데..\" 음주운전 차량에 23살 배달원 다리 절단"       
## [18] "'술집부터 미행 음주차에 고의 사고' 돈 뜯어낸 20대"                           
## [19] "\"10년 전 헤어진 딸 보고파\" 임종 앞두고 상봉 도운 경찰"                     
## [20] "해남에서 길이 50m 대규모 '진흙가마' 발견..\"해남이 청자 생산지 가능성\""     
## [21] "\"음주운전 안 된다\" 말리던 노모, 아들 차에 참변"                            
## [22] "\"싸우다가 몸값만 키워줬다\"..與, 윤석열 급부상에 속내복잡"                  
## [23] "\"하루 한 끼로 버텨요\"..20대 청년들이 추락한다"                             
## [24] "\"주 52시간 피하자\"..사장님은 회사를 8개로 쪼갰다"                          
## [25] "'추-윤' 갈등 격화..\"윤석열 사퇴하고 정치해라\""                             
## [26] "국민의힘·정의당 손잡자 화들짝 놀란 與..\"중대재해법 우리도 발의\""          
## [27] "'공수처장 후보' 줄줄이 검증대..과거 행적까지 '현미경'(종합)"                 
## [28] "한밤 8천만명 시선을 한 곳에..중국서 대세가 된 '1인 홈쇼핑'"                  
## [29] "익산 사망일가족 가장 \"제가 아내·아들·딸 죽였습니다\" 시인"                
## [30] "바이든 사람들은 읽씹 중인데..방미 강경화의 '난센스 외교'"                    
## [31] "[단독] '학대 동영상' 또 있었다..'두 얼굴의 엄마' 구속"                       
## [32] "26년 전 쫓겨난 서의현, 또다시 조계종을 뒤흔들다"                             
## [33] "새벽 걸려온 소리없는 신고전화, 10대 살린 소방관 집념"                        
## [34] "세입자 내보낸 실거주 집주인..2년간 집팔지도 못한다고?"                       
## [35] "540만원 있던 이만희 통장..어떻게 수십억원 쌓였나?"                           
## [36] "윤석열 부인 회사 과세자료 확보..\"보복 수사 NO\""                            
## [37] "쌍용양회 우선주 '폭탄돌리기' 끝나..37억원 '휴지' 됐다(종합2보)"              
## [38] "'시속 21km' 양재IC 교통체증 뚫리나..12일 매헌지하차도 수서방향 개통"         
## [39] "검찰 '자녀 입시비리 의혹' 나경원 딸 다닌 성신여대 압수수색"                  
## [40] "바이든 측 만난 강경화 \"북미대화, 정상 차원의 관심 필요\""                   
## [41] "\"교수 출신은 처음..민주노총, 확 바꾸겠다\""                                 
## [42] "\"김현미 한마디에 거지 아파트 됐다\" 일산 주민들 '부글부글'"                 
## [43] "[단독]검찰, '자녀 특혜 의혹' 나경원 딸이 다닌 대학 압수수색"                 
## [44] "아침에 '이것' 한 잔.. 체중감량, 콜레스테롤 배출에 도움"                      
## [45] "하루 10여명 방문..포항 이명박 전 대통령 기념관 운영 논란"                    
## [46] "교사들 \"코로나19 장기화, 대면수업 늘려야 .. 교육부 예산은 '원격수업' 치중\""
## [47] "秋, '지지율 1위' 尹 맹공..\"사퇴하고 정치하라\"(종합)"                       
## [48] "중부고속도로 증평IC 인근 7중 추돌..1명 사망·3명 부상(종합)"                 
## [49] "유통기한 지난 음식 버리지 마세요..우유 50일까지 'OK'"                        
## [50] "한국인 中 오려고? 40만원 검사 받아라..중국인 韓올땐 \"공짜\""
h_vector <- headlines[1:5]
h_vector
## [1] "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""
## [2] "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"               
## [3] "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"         
## [4] "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"               
## [5] "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"
companies
##  [1] "뉴스1"      "오마이뉴스" "매일경제"   "시사저널"   "중앙일보"  
##  [6] "연합뉴스"   "머니투데이" "KBS"        "KBS"        "KBS"       
## [11] "뉴시스"     "매일경제"   "채널A"      "MBC"        "뉴시스"    
## [16] "세계일보"   "동아일보"   "뉴시스"     "연합뉴스"   "KBS"       
## [21] "SBS"        "연합뉴스"   "MBC"        "한국경제"   "MBC"       
## [26] "서울신문"   "연합뉴스"   "연합뉴스"   "세계일보"   "중앙일보"  
## [31] "MBC"        "한국일보"   "뉴시스"     "매일경제"   "노컷뉴스"  
## [36] "SBS"        "연합뉴스"   "중앙일보"   "뉴스1"      "뉴시스"    
## [41] "노컷뉴스"   "뉴시스"     "머니투데이" "헬스조선"   "연합뉴스"  
## [46] "서울신문"   "연합뉴스"   "연합뉴스"   "이데일리"   "중앙일보"
c_vector <- companies[1:5]
c_vector
## [1] "뉴스1"      "오마이뉴스" "매일경제"   "시사저널"   "중앙일보"
class(c_vector)
## [1] "character"
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
class(d_vector)
## [1] "numeric"

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] "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""
## [2] "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"               
## [3] "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"         
## [4] "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"               
## [5] "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"                  
## 
## $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 "numbers", "characters", and "Booleans"
## [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] "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""
## [2] "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"               
## [3] "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"         
## [4] "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"               
## [5] "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"                  
## 
## $company
## [1] "뉴스1"      "오마이뉴스" "매일경제"   "시사저널"   "중앙일보"
List1[2] # returns a new list object that contains the second element only. What is length(List1[2])?
## $company
## [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"      "오마이뉴스" "매일경제"   "시사저널"   "중앙일보"
List1['headline'] # returns a new list with the element named 'headline' only
## $headline
## [1] "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""
## [2] "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"               
## [3] "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"         
## [4] "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"               
## [5] "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"
List1[['headline']] # returns a vector with the elements of the list element named 'headline'
## [1] "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""
## [2] "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"               
## [3] "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"         
## [4] "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"               
## [5] "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"

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"
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"
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"

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.

Function

Function

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
urls[1]
## [1] "https://news.daum.net/ranking/popular?regDate=20201025"
headline_extractor(urls[2])
##  [1] "아내와 성관계 후 갑자기 폭행한 뒤 살해..英 갑부의 두 얼굴"                                                                   
##  [2] "한국은 되고 유럽은 안 되는 이유, '가디언'의 적나라한 지적"                                                                   
##  [3] "[단독] 나라에 낼 돈 130억인데, 조국 모친 \"전재산 9만원\""                                                                   
##  [4] "\"EU 회원국, WTO 총장 선거서 나이지리아 후보 지지에 접근\""                                                                  
##  [5] "살 뺀다고 탄수화물을 끊어? \"줄일 것은 따로 있어요\""                                                                        
##  [6] "온천천에 나타난 진객 연어, \"하루 사이 무슨 일이.. \""                                                                       
##  [7] "어린이집서 친구와 부딪쳐 넘어진 5살..이틀만에 숨져(종합)"                                                                    
##  [8] "싱가포르, 한국 '독감백신 접종 후 사망'에 백신 2종 접종 중단"                                                                 
##  [9] "제2의 '구하라 사건'..딸 숨지자 28년만에 나타난 생모"                                                                         
## [10] "28년만에 나타나 딸 억대 유산 챙긴 친모..간병한 계모에 절도소송까지"                                                          
## [11] "\"고소하니 합의하자고..\" 어느 날 사라진 유튜버, 망가진 그의 삶"                                                             
## [12] "윤석열 화환 '나이트클럽' 조롱한 진혜원..야당 \"부하가 상급자 모욕, 징계감\""                                                 
## [13] "\"질병청 믿고 백신 맞자\"..62~69세 반나절 만에 26만명 접종"                                                                  
## [14] "[주진우 라이브] 함세웅 신부 \"이건희의 '마누라와 자식 빼고 버려라?'..가족에 매몰된 한계가 삼성의 한계이자 우리 시대의 한계\""
## [15] "가수 '상위 1%' 63명 연소득 34억원..1%가 전체소득 53% 차지"                                                                   
## [16] "\"물 찾다 실수로 소주 1병 마셔\".. 음주운전 경찰관의 황당 변명"                                                              
## [17] "\"윤석열 누구랑 밥먹으면 고발할 것..윤석열 정치 방지법 만들어야\""                                                           
## [18] "한 달째 전남대 앞 쓰레기봉투 들고 나타난 20대들"                                                                             
## [19] "이건희 상속세 무려 11조..국가 세입예산마저 뒤흔들었다"                                                                       
## [20] "'전 남편 살해 무기징역' 고유정, 현 남편과 이혼소송서 패소"                                                                   
## [21] "'6.25는 북침' 열 올리는 중국, 동조하는 아이돌..조용한 한국 정부"                                                             
## [22] "[단독] 첫날부터 오작동..2억 원 아끼려다 5명 목숨 잃었다"                                                                     
## [23] "미국서 '살인말벌' 제거 작전..완전무장에 진공청소기 동원"                                                                     
## [24] "허수아비 후보로 세운 청소부, 진짜로 러 시장 되자 벌어진 일"                                                                  
## [25] "'공항 화장실에 버려진 아이' 카타르, 여성승객 강제 자궁 검사"                                                                 
## [26] "부산에 있는 55년 '해운대암소갈비'가 서울에도..법원 \"불법행위\""                                                             
## [27] "추미애, 野 사퇴요구에 \"뭐라 하겠나..장관 한번 해보세요\""                                                                   
## [28] "'#택배기사님감사합니다'..잇단 사망에 \"새벽배송 안 시킨다\""                                                                 
## [29] "\"되찾을 수 없는 건 생명\"..이건희 '가짜 편지' 확산"                                                                         
## [30] "[타봤습니다] 비행기는 탔지만 목적지는 없다..완판된 9만9000원 여행"                                                           
## [31] "\"40만원 과외, 버는건 8만원\" 요즘 대학생들에게 무슨 일이"                                                                   
## [32] "다시 칼 빼든 추미애 \"윤석열 중앙지검장 때 옵티 무혐의, 감찰 예정\"(종합)"                                                   
## [33] "강경화 \"'병역 면탈' 유승준 비자 발급, 허용하지 않기로\""                                                                    
## [34] "바이든 아들은 노트북 수리를 맡겼다, 그것이 화근이었다"                                                                       
## [35] "조국에게 총애받던 박형철, 그가 입 열수록 조국은 다친다"                                                                      
## [36] "'부하' 표현..조수진 \"우병우에 썼잖냐\" 秋 \"기억 없다\""                                                                    
## [37] "김홍희 해경청장 \"충동적 공황상태에서 자진 월북..증거 다수\"(종합)"                                                          
## [38] "[이건희 별세] 사인은 '신부전'..신장이 노폐물 걸러내지 못하는 병"                                                             
## [39] "검찰인사 문제삼는 野에 폭발..추미애 \"총장한테 물어봐라\""                                                                   
## [40] "종전선언 논의하러 美갔는데..北 \"외세 할아비처럼 섬기며 비굴하게 처신\""                                                     
## [41] "추미애, 윤석열 국감 맹공..'직접감찰·해임건의' 꺼냈다"                                                                       
## [42] "추미애 \"김봉현 술접대 검사 수사팀장 투입..사실로 확인\"(종합)"                                                              
## [43] "'시속 166km' 음주운전하다 2명 사망사고 낸 20대 징역 7년"                                                                     
## [44] "\"못살겠다, 불안해서\"..대선 앞두고 총 사러가는 미국인"                                                                      
## [45] "[시선집중] 윤호중 \"윤석열 불쌍하기까지.. 악마에 영혼 판 파우스트 같아\""                                                    
## [46] "어린이집에서 놀던 5살 남아 숨져..경찰 수사"                                                                                  
## [47] "70대 몰던 어린이 통학버스 주유소 돌진..2명 부상"                                                                             
## [48] "박상기 \"내가 윤석열에게 '조국 선처'?..참 어이가 없다\""                                                                     
## [49] "강준만 \"문재인 정권 거의 모든 게 내로남불, 정리하다 포기\""                                                                 
## [50] "삼성전기 3분기 영업이익 3천25억원..작년 동기 대비 59.9%↑(종합)"
headline_list <- lapply(urls, headline_extractor)
class(headline_list[1])
## [1] "list"

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] "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""
## [2] "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"               
## [3] "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"         
## [4] "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"               
## [5] "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"                  
## 
## $company
## [1] "뉴스1"      "오마이뉴스" "매일경제"   "시사저널"   "중앙일보"  
## 
## $date
## [1] 20201025 20201025 20201025 20201026 20201026
lapply(headlines, str_length)
## [[1]]
## [1] 42
## 
## [[2]]
## [1] 33
## 
## [[3]]
## [1] 38
## 
## [[4]]
## [1] 34
## 
## [[5]]
## [1] 36
## 
## [[6]]
## [1] 31
## 
## [[7]]
## [1] 37
## 
## [[8]]
## [1] 38
## 
## [[9]]
## [1] 37
## 
## [[10]]
## [1] 34
## 
## [[11]]
## [1] 39
## 
## [[12]]
## [1] 30
## 
## [[13]]
## [1] 37
## 
## [[14]]
## [1] 28
## 
## [[15]]
## [1] 35
## 
## [[16]]
## [1] 41
## 
## [[17]]
## [1] 41
## 
## [[18]]
## [1] 30
## 
## [[19]]
## [1] 33
## 
## [[20]]
## [1] 43
## 
## [[21]]
## [1] 28
## 
## [[22]]
## [1] 33
## 
## [[23]]
## [1] 28
## 
## [[24]]
## [1] 30
## 
## [[25]]
## [1] 28
## 
## [[26]]
## [1] 37
## 
## [[27]]
## [1] 36
## 
## [[28]]
## [1] 36
## 
## [[29]]
## [1] 33
## 
## [[30]]
## [1] 33
## 
## [[31]]
## [1] 34
## 
## [[32]]
## [1] 28
## 
## [[33]]
## [1] 31
## 
## [[34]]
## [1] 31
## 
## [[35]]
## [1] 30
## 
## [[36]]
## [1] 29
## 
## [[37]]
## [1] 39
## 
## [[38]]
## [1] 43
## 
## [[39]]
## [1] 34
## 
## [[40]]
## [1] 33
## 
## [[41]]
## [1] 25
## 
## [[42]]
## [1] 34
## 
## [[43]]
## [1] 36
## 
## [[44]]
## [1] 33
## 
## [[45]]
## [1] 34
## 
## [[46]]
## [1] 46
## 
## [[47]]
## [1] 33
## 
## [[48]]
## [1] 37
## 
## [[49]]
## [1] 33
## 
## [[50]]
## [1] 36
unlist(lapply(headlines, str_length))
##  [1] 42 33 38 34 36 31 37 38 37 34 39 30 37 28 35 41 41 30 33 43 28 33 28 30 28
## [26] 37 36 36 33 33 34 28 31 31 30 29 39 43 34 33 25 34 36 33 34 46 33 37 33 36
class(unlist(lapply(headlines, str_length)))
## [1] "integer"
class(lapply(headlines, str_length))
## [1] "list"
sapply(headlines, str_length)
##      이용수 할머니 "군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생" 
##                                                                         42 
##                     [단독] "경비원에게 이런 일을, 너무 잔인" 대학생의 일갈 
##                                                                         33 
##             '윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진' 
##                                                                         38 
##                   국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까 
##                                                                         34 
##                      시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까 
##                                                                         36 
##                         네 살 아이 두 눈에 시퍼런 피멍 들 때까지 때린 40대 
##                                                                         31 
##              "한국은 늘 혁신적" 투자귀재 짐 로저스가 찍은 '기적의 물질'은? 
##                                                                         37 
##              [현장영상] 서울 하늘에 처음 뜬 '드론택시'..누가 탔나? 요금은? 
##                                                                         38 
##                윤석열 부인 회사 과세자료 확보.."무리한 수사" vs "원칙대로" 
##                                                                         37 
##                    "확산세 계속되면 거리두기 격상"..1.5단계 뭐가 달라지나? 
##                                                                         34 
##           美펜실베이니아 "선거 마감 후 도착 표, 1만개"..승패 뒤집기 역부족 
##                                                                         39 
##                          [단독] 제넥신, 내년 9월 화이자 넘어서는 백신 출시 
##                                                                         30 
##                  '화이자 백신' 日 1억 회분 '선주문' 했는데..한국 "협상 중" 
##                                                                         37 
##                            제트기 동원해 독일로 환자 이송.."의료붕괴 위기" 
##                                                                         28 
##                  "차라리 경기도 집 사자"..서울사람 경기도 매입 '역대 최다' 
##                                                                         35 
##        [단독] 주요수사 목록서 '조국·정경심' 쏙 뺀 檢.. 정치논리 작용 비판 
##                                                                         41 
##        [단독]"위험하다고 말렸는데.." 음주운전 차량에 23살 배달원 다리 절단 
##                                                                         41 
##                          '술집부터 미행 음주차에 고의 사고' 돈 뜯어낸 20대 
##                                                                         30 
##                      "10년 전 헤어진 딸 보고파" 임종 앞두고 상봉 도운 경찰 
##                                                                         33 
##      해남에서 길이 50m 대규모 '진흙가마' 발견.."해남이 청자 생산지 가능성" 
##                                                                         43 
##                             "음주운전 안 된다" 말리던 노모, 아들 차에 참변 
##                                                                         28 
##                   "싸우다가 몸값만 키워줬다"..與, 윤석열 급부상에 속내복잡 
##                                                                         33 
##                              "하루 한 끼로 버텨요"..20대 청년들이 추락한다 
##                                                                         28 
##                           "주 52시간 피하자"..사장님은 회사를 8개로 쪼갰다 
##                                                                         30 
##                              '추-윤' 갈등 격화.."윤석열 사퇴하고 정치해라" 
##                                                                         28 
##           국민의힘·정의당 손잡자 화들짝 놀란 與.."중대재해법 우리도 발의" 
##                                                                         37 
##                '공수처장 후보' 줄줄이 검증대..과거 행적까지 '현미경'(종합) 
##                                                                         36 
##                 한밤 8천만명 시선을 한 곳에..중국서 대세가 된 '1인 홈쇼핑' 
##                                                                         36 
##                 익산 사망일가족 가장 "제가 아내·아들·딸 죽였습니다" 시인 
##                                                                         33 
##                   바이든 사람들은 읽씹 중인데..방미 강경화의 '난센스 외교' 
##                                                                         33 
##                      [단독] '학대 동영상' 또 있었다..'두 얼굴의 엄마' 구속 
##                                                                         34 
##                            26년 전 쫓겨난 서의현, 또다시 조계종을 뒤흔들다 
##                                                                         28 
##                       새벽 걸려온 소리없는 신고전화, 10대 살린 소방관 집념 
##                                                                         31 
##                      세입자 내보낸 실거주 집주인..2년간 집팔지도 못한다고? 
##                                                                         31 
##                          540만원 있던 이만희 통장..어떻게 수십억원 쌓였나? 
##                                                                         30 
##                             윤석열 부인 회사 과세자료 확보.."보복 수사 NO" 
##                                                                         29 
##             쌍용양회 우선주 '폭탄돌리기' 끝나..37억원 '휴지' 됐다(종합2보) 
##                                                                         39 
##        '시속 21km' 양재IC 교통체증 뚫리나..12일 매헌지하차도 수서방향 개통 
##                                                                         43 
##                 검찰 '자녀 입시비리 의혹' 나경원 딸 다닌 성신여대 압수수색 
##                                                                         34 
##                    바이든 측 만난 강경화 "북미대화, 정상 차원의 관심 필요" 
##                                                                         33 
##                                  "교수 출신은 처음..민주노총, 확 바꾸겠다" 
##                                                                         25 
##                  "김현미 한마디에 거지 아파트 됐다" 일산 주민들 '부글부글' 
##                                                                         34 
##                [단독]검찰, '자녀 특혜 의혹' 나경원 딸이 다닌 대학 압수수색 
##                                                                         36 
##                     아침에 '이것' 한 잔.. 체중감량, 콜레스테롤 배출에 도움 
##                                                                         33 
##                   하루 10여명 방문..포항 이명박 전 대통령 기념관 운영 논란 
##                                                                         34 
## 교사들 "코로나19 장기화, 대면수업 늘려야 .. 교육부 예산은 '원격수업' 치중" 
##                                                                         46 
##                        秋, '지지율 1위' 尹 맹공.."사퇴하고 정치하라"(종합) 
##                                                                         33 
##                중부고속도로 증평IC 인근 7중 추돌..1명 사망·3명 부상(종합) 
##                                                                         37 
##                       유통기한 지난 음식 버리지 마세요..우유 50일까지 'OK' 
##                                                                         33 
##                 한국인 中 오려고? 40만원 검사 받아라..중국인 韓올땐 "공짜" 
##                                                                         36
class(sapply(headlines, str_length))
## [1] "integer"

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 "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""~ 뉴스1      2.02e7
## 2 "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"   오마이뉴스~  2.02e7
## 3 "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"~ 매일경제   2.02e7
## 4 "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"   시사저널   2.02e7
## 5 "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"      중앙일보   2.02e7
mytable$headline # $ sign selects a column of a data frame named "headline"
## [1] "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""
## [2] "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"               
## [3] "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"         
## [4] "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"               
## [5] "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"
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] 42 33 38
## 
## $`20201026`
## [1] 34 36

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 "이용수 할머니 \"군인이 방으로 끌고 갔을 때 '엄마' 부른 소리 아직 생생\""~ 뉴스1    
##  2 "[단독] \"경비원에게 이런 일을, 너무 잔인\" 대학생의 일갈"          오마이뉴스~
##  3 "'윤석열'이 이낙연·이재명 제친 날..출사표 꺼낸 71년생 '박용진'"     매일경제 
##  4 "국시 미응시로 '면허' 못 딴 의대생들..군 입대 어떻게 될까"          시사저널 
##  5 "시속 1000km 뚫었다..서울~부산 20분 '꿈의 열차' 나올까"             중앙일보 
##  6 "네 살 아이 두 눈에 시퍼런 피멍 들 때까지 때린 40대"                연합뉴스 
##  7 "\"한국은 늘 혁신적\" 투자귀재 짐 로저스가 찍은 '기적의 물질'은?"   머니투데이~
##  8 "[현장영상] 서울 하늘에 처음 뜬 '드론택시'..누가 탔나? 요금은?"     KBS      
##  9 "윤석열 부인 회사 과세자료 확보..\"무리한 수사\" vs \"원칙대로\""   KBS      
## 10 "\"확산세 계속되면 거리두기 격상\"..1.5단계 뭐가 달라지나?"         KBS      
## # ... 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        SBS   노컷뉴스      뉴스1     뉴시스   동아일보 
##          4          4          2          2          2          6          1 
##   매일경제 머니투데이   서울신문   세계일보   시사저널   연합뉴스 오마이뉴스 
##          3          2          2          2          1          9          1 
##   이데일리   중앙일보      채널A   한국경제   한국일보   헬스조선 
##          1          4          1          1          1          1
tapply(headline_df$headlines, headline_df$companies, str_length)
## $KBS
## [1] 38 37 34 43
## 
## $MBC
## [1] 28 28 28 34
## 
## $SBS
## [1] 28 29
## 
## $노컷뉴스
## [1] 30 25
## 
## $뉴스1
## [1] 42 34
## 
## $뉴시스
## [1] 39 35 30 31 33 34
## 
## $동아일보
## [1] 41
## 
## $매일경제
## [1] 38 30 31
## 
## $머니투데이
## [1] 37 36
## 
## $서울신문
## [1] 37 46
## 
## $세계일보
## [1] 41 33
## 
## $시사저널
## [1] 34
## 
## $연합뉴스
## [1] 31 33 33 36 36 39 34 33 37
## 
## $오마이뉴스
## [1] 33
## 
## $이데일리
## [1] 33
## 
## $중앙일보
## [1] 36 33 43 36
## 
## $채널A
## [1] 37
## 
## $한국경제
## [1] 30
## 
## $한국일보
## [1] 28
## 
## $헬스조선
## [1] 33

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(url) {
  page <- readLines(url)
  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