輕鬆學習 R 語言:網頁資料擷取

輕鬆學習 R 語言:網頁資料擷取以 jsonlite、xml2、rvest 套件實踐網站爬蟲Yao-Jen KuoBlockedUnblockFollowFollowingApr 23Photo by Tom Blackout on UnsplashThe world’s most valuable resource is no longer oil, but data.

The Economist獲取資料(Getting Data)在資料科學專案中扮演攻擊發起點,如果這個專案目的是協助我們制定資料驅動的策略(data-driven strategy),而非傳統倚賴直覺的「根據經驗」策略,那麼為專案細心盤點資料來源與整理獲取方法,將可以為決策奠基穩固的基礎。常見的資料來源可以分為三種:檔案資料庫網頁資料擷取在輕鬆學習 R 語言:資料輸入與輸出我們討論了如何透過 R 語言載入表格式檔案(包含 CSV 資料、Excel 試算表)、非表格式檔案(包含 TXT 資料、JSON 資料);在輕鬆學習 R 語言:向資料庫查詢我們簡介如何以 R 語言透過 DBI 與 RSQLite 兩個套件連結本機端的 SQLite 資料庫,並利用 DBI 套件所提供的函數實踐四種常見資料庫表格操作,即所謂的 CRUD:Create、Read、Update 與 Delete。這個小節我們要討論第三種資料來源:網頁,而從網頁擷取資料的技巧,有著另外一個更為眾人耳熟能詳的名稱:網站爬蟲。網站爬蟲的核心任務網站爬蟲的核心任務可以簡單區分為兩個:請求資料(requesting data)與解析資料(parsing data);其中請求資料的運作就像我們在瀏覽器中輸入網址一般,只不過送出請求的管道由瀏覽器改變成為 R 語言程式碼;解析資料的運作則是將伺服器回傳的資料內容去蕪存菁,萃取必要的一小部分。接著我們可依照解析資料的複雜程度將任務再細分為三類:JSON(全名為 JavaScript Object Notation,一種輕量級的資料交換格式)、XML(全名為 Extensible Markup Language)與 HTML(全名為 HyperText Markup Language)。很多的 Web API(全名為 Web Application Programming Interface,意即建構於網站伺服器的應用程式介面,作為不同系統之間的資料傳遞管道)其資料格式皆約定為 JSON 與 XML。如果資料格式是 JSON 在請求資料之後會以 R 語言的 list 或 data.

frame 結構儲存,幾乎沒有額外的解析需求;假使資料格式是標記語言(XML 或 HTML),則會需要繼續以 XPath(提供在 XML/HTML 資料中以 XML 節點找尋特定資料位置的定位方法)或 CSS Selector(提供在 HTML 資料中以層疊樣式表找尋特定資料位置的定位方法)來解析。安裝與載入套件在這個小節中我們主要應用作為網頁資料擷取的套件是 jsonlite 、 xml2 、 magrittr 與 rvest,其中 magrittr 是為了使用 %>% 搭配 rvest 中的函數、xml2 是 rvest 的依賴套件,因此安裝時只需指定 jsonlite、rvest 與 magrittr 即可。我們可以選擇透過命令列(Console)以 install.

packages() 函數進行安裝。## > # 安裝 jsonlite、rvest 與 magrittr## > pkgs <- c("jsonlite", "rvest", "magrittr")## > install.

packages(pkgs)## trying URL 'https://cran.

rstudio.

com/bin/macosx/el-capitan/contrib/3.

5/jsonlite_1.

6.

tgz'## Content type 'application/x-gzip' length 1114907 bytes (1.

1 MB)## ==================================================## downloaded 1.

1 MB## ## trying URL 'https://cran.

rstudio.

com/bin/macosx/el-capitan/contrib/3.

5/rvest_0.

3.

3.

tgz'## Content type 'application/x-gzip' length 912701 bytes (891 KB)## ==================================================## downloaded 891 KB## ## trying URL 'https://cran.

rstudio.

com/bin/macosx/el-capitan/contrib/3.

5/magrittr_1.

5.

tgz'## Content type 'application/x-gzip' length 152395 bytes (148 KB)## ==================================================## downloaded 148 KB## ## ## The downloaded binary packages are in## /var/folders/0b/r__z5mpn6ldgb_w2j7_y_ntr0000gn/T//RtmpjWr2NP/downloaded_packages或是透過圖形化介面(Graphic User Interface, GUI)的方法安裝,在右下角的 packages 頁籤點選 install,再輸入套件名稱接著點選安裝。透過圖形化介面安裝我們可以選擇透過命令列(Console)以 library() 函數將套件載入環境來使用。## > # 載入 jsonlite、rvest 與 magrittr## > library(jsonlite)## > library(rvest)## Loading required package: xml2## > library(magrittr)或是透過圖形化介面(Graphic User Interface, GUI)在右下角的 packages頁籤下搜尋然後將前面的核取方框打勾。擷取 JSON 格式資料接著我們以 jsonlite 套件中的 fromJSON() 函數示範擷取政府資料開放平台:空氣品質指標(AQI)所提供的 Web API 將 JSON 格式資料載入 R 語言中,由於該 Web API 提供的是 Array of JSON,因此擷取之後的資料結構是 data.

frame 。## > # 安裝 jsonlite、rvest 與 magrittr## > #pkgs <- c("jsonlite", "rvest", "magrittr")## > #install.

packages(pkgs)## > # 載入 jsonlite## > library(jsonlite)## > ## > aqi_url <- "https://opendata.

epa.

gov.

tw/ws/Data/AQI/?$format=json"## > aqi <- fromJSON(aqi_url)## > class(aqi)## [1] "data.

frame"## > head(aqi)## SiteName County AQI Pollutant Status SO2 CO CO_8hr O3 O3_8hr PM10 PM2.

5 NO2 NOx NO WindSpeed WindDirec PublishTime PM2.

5_AVG PM10_AVG## 1 屏東(琉球) 屏東縣 設備維護 2.

2 0.

15 0.

2 22 15 20 5.

4 7.

8 2.

4 2.

3 323 2019-04-23 10:00 22## 2 苗栗(後龍) 苗栗縣 66 細懸浮微粒 普通 2.

7 0.

25 0.

2 35 14 23 22 5.

9 9.

9 4 4.

3 208 2019-04-23 10:00 22 26## 3 彰化(大城) 彰化縣 51 細懸浮微粒 普通 2.

1 0.

16 0.

2 29 16 23 14 3.

1 4.

2 1.

1 0.

4 228 2019-04-23 10:00 16 23## 4 臺南(北門) 臺南市 23 良好 1.

4 0.

02 0.

1 25 18 23 9 2.

1 2.

4 0.

3 1.

9 239 2019-04-23 10:00 7 22## 5 富貴角 新北市 62 細懸浮微粒 普通 1.

1 0.

21 0.

2 32 22 43 20 5.

4 6.

9 1.

4 1.

3 274 2019-04-23 10:00 20 39## 6 麥寮 雲林縣 35 良好 2.

1 0.

18 0.

2 24 14 31 13 5.

2 7.

2 2 2.

7 236 2019-04-23 10:00 11 36## SO2_AVG Longitude Latitude## 1 2 120.

377222 22.

352222## 2 2 120.

786028 24.

616369## 3 2 120.

273117 23.

843139## 4 2 120.

124444 23.

264722## 5 1 121.

536763 25.

298562## 6 2 120.

251825 23.

753506同樣以jsonlite 套件中的 fromJSON() 函數示範擷取 data.

nba.

net 所提供的 Web API 將 JSON 格式資料載入 R 語言中,這時由於該 Web API 提供的是 JSON,擷取之後的資料結構則會是 list 。## > # 安裝 jsonlite、rvest 與 magrittr## > #pkgs <- c("jsonlite", "rvest", "magrittr")## > #install.

packages(pkgs)## > # 載入 jsonlite## > library(jsonlite)## > ## > nba_url <- "http://data.

nba.

net/10s/prod/v1/2018/players.

json"## > nba_players <- fromJSON(nba_url)## > class(nba_players)## [1] "list"## > paste(nba_players$league$standard$firstName, nba_players$league$standard$lastName)[1:10]## [1] "Jaylen Adams" "Steven Adams" "Bam Adebayo" "Deng Adel" "LaMarcus Aldridge" "Rawle Alkins" "Grayson Allen" ## [8] "Jarrett Allen" "Kadeem Allen" "Al-Farouq Aminu"擷取 XML 格式資料接著我們利用 xml2 套件示範擷取政府資料開放平台:空氣品質指標(AQI)所提供的 Web API 將 XML 格式資料載入 R 語言中,使用 read_xml() 函數之後獲得的資料結構是命名為 xml_document 的 list,面對 xml_document 可以呼叫 xml2 套件提供的 xml_find_all() 與 xml_text() 函數指定 XPath 並解析出文字格式的資料。## > # 安裝 jsonlite、rvest 與 magrittr## > #pkgs <- c("jsonlite", "rvest", "magrittr")## > #install.

packages(pkgs)## > # 載入 xml2, magrittr## > library(xml2)## > library(magrittr)## > ## > aqi_url <- "https://opendata.

epa.

gov.

tw/ws/Data/AQI/?$format=xml"## > aqi <- read_xml(aqi_url)## > class(aqi)## [1] "xml_document" "xml_node" ## > site_names <- aqi %>%## + xml_find_all(xpath = "//Data/SiteName") %>%## + xml_text()## > class(site_names)## [1] "character"## > site_names## [1] "屏東(琉球)" "苗栗(後龍)" "彰化(大城)" "臺南(北門)" "富貴角" ## [6] "麥寮" "關山" "馬公" "金門" "馬祖" ## [11] "埔里" "復興" "永和" "竹山" "中壢" ## [16] "三重" "冬山" "宜蘭" "陽明" "花蓮" ## [21] "臺東" "恆春" "潮州" "屏東" "小港" ## [26] "前鎮" "前金" "左營" "楠梓" "林園" ## [31] "大寮" "鳳山" "仁武" "橋頭" "美濃" ## [36] "臺南" "安南" "善化" "新營" "嘉義" ## [41] "臺西" "朴子" "新港" "崙背" "斗六" ## [46] "南投" "二林" "線西" "彰化" "西屯" ## [51] "忠明" "大里" "沙鹿" "豐原" "三義" ## [56] "苗栗" "頭份" "新竹" "竹東" "湖口" ## [61] "龍潭" "平鎮" "觀音" "大園" "桃園" ## [66] "大同" "松山" "古亭" "萬華" "中山" ## [71] "士林" "淡水" "林口" "菜寮" "新莊" ## [76] "板橋" "土城" "新店" "萬里" "汐止" ## [81] "基隆"擷取 HTML 格式資料向伺服器發送請求後若是獲得 HTML 格式資料,將需要進行較複雜的解析任務,原因是請求後的 HTML 文件包含了太多不需要的資訊,諸如包含在 <style></style> 標籤中的 CSS(Cascading Style Sheets,階層樣式表)語言或者包含在 <script></script> 標籤中的 JavaScript 語言。所以熟練定位網頁中特定資料位址的技巧就變得十分重要,如同在地圖上加入標記(Marker)一般,我們需要景點或建築物的位址,可以是門牌號碼、詳細地址甚至是精準的經緯度。在網頁上標記資料為止有非常多方法能夠表示,常見的像是使用:HTML 的標籤名稱HTML 標籤中給予的 idHTML 標籤中給予的 classCSS 選擇器(CSS Selector)XPath考量多數資料科學愛好者並不具備網頁工程師的背景技能,透過 Chrome 瀏覽器的外掛來取得資料所在的 CSS 選擇器或者 XPath 是快速入門的捷徑。Chrome 瀏覽器外掛:Selector Gadget透過下列步驟將 Selector Gadget 外掛加入 Chrome 瀏覽器。前往 Chrome Web Store,點選外掛(Extensions)搜尋 Selector Gadget 並點選加入到 Chrome 瀏覽器確認要加入 Selector Gadget完成安裝前往 Chrome Web Store,點選外掛(Extensions)搜尋 Selector Gadget 並點選加入到 Chrome 瀏覽器確認要加入 Selector Gadget完成安裝依照下列步驟定位 HTML 格式資料的 CSS 選擇器。點選 Selector Gadget 的外掛圖示留意 Selector Gadget 的 CSS 選擇器移動滑鼠到想要定位的元素在想要定位的評分上面點選左鍵,留意此時的 CSS 選擇器位址與資料筆數,通常在第一次點擊後網頁上很多的資料都會同時被選到(以黃底標記),Clear 後面數字表示有多少筆移動滑鼠點選不要選擇的元素(改以紅底標記),並同時注意 CSS 選擇器位址與資料筆數的變動,當資料筆數與預期相符時表示完成定位我們以 IMDB.

com 的 Avengers: Infinity War (2018) 頁面示範如何以 CSS 選擇器定位評等。點選 Selector Gadget 外掛圖示留意 Selector Gadget 的 CSS 選擇器在想要定位的評分上面點選左鍵,留意此時的 CSS 選擇器位址與資料筆數移動滑鼠點選不要選擇的元素,當資料筆數與預期相符時表示完成定位最後利用 rvest 套件的 read_html() 函數將 HTML 資料格式讀入,獲得的資料結構同樣是命名為 xml_document 的 list,面對 xml_document 可以呼叫 rvest 套件提供的 html_nodes() 與 html_text() 函數指定 CSS 選擇器解析出文字格式的資料。## > # 安裝 jsonlite、rvest 與 magrittr## > #pkgs <- c("jsonlite", "rvest", "magrittr")## > #install.

packages(pkgs)## > # 載入 rvest, magrittr## > library(rvest)## > library(magrittr)## > ## > movie_url <- "https://www.

imdb.

com/title/tt4154756"## > movie <- read_html(movie_url)## > class(movie)## [1] "xml_document" "xml_node" ## > rating <- movie %>%## + html_nodes(css = "strong span") %>%## + html_text() %>%## + as.

numeric()## > rating## [1] 8.

5Chrome 瀏覽器外掛:XPath Helper透過下列步驟將 XPath Helper 外掛加入 Chrome 瀏覽器。前往 Chrome Web Store,點選外掛(Extensions)搜尋 XPath Helper 並點選加入到 Chrome 瀏覽器確認要加入 XPath Helper完成安裝前往 Chrome Web Store,點選外掛(Extensions)搜尋 XPath Helper 並點選加入到 Chrome 瀏覽器確認要加入 XPath Helper完成安裝依照下列步驟定位 HTML 格式資料的 XPath。點選 XPath Helper 的外掛圖示留意 XPath Helper 介面左邊的 XPath 與右邊被定位到的資料按住 shift 鍵移動滑鼠到想要定位的資料試著縮減 XPath,從最前面的節點開始刪減,在最短的 XPath 依然能對應到資料即表示完成定位我們以 IMDB.

com 的 Avengers: Infinity War (2018) 頁面示範如何以 XPath 定位評等。點選 XPath Helper 的外掛圖示留意 XPath Helper 介面左邊的 XPath 與右邊被定位到的資料按住 shift 鍵移動滑鼠到想要定位的資料從最前面的節點開始刪減,在最短的 XPath 依然能對應到資料即表示完成定位最後利用 rvest 套件的 read_html() 函數將 HTML 資料格式讀入,獲得的資料結構同樣是命名為 xml_document 的 list,面對 xml_document 可以呼叫 rvest 套件提供的 html_nodes() 與 html_text() 函數指定 XPath 解析出文字格式的資料。## > # 安裝 jsonlite、rvest 與 magrittr## > #pkgs <- c("jsonlite", "rvest", "magrittr")## > #install.

packages(pkgs)## > # 載入 rvest, magrittr## > library(rvest)## > library(magrittr)## > ## > movie_url <- "https://www.

imdb.

com/title/tt4154756"## > movie <- read_html(movie_url)## > class(movie)## [1] "xml_document" "xml_node" ## > rating <- movie %>%## + html_nodes(xpath = "//strong/span") %>%## + html_text() %>%## + as.

numeric()## > rating## [1] 8.

5小結在這個小節中我們簡介如何以 R 語言透過 jsonlite 、 xml2 與 rvest 等套件實踐網站爬蟲的核心任務:請求資料(requesting data)與解析資料(parsing data)。面對不同類型的網頁資料,分別以 jsonlite 套件的 fromJSON() 函數處理 Web API 的 JSON 格式資料;以 xml2 套件的 read_xml() 、 xml_find_all() 與 xml_text() 函數處理 Web API 的 XML 格式資料;以 rvest 套件的 read_html() 、 html_nodes() 與 html_text() 函數搭配 Chrome 瀏覽器外掛 Selector Gadget 以及 XPath Helper 處理 HTML 格式資料。延伸閱讀Working with Web Data in RLearn how to efficiently import data from the web into R.

www.

datacamp.

com.

. More details

Leave a Reply