<jupyter_start><jupyter_text>成為初級資料分析師 | R 程式設計與資料科學應用> 網頁爬蟲 郭耀仁 > The world’s most valuable resource is no longer oil, but data.>> The Economist  大綱- 網站爬蟲的核心任務- JSON 格式資料- HTML 格式資料  網站爬蟲的核心任務  核心任務可以簡單區分為兩個- 請求資料（requesting data）- 解析資料（parsing data）  請求資料的運作就像在瀏覽器中輸入網址一般，不過送出請求的管道由瀏覽器改變成為 R 語言程式碼  解析資料的運作則是將請求所得之不同格式資料轉換為 R 資料結構，常見的有- JSON 格式- HTML 格式  JSON 格式資料  使用 `jsonlite` 套件中的 `fromJSON()` 函數`fromJSON()` 函數一次就處理了兩個核心任務：- 對網站發出請求- 將請求的回應解析為    - `data.frame`（Array of JSONs）    - `list`（JSON）  安裝 `jsonlite` 套件- 透過 RStudio 的 `Packages` 功能頁籤- 透過 `install.packages()` 函數```rinstall.packages("jsonlite")```  載入 `jsonlite` 套件- 透過 RStudio 的 `Packages` 功能頁籤- 透過 `library()` 函數```rlibrary("jsonlite")```  安裝 Chrome 瀏覽器外掛：JSONView- - 更漂亮地在瀏覽器上預覽 JSON 格式資料  安裝好 JSONView 後用瀏覽器預覽   擷取  資料<jupyter_code>library("jsonlite")

aqi_url <- "https://opendata.epa.gov.tw/ws/Data/AQI/?$format=json"
aqi <- fromJSON(aqi_url)
class(aqi)<jupyter_output><empty_output><jupyter_text>隨堂練習：全台灣有幾個空氣品質測站？<jupyter_code>library("jsonlite")

aqi_url <- "https://opendata.epa.gov.tw/ws/Data/AQI/?$format=json"
aqi <- fromJSON(aqi_url)
ans <- nrow(aqi)
ans<jupyter_output><empty_output><jupyter_text>隨堂練習：列出位於臺北市與新北市的空氣品質測站<jupyter_code>library("dplyr")

ans <- aqi %>% 
    filter(County %in% c("臺北市", "新北市")) %>% 
    select(County, SiteName)
ans<jupyter_output><empty_output><jupyter_text>XML 格式資料  使用 `xml2` 套件- `read_xml()` 函數請求資料- `xml_find_all()` 與 `xml_text()` 函數解析資料  安裝 `xml2` 套件- 透過 RStudio 的 `Packages` 功能頁籤- 透過 `install.packages()` 函數```rinstall.packages("xml2")```  載入 `xml2` 套件- 透過 RStudio 的 `Packages` 功能頁籤- 透過 `library()` 函數```rlibrary("xml2")```  請求  資料<jupyter_code># requesting data
library("xml2")

aqi_url <- "https://opendata.epa.gov.tw/ws/Data/AQI/?$format=xml"
aqi <- read_xml(aqi_url)
class(aqi)<jupyter_output><empty_output><jupyter_text>解析  資料<jupyter_code># parsing data
library("dplyr")

site_names <- aqi %>%
  xml_find_all(xpath = "//SiteName") %>%
  xml_text()
site_names
# parsing data
counties <- aqi %>%
  xml_find_all(xpath = "//County") %>% 
  xml_text()
counties<jupyter_output><empty_output><jupyter_text>HTML 格式資料  使用 `rvest` 套件中的- `read_html()` 函數對網站發出請求- `html_nodes(CSS = )` 定位 HTML 中指定的標記- `html_text()` 解析標記中的文字- `html_attr(ATTR)` 解析標記中的屬性  安裝 `rvest` 套件- 透過 RStudio 的 `Packages` 功能頁籤- 透過 `install.packages()` 函數```rinstall.packages("rvest")```  載入 `rvest` 套件- 透過 RStudio 的 `Packages` 功能頁籤- 透過 `library()` 函數```rlibrary("rvest")```  以 `read_html()` 請求  資料<jupyter_code>library("rvest")

html_doc <- read_html("https://www.imdb.com/title/tt4154796")
class(html_doc)<jupyter_output><empty_output><jupyter_text>安裝 Chrome 瀏覽器外掛：Selector Gadget- - 查詢 HTML 標記的 CSS Selector  以 `html_nodes()` 解析 `html_doc`<jupyter_code># rating
html_doc %>%
  html_nodes(css = "strong span")<jupyter_output><empty_output><jupyter_text>以 `html_text()` 解析標記中的文字<jupyter_code># rating
html_doc %>%
  html_nodes(css = "strong span") %>% 
  html_text() %>% 
  as.numeric()<jupyter_output><empty_output><jupyter_text>以 `html_attr(ATTR)` 解析標記中的屬性<jupyter_code># poster image link
html_doc %>%
  html_nodes(css = ".poster img") %>% 
  html_attr("src")<jupyter_output><empty_output><jupyter_text>隨堂練習：寫作一個函數 `get_movie_info()`<jupyter_code># install.packages(c("rvest", "magrittr"))
library(rvest)
library(magrittr) # 使用 %>% 運算子

get_movie_info <- function(movie_url) {
  # 指定電影資訊的 CSS 選擇器
  rating_css <- "strong span"
  genre_css <- ".subtext a"
  poster_css <- ".poster img"
  cast_css <- ".primary_photo+ td a"
  title_css <- "h1"
  
  movie_doc <- movie_url %>% 
    read_html()
  # 擷取資訊
  movie_rating <- movie_doc %>% 
    html_nodes(css = rating_css) %>%
    html_text() %>%
    as.numeric()
  movie_genre <- movie_doc %>% 
    html_nodes(css = genre_css) %>% 
    html_text() %>% 
    trimws() %>% 
    gsub(pattern = "\n", replacement = "")
  movie_genre_len <- length(movie_genre)
  movie_genre <- movie_genre[-movie_genre_len]
  movie_poster <- movie_doc %>% 
    html_nodes(css = poster_css) %>% 
    html_attr("src")
  movie_cast <- movie_doc %>% 
    html_nodes(css = cast_css) %>% 
    html_text() %>% 
    trimws() %>% 
    gsub(pattern = "\n", replacement = "")
  movie_title <- movie_doc %>% 
    html_nodes(css = title_css) %>% 
    html_text() %>% 
    trimws()
  
  # 回傳資訊
  movie_info <- list(
    title = movie_title,
    rating = movie_rating,
    genre = movie_genre,
    posterLink = movie_poster,
    cast = movie_cast
  )
  return(movie_info)
}
movie_url <- "https://www.imdb.com/title/tt7286456"
joker_movie_info <- get_movie_info(movie_url)
print(joker_movie_info$title)
print(joker_movie_info$rating)
print(joker_movie_info$genre)
print(joker_movie_info$posterLink)
print(joker_movie_info$cast)<jupyter_output>[1] "小丑 (2019)"
[1] 8.6
[1] "Crime"    "Drama"    "Thriller"
[1] "https://m.media-amazon.com/images/M/MV5BNGVjNWI4ZGUtNzE0MS00YTJmLWE0ZDctN2ZiYTk2YmI3NTYyXkEyXkFqcGdeQXVyMTkxNjUyNQ@@._V1_UX182_CR0,0,182,268_AL_.jpg"
 [1] "<NAME>" "<NAME>"  "<NAME>"     "<NAME>" 
 [5] "<NAME>"    "<NAME>"    "<NAME>"       "<NAME>" 
 [9] "<NAME>"      "<NAME>"       "<NAME>"      "<NAME>"     
[13] "<NAME>"    "<NAME>"    "<NAME>"
{'fraction_non_alphanumeric': 0.1687378640776699, 'fraction_numerical': 0.011067961165048544, 'mean_word_length': 4.907110091743119, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 89, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 15}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '335521', 'license': 'MIT', 'n_tokens_mistral': 2719, 'n_tokens_neox': 2724, 'n_words': 369, 'path': 'notebooks/12-web-scraping.ipynb', 'repo_name': 'yaojenkuo/introduction-to-r', 'size': '5237'}