使用 CSS 選擇器從網頁中提取數據

在 R 中,關於網絡爬蟲最簡單易用的擴展包是 rvest。運行如下代碼從 CRAN 上安裝:
install.packages("rvest")
首先,加載包並用 read_html( ) 讀取 data/single-table.html,再嘗試從網頁中提取表格:
library(rvest)
## Loading required package: xml2
single_table_page <- read_ _html("data/single-table.html")
single_table_page
## {xml_document}
## <html>
## [1] <head>\n <title>Single table</title>\n</head>
## [2] <body>\n <p>The following is a table</p>\n <table i ...
注意到,single_table_page 是一個HTML 解析文檔,是HTML 節點的嵌套數據結構。
使用 rvest 函數從網頁上爬取信息的典型過程是這樣的。首先,定位須要從中提取數
據的 HTML 節點。而後,使用 CSS 選擇器或者 XPath 表達式篩選 HTML 節點,從而選擇
須要的節點,剔除不須要的節點。最後,對已解析的網頁使用合適的選擇器,用 html_
nodes( ) 提取節點子集,用 html_attrs( ) 提取屬性,用 html_text( ) 提取文本。
rvest 包也提供了一些簡單的函數,從網頁中直接提取數據並返回一個數據框。例如,
提取網頁中全部的 <table> 元素,咱們直接調用 html_table( ):
html_ _table(single_table_page)
## [[1]]
## Name Age
## 1 Jenny 18
## 2 James 19
爲了提取<table> 中的第 1 個元素,咱們在使用 CSS 選擇器 table 的時候,調用
html_node( ) 選擇第1個節點,再對選擇出來的節點調用 html_table( ) 獲得一個數據框:
html_ _table(html_ _node(single_table_page, "table"))
## Name Age
## 1 Jenny 18
## 2 James 19
一個很天然的想法即是使用管道操做,就像第 12 章中介紹的 dplyr 包中使用 %>% 管
道操做符。回顧一下,%>% 執行 x %>% f(···) 的基本方法就是 f(x,···),所以,嵌
套調用能夠被拆解,從而提升可讀性。上述代碼能夠用 %>% 重寫爲:
single_table_page %>%
html_ _node("table") %>%
html_ _table()
## Name Age
## 1 Jenny 18
## 2 James 19
如今,讀取 data/products.html,並用 html_nodes( ) 匹配 <span class = "name"> 節點:
products_page <- read_ _html("data/products.html")
products_page %>%
html_ _nodes(".product-list li .name")
## {xml_nodeset (3)}
## [1] <span class = "name">Product-A</span>
## [2] <span class = "name">Product-B</span>
## [3] <span class = "name">Product-C</span>
注意到,咱們想選擇的節點是 product-list 類的 <li> 標籤下屬於 name 類的節
點。所以,使用.product-list li .name 選擇這樣的嵌套節點。若是對這些符號不熟
悉,請溫習經常使用的 CSS 表。
以後,再用 html_text( ) 從選擇的節點中提取內容,這個函數會返回一個字符向量:
products_page %>%
html_ _nodes(".product-list li .name") %>%
html_ _text()
## [1] "Product-A" "Product-B" "Product-C"
相似地,下面的代碼提取出產品價格:
products_page %>%
html_ _nodes(".product-list li .price") %>%
html_ _text()
## [1] "$199.95" "$129.95" "$99.95"
前 面 這 些 代 碼 中 , html_nodes( ) 返 回 一 個 包 含 HTML 節 點 的 集 合 ,
而 html_text( ) 則從每一個 HTML 節點中智能地提取內部文本,而後返回一個字符向量。
可是,這些價格保留了它們的原生格式,即字符串形式,而不是數字。下面的代碼提
取出來相同的數據,並把它轉換成更經常使用的格式:
product_items <- products_page %>%
html_ _nodes(".product-list li")
products <- data.frame(
name = product_items %>%
html_ _nodes(".name") %>%
html_ _text(),
price = product_items %>%
html_ _nodes(".price") %>%
html_ _text() %>%
gsub("$", "", ., fixed = TRUE) %>%
as.numeric(),
stringsAsFactors = FALSE
)
products
## name price
## 1 Product-A 199.95
## 2 Product-B 129.95
## 3 Product-C 99.95
注意到,選擇節點的中間結果能夠被存儲在一個變量中,以便重複使用。後續
的 html_nodes( ) 或 html_node( ) 僅僅匹配內部節點。
既然產品價格是數值,咱們即可以用 gsub( ) 從原生價格中移除 $,而後將結果轉換
成一個數值向量。管道操做中的 gsub( ) 調用有點特殊,由於前面的結果(用 . 表示)
本該放在第 3 個參數位置,而不是第 1 個。
這個例子中,.product-list li .name 能夠縮寫爲 .name,同理,.product-list
li .price 能夠被 .price 代替。在實際應用中,CSS 類被普遍地運用,所以,一個通用
的選擇器可能會匹配太多非合意的元素。因此,最好選擇一個描述更清晰,限制條件更嚴
格的選擇器去匹配感興趣的節點。html

相關文章
相關標籤/搜索