這份作業希望能夠讓你熟悉 Web Scraping 的流程。本次作業的案例為蘋果基金會的捐款平台。對於這樣的捐款平台,就資料新聞的角度來說,我們可以去看哪些人是常見的捐款者?甚至用文字探勘的方法去了解哪些類型的案子是常見的捐款案?就資料科學的角度來說,我們可以抽取出捐款新聞文字描述、記者姓名、捐款類別等來預估最後捐款的總數。
本作業是上述案例的第一步驟,就是獲取資料。請盡可能獲取所有蘋果基金會捐款案的近10頁資料。並且應可獲得每一筆捐款案的以下欄位,前為tibble的指定名稱,括號內為指定變數名稱。
df_case_list,包含捐款案id(case_id)、新聞標題(title)、捐款案時間(date)、捐款案狀態(status)、捐款總額(amount)、新聞連結(link)、捐款明細連結(link_detail)
df_case_donation,包含捐款案id(case_id)、捐款明細連結(link_detail)、捐款者(donator)、捐款金額(donation)、捐款時間(donate_date)
df_case_news,包含新聞連結(link)、新聞內容(text)、新聞發布時間(time)、記者或攝影師(reporter)、首圖圖說(caption)、配圖數量(n_figure)(這很難抓可以放棄)
glimpse()
分別呈現上述 tibble 的長相df_case_list
爬蟲過程與內容,包含捐款案id(case_id)、新聞標題(title)、捐款案時間(date)、捐款案狀態(status)、捐款總額(amount)、新聞連結(link)、捐款明細連結(link_detail)df_case_donation
爬蟲過程與內容,包含捐款案id(case_id)、捐款明細連結(link_detail)、捐款者(donator)、捐款金額(donation)、捐款時間(donate_date)df_case_news
爬蟲過程與內容,包含新聞連結(link)、新聞內容(text)df_case_news
抓到的欄位越多加分越多,你可以多抓新聞標題(title)、新聞發布時間(time)、記者或攝影師(reporter)、首圖配字(caption)、圖片數量(n_figure),並 join df_case_list
and df_case_news
再呈現結果再次重申:圖片數量很難抓,不要花太多時間在上面,我也抓不到!
### your code
library(tidyverse)
# library(httr)
# library(rvest)
#
# p_read_html <- possibly(read_html, otherwise = NULL)
#
# ##### 抓案例
# df_case_list <- tibble()
# for(i in 1:10){
# url <- str_c("https://tw.feature.appledaily.com/charity/projlist/", i)
# html <- url %>% curl::curl(handle = curl::new_handle("useragent" = "Mozilla/5.0")) %>% p_read_html()
# table <- html %>% html_table()
# df_table <-
# table[[1]] %>% as_tibble() %>% slice(-1) %>% `colnames<-`(c("case_id", "title", "date", "status", "amount", "detail"))
#
# link <- html %>% html_nodes(".artcatdetails") %>% html_attr("href")
# link_detail <- html %>% html_nodes(".details") %>% html_attr("href")
# df_case_list_tmp <- df_table %>% bind_cols(tibble(link = link, link_detail = link_detail))
#
# df_case_list <- df_case_list %>% bind_rows(df_case_list_tmp)
# print(i)
# Sys.sleep(20)
# }
#
# df_case_list
# df_case_list %>% distinct(case_id)
# df_case_list %>% write_rds("data/AS08/df_case_list.rds")
# df_case_list %>% write_csv("data/AS08/df_case_list.csv")
#
# ##### 抓捐款清單
# df_case_donation <- tibble()
# index_now <- 1
# index_length <- ceiling(dim(df_case_list)[1]/10)
#
# for(i in index_now:index_length){
# j = i*10-9
# k = j+9
# url = df_case_list %>% select(link_detail) %>% slice(j:k) %>% pull()
#
# html = url %>% map(function(x){x %>% curl::curl(handle = curl::new_handle("useragent" = "Mozilla/5.0")) %>% p_read_html()}) %>%
# set_names(url) %>% compact()
# html_index <- html %>%
# map(function(x){x %>% html_nodes(".addellis-f") %>% html_text() %>% '['(1)}) %>%
# map_lgl(function(x){!is.na(x)})
#
# html_f <- html[html_index]
#
# if(length(html_f)==0) {index_now = index_now + 1;print(str_c("all links are dead: article ",j, " to article ", k));next}
#
# table_raw <- html_f %>% map(function(x){x %>% html_table()})
# df_case_donation_tmp <- table_raw %>% map(function(x){x %>% '[['(2) %>% slice(-1)}) %>% bind_rows(.id = "link_detail") %>% as_tibble() %>%
# `colnames<-`(c("link_detail","donator_order", "donator", "donation", "donate_date"))
#
# df_case_donation <- df_case_donation %>% bind_rows(df_case_donation_tmp)
#
# print(str_c("finished article ", j, " to article ", k))
# index_now = index_now + 1
# Sys.sleep(20)
# closeAllConnections()
# gc()
# }
#
# df_case_donation
# df_case_donation %>% distinct(link_detail)
# df_case_donation %>% count(link_detail)
# df_case_donation %>%
# mutate(case_id = str_remove(link_detail, "https://tw.feature.appledaily.com/charity/projdetail/")) %>%
# write_rds("data/AS08/df_case_donation.rds")
# df_case_donation %>%
# mutate(case_id = str_remove(link_detail, "https://tw.feature.appledaily.com/charity/projdetail/")) %>%
# write_csv("data/AS08/df_case_donation.csv")
#
#
# ##### 抓新聞內容
# df_case_news <- tibble()
# index_now <- 1
# index_length <- ceiling(dim(df_case_list)[1]/10)
#
# for(i in index_now:index_length){
# j = i*10-9
# k = j+9
# i=1
# url = df_case_list %>% select(link) %>% slice(j:k) %>% pull()
#
# html = url %>% map(function(x){x %>% p_read_html()}) %>%
# set_names(url) %>% compact()
# html_index <- html %>%
# map(function(x){x %>% html_nodes(".text_medium") %>% html_text() %>% '['(1)}) %>%
# map_lgl(function(x){!is.na(x)})
#
# html_f <- html[html_index]
#
# if(length(html_f)==0) {index_now = index_now + 1;print(str_c("all links are dead: article ",j, " to article ", k));next}
#
# page_title <- html_f %>% map(function(x){x %>% html_nodes(".text_medium") %>% html_text()}) %>% map(function(x){if(length(x)==0) x = "empty" else(x)})
# page_text <- html_f %>% map(function(x){x %>% html_nodes(".tw-max_width") %>% html_text() %>% str_c(collapse = "::::::")}) %>% map(function(x){if(length(x)==0) x = "empty" else(x)})
# page_reporter <- html_f %>% map(function(x){x %>% html_nodes(".tw-max_width:nth-child(5)") %>% html_text() %>% `[`(1)}) %>% map(function(x){if(length(x)==0) x = "empty" else(x)})
# page_time <- html_f %>% map(function(x){x %>% html_nodes(".timestamp") %>% html_text() %>% `[`(1)}) %>% map(function(x){if(length(x)==0) x = "empty" else(x)})
# page_caption <- html_f %>% map(function(x){x %>% html_nodes(".box--margin-top-lg") %>% html_text()}) %>% map(function(x){if(length(x)==0) x = "empty" else(x)})
#
# df_case_news_tmp <- tibble(link = names(page_title), text = unlist(page_text), reporter = unlist(page_reporter),
# title = unlist(page_title), time = unlist(page_time), caption = unlist(page_caption))
#
# df_case_news <- df_case_news %>% bind_rows(df_case_news_tmp)
# print(str_c("finished article ", j, " to article ", k))
# index_now = index_now + 1
# Sys.sleep(20)
# closeAllConnections()
# gc()
# }
#
# df_case_news
# df_case_news %>% distinct(link)
# df_case_news %>% count(link)
# df_case_news %>% write_rds("data/AS08/df_case_news.rds")
# df_case_news %>% write_csv("data/AS08/df_case_news.csv")
#
# df_case_news <- read_csv("data/AS08/df_case_news.csv")
# df_case_donation <- read_csv("data/AS08/df_case_donation.csv")
# df_case_list <- read_csv("data/AS08/df_case_list.csv")
這邊的 code 請去掉 comment 後執行喔!可以用來確認結果!
### your code
<- read_csv("data/AS08/df_case_list.csv")
df_case_list <- read_csv("data/AS08/df_case_donation.csv")
df_case_donation <- read_csv("data/AS08/df_case_news.csv")
df_case_news
## 檢查
%>% summarise(n_distinct(case_id)) df_case_list
#> # A tibble: 1 x 1
#> `n_distinct(case_id)`
#> <int>
#> 1 200
%>% summarise(n_distinct(link)) df_case_list
#> # A tibble: 1 x 1
#> `n_distinct(link)`
#> <int>
#> 1 200
%>% summarise(n_distinct(link_detail)) df_case_list
#> # A tibble: 1 x 1
#> `n_distinct(link_detail)`
#> <int>
#> 1 200
%>% summarise(n_distinct(link_detail)) df_case_donation
#> # A tibble: 1 x 1
#> `n_distinct(link_detail)`
#> <int>
#> 1 200
%>% summarise(n_distinct(link)) df_case_news
#> # A tibble: 1 x 1
#> `n_distinct(link)`
#> <int>
#> 1 199
## bar chart
<- df_case_donation %>%
df_donator_top mutate(donator = str_split(donator, ",|,|、")) %>%
unnest(c(donator)) %>%
mutate(donator = if_else(str_detect(donator, "善心|匿名|不具名|無"), "匿名", donator)) %>%
count(donator, sort = T) %>% head(20)
%>% slice(1:10) %>% mutate(donator = fct_reorder(donator, n)) %>%
df_donator_top ggplot(aes(donator, n)) + geom_col() +
coord_flip() +
theme_bw() +
guides(fill = FALSE) +
labs(x= "捐款人",y= "捐款次數", title = "捐款芳名錄與捐款次數", caption = "資料:蘋果日報基金會近兩百項案件") +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour = "black")) +
theme(text = element_text(family = "Noto Sans CJK TC Medium"))
## 看長相
%>% glimpse() df_case_list
#> Rows: 200
#> Columns: 8
#> $ case_id <chr> "A5131", "A5130", "A5129", "A5128", "A5127", "A5126", "A51…
#> $ title <chr> "大三男罹血癌 單親母嘆夫已癌逝「老天殘忍」", "婦咬牙作工兼顧癌夫 「為小孩苦往肚裡吞」", "粗工翁腦出血中風…
#> $ date <date> 2021-05-07, 2021-05-06, 2021-05-05, 2021-05-04, 2021-05-0…
#> $ status <chr> "未結案", "未結案", "未結案", "未結案", "未結案", "未結案", "未結案", "未結案", "未…
#> $ amount <dbl> 18365, 122899, 201968, 282653, 498089, 654573, 784644, 809…
#> $ detail <chr> "明細", "明細", "明細", "明細", "明細", "明細", "明細", "明細", "明細", "明細"…
#> $ link <chr> "https://tw.appledaily.com/headline/20210507/VRXKZCX76BDTN…
#> $ link_detail <chr> "https://tw.feature.appledaily.com/charity/projdetail/A513…
%>% glimpse() df_case_donation
#> Rows: 278,365
#> Columns: 6
#> $ link_detail <chr> "https://tw.feature.appledaily.com/charity/projdetail/A5…
#> $ donator_order <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1…
#> $ donator <chr> "張力升", "張元銘", "張元瑄", "陳維全", "劉麗珍", "張凱名", "李鎂鷹", "藍予宏", …
#> $ donation <dbl> 10000, 1500, 1500, 1000, 1000, 1000, 500, 500, 300, 300,…
#> $ donate_date <date> 2021-05-06, 2021-05-07, 2021-05-07, 2021-05-07, 2021-05…
#> $ case_id <chr> "A5131", "A5131", "A5131", "A5131", "A5131", "A5131", "A…
%>% glimpse() df_case_news
#> Rows: 199
#> Columns: 6
#> $ link <chr> "https://tw.appledaily.com/headline/20210507/VRXKZCX76BDTNK7Y…
#> $ text <chr> "「先生是在6年前因口腔癌走的,沒想到今年1月小兒子小文又罹血癌,老天對我很殘忍。」45歲單親媽阿慧(黃之慧)提到22歲、…
#> $ reporter <chr> "報導.攝影/韓旭爾", "報導‧攝影∕張嘉恬", "報導‧攝影/向高彬", "報導.攝影/韓旭爾", "報導‧攝影/向高…
#> $ title <chr> "大三男罹血癌 單親母嘆夫已癌逝「老天殘忍」", "婦咬牙作工兼顧癌夫 「為小孩苦往肚裡吞」", "粗工翁腦出血中風倒 「…
#> $ time <chr> "更新時間: 2021/05/07 03:00", "更新時間: 2021/05/06 03:00", "更新時間: 20…
#> $ caption <chr> "小文(中)罹癌後身體虛弱,媽媽阿慧(左)幫他沖泡營養品補充體力。右為阿慧83歲婆婆。", "阿鴻罹癌無力工作,妻子阿莉(…
## 加分題
%>% left_join(df_case_news) %>% count(is.na(reporter)) df_case_list
#> # A tibble: 2 x 2
#> `is.na(reporter)` n
#> * <lgl> <int>
#> 1 FALSE 190
#> 2 TRUE 10
%>% left_join(df_case_news) %>% count(is.na(time)) df_case_list
#> # A tibble: 2 x 2
#> `is.na(time)` n
#> * <lgl> <int>
#> 1 FALSE 197
#> 2 TRUE 3
%>% left_join(df_case_news) %>%
df_case_list select(case_id, title, date, time, reporter, caption) %>% glimpse()
#> Rows: 200
#> Columns: 6
#> $ case_id <chr> "A5131", "A5130", "A5129", "A5128", "A5127", "A5126", "A5125"…
#> $ title <chr> "大三男罹血癌 單親母嘆夫已癌逝「老天殘忍」", "婦咬牙作工兼顧癌夫 「為小孩苦往肚裡吞」", "粗工翁腦出血中風倒 「…
#> $ date <date> 2021-05-07, 2021-05-06, 2021-05-05, 2021-05-04, 2021-05-03, …
#> $ time <chr> "更新時間: 2021/05/07 03:00", "更新時間: 2021/05/06 03:00", "更新時間: 20…
#> $ reporter <chr> "報導.攝影/韓旭爾", "報導‧攝影∕張嘉恬", "報導‧攝影/向高彬", "報導.攝影/韓旭爾", "報導‧攝影/向高…
#> $ caption <chr> "小文(中)罹癌後身體虛弱,媽媽阿慧(左)幫他沖泡營養品補充體力。右為阿慧83歲婆婆。", "阿鴻罹癌無力工作,妻子阿莉(…