Step 3: Retrieve article content
Take 5 minutes to recall where and how you found the content of the article in the structure of the website.
CHU0397 | National Taiwan Normal University
Step 1
Being aware of the steps you are going through if you had to manually copy and paste the data you want into an Excel file, and document each step with as many details as possible.
Step 2
Understanding the structure of a website, how to access the structure of the website, and where the information you want are.
Covered in Week 7 (Steps 1 & 2)
Recall from last week
Please take 5 minutes to recall the different manual steps we went through last week.
Step 1
Being aware of the steps you are going through if you had to manually copy and paste the data you want into an Excel file, and document each step with as many details as possible.
Step 2
Understanding the structure of a website, how to access the structure of the website, and where the information you want are.
Step 3
Finally, mapping the R functions to the information you want.
Covered in Week 7 (Steps 1 & 2)
Content of this week (Step 3)
Please download the script for this week, and place it in your PreprocessingAnalysesR folder.
💻 Please start RStudio and select the project called PreprocessingAnalysesR.
For this task, we will only need four packages:
Generate web addresses that list individual articles based on filters:
https://www.ettoday.net/news/news-list[Base] - [Date] - [Category] .htmFirst, let’s paste a single date and category together:
We use paste0() to stitch the URL together:
To generate links for the whole year, we use a for loop. Every loop has three basic components:
The List: The group of items you want to work through.
The Action: The specific job you want to do for a single item.
The Loop: The process that automatically repeats the action for the next item.
We nest loops for Days, Months, and Years to generate all dates:
Dates_total <- data.frame(matrix(ncol = 1, nrow = 0))
Year <- 2024
Month <- 1:12
Day <- 1:31
for (a in 1:length(Day)){
for (b in 1:length(Month)){
for (c in min(Year):max(Year)){
Dates <- paste0(c, "-", b, "-", a)
Dates <- as.data.frame(Dates)
Dates_total <- rbind(Dates_total, Dates)
}
}
}
Dates_total <- as.character(Dates_total$Dates)
head(Dates_total, 5)[1] "2024-1-1" "2024-2-1" "2024-3-1" "2024-4-1" "2024-5-1"
Next, we attach our categories (e.g., Society & Politics) to our list of dates:
Category_total <- c("6", "1") # 6 = Society, 1 = Politics
URL_total <- data.frame(matrix(ncol = 1, nrow = 0))
for (a in 1:length(Category_total)){
URL_temp <- paste0(ETTodayPageUrl, "-", Dates_total, "-", Category_total[a], ".htm")
URL_temp <- as.data.frame(URL_temp)
URL_total <- rbind(URL_total, URL_temp)
}
URL_total <- as.character(URL_total$URL_temp)
head(URL_total, 5)[1] "https://www.ettoday.net/news/news-list-2024-1-1-6.htm"
[2] "https://www.ettoday.net/news/news-list-2024-2-1-6.htm"
[3] "https://www.ettoday.net/news/news-list-2024-3-1-6.htm"
[4] "https://www.ettoday.net/news/news-list-2024-4-1-6.htm"
[5] "https://www.ettoday.net/news/news-list-2024-5-1-6.htm"
In the script, what would you change if:
You want the articles from May 2022 only?
You don’t want the ‘Politics’ category?
Take 5 minutes to reflect!
Take 5 minutes to recall where and how you found the links in the structure of the website.
Important
Always try with one page first!
Now that we have the list of pages, we extract the links to the individual articles using rvest:
# Read the first page
IndPage <- read_html(URL_total[1])
# Extract specific href links
news_url <- IndPage %>%
html_nodes("div.part_list_2") %>%
html_nodes("h3") %>%
html_nodes("a") %>%
html_attr("href")
news_url [1] "https://www.ettoday.net/news/20240101/2655300.htm"
[2] "https://www.ettoday.net/news/20240101/2655313.htm"
[3] "https://www.ettoday.net/news/20240101/2655305.htm"
[4] "https://www.ettoday.net/news/20240101/2655303.htm"
[5] "https://www.ettoday.net/news/20240101/2655277.htm"
[6] "https://www.ettoday.net/news/20240101/2655264.htm"
[7] "https://www.ettoday.net/news/20240101/2655256.htm"
[8] "https://www.ettoday.net/news/20240101/2655215.htm"
[9] "https://www.ettoday.net/news/20240101/2655126.htm"
[10] "https://www.ettoday.net/news/20240101/2655200.htm"
[11] "https://www.ettoday.net/news/20240101/2655185.htm"
[12] "https://www.ettoday.net/news/20240101/2655161.htm"
[13] "https://www.ettoday.net/news/20240101/2655150.htm"
[14] "https://www.ettoday.net/news/20240101/2655127.htm"
[15] "https://www.ettoday.net/news/20240101/2655143.htm"
[16] "https://www.ettoday.net/news/20240101/2655124.htm"
[17] "https://www.ettoday.net/news/20240101/2655134.htm"
[18] "https://www.ettoday.net/news/20240101/2655055.htm"
[19] "https://www.ettoday.net/news/20240101/2655104.htm"
[20] "https://www.ettoday.net/news/20240101/2655079.htm"
[21] "https://www.ettoday.net/news/20240101/2655082.htm"
[22] "https://www.ettoday.net/news/20240101/2655069.htm"
[23] "https://www.ettoday.net/news/20240101/2655067.htm"
[24] "https://www.ettoday.net/news/20240101/2655059.htm"
[25] "https://www.ettoday.net/news/20240101/2655060.htm"
[26] "https://www.ettoday.net/news/20240101/2655058.htm"
[27] "https://www.ettoday.net/news/20240101/2655056.htm"
[28] "https://www.ettoday.net/news/20240101/2655035.htm"
[29] "https://www.ettoday.net/news/20240101/2655002.htm"
[30] "https://www.ettoday.net/news/20240101/2653821.htm"
[31] "https://www.ettoday.net/news/20240101/2653800.htm"
[32] "https://www.ettoday.net/news/20240101/2654985.htm"
[33] "https://www.ettoday.net/news/20240101/2654981.htm"
[34] "https://www.ettoday.net/news/20240101/2654968.htm"
[35] "https://www.ettoday.net/news/20240101/2654942.htm"
[36] "https://www.ettoday.net/news/20240101/2654951.htm"
[37] "https://www.ettoday.net/news/20240101/2654940.htm"
[38] "https://www.ettoday.net/news/20240101/2654962.htm"
[39] "https://www.ettoday.net/news/20240101/2654966.htm"
[40] "https://www.ettoday.net/news/20240101/2654939.htm"
[41] "https://www.ettoday.net/news/20240101/2654933.htm"
[42] "https://www.ettoday.net/news/20240101/2654925.htm"
[43] "https://www.ettoday.net/news/20240101/2654910.htm"
[44] "https://www.ettoday.net/news/20240101/2653751.htm"
[45] "https://www.ettoday.net/news/20240101/2654866.htm"
[46] "https://www.ettoday.net/news/20240101/2654858.htm"
[47] "https://www.ettoday.net/news/20240101/2653513.htm"
[48] "https://www.ettoday.net/news/20240101/2653353.htm"
[49] "https://www.ettoday.net/news/20240101/2654835.htm"
[50] "https://www.ettoday.net/news/20240101/2654811.htm"
[51] "https://www.ettoday.net/news/20240101/2654807.htm"
[52] "https://www.ettoday.net/news/20240101/2654796.htm"
[53] "https://www.ettoday.net/news/20240101/2654789.htm"
[54] "https://www.ettoday.net/news/20231231/2654760.htm"
[55] "https://www.ettoday.net/news/20231231/2654767.htm"
[56] "https://www.ettoday.net/news/20231231/2654758.htm"
[57] "https://www.ettoday.net/news/20231231/2654749.htm"
[58] "https://www.ettoday.net/news/20231231/2654734.htm"
[59] "https://www.ettoday.net/news/20231231/2654732.htm"
[60] "https://www.ettoday.net/news/20231231/2654722.htm"
[61] "https://www.ettoday.net/news/20231231/2654727.htm"
[62] "https://www.ettoday.net/news/20231231/2654723.htm"
[63] "https://www.ettoday.net/news/20231231/2654718.htm"
[64] "https://www.ettoday.net/news/20231231/2654687.htm"
[65] "https://www.ettoday.net/news/20231231/2654695.htm"
[66] "https://www.ettoday.net/news/20231231/2654692.htm"
[67] "https://www.ettoday.net/news/20231231/2654693.htm"
[68] "https://www.ettoday.net/news/20231231/2654688.htm"
[69] "https://www.ettoday.net/news/20231231/2654686.htm"
[70] "https://www.ettoday.net/news/20231231/2654659.htm"
[71] "https://www.ettoday.net/news/20231231/2654655.htm"
[72] "https://www.ettoday.net/news/20231231/2654650.htm"
[73] "https://www.ettoday.net/news/20231231/2654632.htm"
[74] "https://www.ettoday.net/news/20231231/2654629.htm"
[75] "https://www.ettoday.net/news/20231231/2654614.htm"
[76] "https://www.ettoday.net/news/20231231/2653538.htm"
[77] "https://www.ettoday.net/news/20231231/2654592.htm"
[78] "https://www.ettoday.net/news/20231231/2654557.htm"
[79] "https://www.ettoday.net/news/20231231/2654572.htm"
[80] "https://www.ettoday.net/news/20231231/2654575.htm"
[81] "https://www.ettoday.net/news/20231231/2654564.htm"
[82] "https://www.ettoday.net/news/20231231/2653406.htm"
[83] "https://www.ettoday.net/news/20231231/2654554.htm"
[84] "https://www.ettoday.net/news/20231231/2654550.htm"
[85] "https://www.ettoday.net/news/20231231/2654519.htm"
[86] "https://www.ettoday.net/news/20231231/2654544.htm"
[87] "https://www.ettoday.net/news/20231231/2654511.htm"
[88] "https://www.ettoday.net/news/20231231/2654537.htm"
[89] "https://www.ettoday.net/news/20231231/2654510.htm"
[90] "https://www.ettoday.net/news/20231231/2652951.htm"
[91] "https://www.ettoday.net/news/20231231/2654489.htm"
[92] "https://www.ettoday.net/news/20231231/2654459.htm"
[93] "https://www.ettoday.net/news/20231231/2654486.htm"
[94] "https://www.ettoday.net/news/20231231/2654474.htm"
[95] "https://www.ettoday.net/news/20231231/2654488.htm"
[96] "https://www.ettoday.net/news/20231231/2654471.htm"
[97] "https://www.ettoday.net/news/20231231/2653322.htm"
[98] "https://www.ettoday.net/news/20231231/2654400.htm"
[99] "https://www.ettoday.net/news/20231231/2654433.htm"
[100] "https://www.ettoday.net/news/20231231/2654435.htm"
We repeat this extraction across our entire URL_total list:
URL_IndArticles <- data.frame(matrix(ncol = 1, nrow = 0))
for (i in 1:length(URL_total)){
IndPage <- read_html(URL_total[i])
news_url <- IndPage %>%
html_nodes("div.part_list_2") %>%
html_nodes("h3") %>%
html_nodes("a") %>%
html_attr("href")
news_url <- as.data.frame(news_url)
URL_IndArticles <- rbind(URL_IndArticles, news_url)
}
# Remove any duplicated addresses
article_overview_unique <- unique(URL_IndArticles)Take 5 minutes to recall where and how you found the content of the article in the structure of the website.
We map nodes to extract the specific text (date, title, body) from an individual article:
OneArticle <- read_html(article_overview_unique$news_url[1])
# time of news
news_time <- OneArticle %>%
html_nodes("time") %>%
html_text(trim = TRUE)
# class of news
news_class <- OneArticle %>%
html_nodes(".part_menu_5") %>%
html_nodes("strong") %>%
html_text(trim = TRUE)
# title
news_title <- OneArticle %>%
html_nodes("h1") %>%
html_text(trim = TRUE)
# content
news_body <- OneArticle %>%
html_nodes('div[itemprop="articleBody"]') %>%
html_text(trim = TRUE)
article <- (data.frame(time = news_time,
class = news_class,
title = news_title,
body = news_body,
url = article_overview_unique$news_url[1]))
head(article)When scraping thousands of pages, broken links happen. We wrap our loop in tryCatch() so R skips errors instead of crashing completely:
Article_total <- data.frame()
for (j in 1:length(article_overview_unique$news_url)){
temp <- read_html(article_overview_unique$news_url[j])
# time of news
news_time <- temp %>%
html_nodes("time") %>%
html_text(trim = TRUE)
# class of news
news_class <- temp %>%
html_nodes(".part_menu_5") %>%
html_nodes("strong") %>%
html_text(trim = TRUE)
# title
news_title <- temp %>%
html_nodes("h1") %>%
html_text(trim = TRUE)
# content
news_body <- temp %>%
html_nodes('div[itemprop="articleBody"]') %>%
html_text(trim = TRUE)
# url
news_url <- temp %>%
html_nodes("div.block div.block_content div.part_list_2 h3") %>%
html_nodes("a") %>%
html_attr("href")
Article <- (data.frame(time = news_time,
class = news_class,
title = news_title,
body = news_body,
url = article_overview_unique$news_url[j]))
Article_total <- rbind(Article_total, Article))
}Article_total <- data.frame()
for (j in 1:length(article_overview_unique$news_url)){
tryCatch({
temp <- read_html(article_overview_unique$news_url[j])
# time of news
news_time <- temp %>%
html_nodes("time") %>%
html_text(trim = TRUE)
# class of news
news_class <- temp %>%
html_nodes(".part_menu_5") %>%
html_nodes("strong") %>%
html_text(trim = TRUE)
# title
news_title <- temp %>%
html_nodes("h1") %>%
html_text(trim = TRUE)
# content
news_body <- temp %>%
html_nodes('div[itemprop="articleBody"]') %>%
html_text(trim = TRUE)
# url
news_url <- temp %>%
html_nodes("div.block div.block_content div.part_list_2 h3") %>%
html_nodes("a") %>%
html_attr("href")
Article <- (data.frame(time = news_time,
class = news_class,
title = news_title,
body = news_body,
url = article_overview_unique$news_url[j]))
Article_total <- rbind(Article_total, Article)
}, error=function(e){message("ERROR :",conditionMessage(e), "\n")})
}Article_total <- data.frame()
## Set the progress bar
total_urls <- length(article_overview_unique$news_url)
pb <- progress_bar$new(
format = " Scraping [:bar] :current/:total (:percent) | ETA: :eta",
total = total_urls,
clear = FALSE,
width = 60
)
for (j in 1:length(article_overview_unique$news_url)){
pb$tick()
tryCatch({
temp <- read_html(article_overview_unique$news_url[j])
# time of news
news_time <- temp %>%
html_nodes("time") %>%
html_text(trim = TRUE)
# class of news
news_class <- temp %>%
html_nodes(".part_menu_5") %>%
html_nodes("strong") %>%
html_text(trim = TRUE)
# title
news_title <- temp %>%
html_nodes("h1") %>%
html_text(trim = TRUE)
# content
news_body <- temp %>%
html_nodes('div[itemprop="articleBody"]') %>%
html_text(trim = TRUE)
# url
news_url <- temp %>%
html_nodes("div.block div.block_content div.part_list_2 h3") %>%
html_nodes("a") %>%
html_attr("href")
Article <- (data.frame(time = news_time,
class = news_class,
title = news_title,
body = news_body,
url = article_overview_unique$news_url[j]))
Article_total <- rbind(Article_total, Article)
}, error=function(e){pb$message("ERROR :",conditionMessage(e), "\n")})
}
testit <- function(x = sort(runif(20)), ...)
{
pb <- txtProgressBar(...)
for(i in c(0, x, 1)) {Sys.sleep(0.5); setTxtProgressBar(pb, i)}
Sys.sleep(1)
close(pb)
}Finally, we export the scraped dataset to both an Excel document and a native RData workspace file: