knitr::opts_chunk$set( message = FALSE, warning = FALSE, collapse = TRUE, comment = "#>" )
這篇文章介紹如何使用 pttR 從 PTT 網頁版 抓取資料。
文章會用到這些函數:
index2df()
:爬取 PTT 某版的文章列表,並將資料轉換成 data frame。down_html()
:從 index2df()
回傳的網址,下載 PTT 文章至本地電腦。post2df()
:將多篇 PTT 文章轉換成 data frame 。index2df()
是用來抓取 PTT 網頁版的看板文章資料,index
即對應到https://www.ptt.cc/bbs/<看板名稱>/index.html
這個頁面。
index2df()
提供 3 種搜尋頁面的方式:
這裡以含特定關鍵字的頁面範圍為例:
使用關鍵字搜尋,實際上相當於在 PTT 網頁版上方的"搜尋文章..."搜尋關鍵字,而最新的頁面的頁數是 1,越老的頁面數字越大。
set.seed(2018) library(pttR) index_df <- index2df(board = "gossiping", search_term = "魯蛇", search_page = sample(1:20, 3))
set.seed(2018)
我們在八卦板中搜尋關鍵字:魯蛇,
並抓取 r paste(sort(sample(1:20, 3)), sep=", ")
這幾頁的資料。
index2df()
會將網頁的資料整理成一個 data frame,各變項的資料對照實際網頁去看很容易就可了解,例如:
knitr::kable(head(index_df)) str(index_df, nchar.max = 20)
由於頁面的頁碼會不斷改變 (關鍵字搜尋最新頁面永遠是 第一頁[^newest]),文章也常常會被刪除,因此將文章頁面下載至電腦再擷取頁面資訊會是比較建議的方式。
urls <- sample(index_df$link, 5) if (!dir.exists("./loser")) dir.create("./loser") down_html(as_url(urls), dir = "./loser")
as_url()
是一個方便的函數,將部份 URL 轉換成完整的 URL。
在下載完網頁之後,需要將檔案讀進 R,因此需要取得這些檔案在電腦裡的位置:
fpath <- list.files("./loser", full.names = TRUE)
dirpath <- system.file("loser", package = "pttR") fpath <- list.files(dirpath, full.names = T)
接著,將下載下來的 5 個檔案 (5 篇文章) 用post_df
讀入並轉成data_frame
:
post_df <- post2df(fpath)
接著看看跑出來的資料:
str(head(post_df, 3), vec.len = 3, nchar.max = 17, max.level = 2)
可以發現這個 data frame 的comment
與content_urls
是 list-column[^lstcol]。
post_df$comment
的每個元素是一個 data frame,需用[[
,]]
檢視其內容。
這裡檢視post_df
中第一篇文章的留言:
library(magrittr) post_df$comment[[1]] %>% knitr::kable()
[^newest]: 這點和一般頁面不同,第一頁是最舊的,頁碼越大頁面越新,但頁碼的上限似乎是 4 萬頁。目前八卦板最新的頁面是 3 萬多頁,
最舊的頁面是Gossiping/index1.html
。
[^lstcol]: 一般來說,data frame 的一個 cell 都是儲存一個值,因此一個 column 通常是一個atomic vector
。list-column 則為一個 list
,其下的每個 cell 也是一個list
(list[1]
回傳的依然是list
)。在這裡,df$comment
回傳一個長度為 r nrow(df)
的list
。
這是個有點複雜的資料結構,但在這裡卻非常合適:運用list
的 recursive 特性,我們可以將一篇 PTT 文章中的所有留言整理成一個 data frame,將其 儲存在list
的一個 element 中。因此要取得某篇文章的資訊,例如僅需用[[
,]]
脫開 list 結構,取得原來的 data frame
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.