本篇介紹如何在 R 中透過 RSelenium
模組使用 Selenium 自動操控瀏覽器,下載並擷取網頁中的資料。
RSelenium 是一個可以讓 R 程式透過 Selenium 操控瀏覽器的套件,它的功能非常強大,幾乎可以讓程式對瀏覽器進行任何操作,以下我們要介紹如何在 R 中使用 RSelenium,透過標準的 Google Chrome 或 Firefox 瀏覽器,擷取到最標準的網頁內容。
安裝 RSelenium 套件
RSelenium 可以從 R 官方的 CRAN 套件庫下載安裝:
# 從 CRAN 安裝 RSelenium install.packages("RSelenium")
或是從 GitHub 上面下載最新的版本來安裝:
# 從 GitHub 安裝 RSelenium install.packages("devtools") devtools::install_github("ropensci/RSelenium")
安裝好之後,載入 RSelenium
套件:
# 載入 RSelenium 套件 library("RSelenium")
若沒有錯誤訊息,就表示安裝完成了。
WebDriver
Selenium 是透過 WebDriver API 來操控瀏覽器的,所以在使用時必須先安裝對應瀏覽器的 WebDriver,目前支援 WebDriver 的瀏覽器有 Google Chrome 與 Firefox:
- Google Chrome 瀏覽器:ChromeDriver
- Firefox 瀏覽器:geckodriver
ChromeDriver 與 geckodriver 這兩種 WebDriver 的使用方式都相同,首先從它們的官方網站依據自己的作業系統下載編譯好的 WebDriver 執行檔,以 Windows 作業系統來說,ChromeDriver 的執行檔為 chromedriver.exe
,而 geckodriver 的執行檔則為 geckodriver.exe
。
下載 WebDriver 的執行檔之後,放在自己喜歡的固定位置,然後記下 WebDriver 的放置路徑,在下面的 Selenium 伺服器啟動時,指定這個路徑即可。
Selenium 伺服器
從 Selenium 官方網站下載最新版的 Selenium JAR 檔,然後在 Windows 命令提示字元中,以 Java 執行此 JAR 檔,並且指定 chromedriver.exe
與 geckodriver.exe
的放置路徑,假設這兩個 WebDriver 都放在 D:
底下,則執行:
java -Dwebdriver.chrome.driver=D:chromedriver.exe -Dwebdriver.gecko.driver=D:geckodriver.exe -jar selenium-server-standalone-3.12.0.jar
這裡我們同時指定 Google Chrome 與 Firefox 兩個瀏覽器的 WebDriver 位置,這樣的話在程式中就可以使用兩種瀏覽器,如果只使用一種瀏覽器的話,可以將沒用到的 WebDriver 省略。
操控瀏覽器
安裝好並啟動了 Selenium 伺服器之後,接著就可以回到 R 中開始使用 RSelenium 套件操控瀏覽器了。
首先載入 RSelenium
套件:
# 載入 RSelenium 套件 library("RSelenium")
接著使用 remoteDriver
函數連接 Selenium 伺服器:
# 連接 Selenium 伺服器,選用 Firefox 瀏覽器 remDr <- remoteDriver( remoteServerAddr = "localhost", port = 4444, browserName = "firefox")
預設的 Selenium 伺服器會開在 localhost
的 4444
連接埠,分別可用 remoteServerAddr
與 port
參數來指定,而 browserName
則是指定要使用的瀏覽器,如果慣用 Google Chrome 的人,可以指定為 chrome
。
連接 Selenium 伺服器之後,即可用 RSelenium 開啟瀏覽器:
# 開啟瀏覽器 remDr$open()
以 RSelenium 開啟的 Firefox 瀏覽器,在外觀上看起來會跟正常開啟的 Firefox 瀏覽器有一些差異,網址列會有一個機器人的圖示,標示這個瀏覽器是由程式在控制的。
若要瀏覽指定的網址,可以呼叫 navigate
函數:
# 瀏覽 Google 首頁 remDr$navigate("https://www.google.com.tw/")
接著我們讓瀏覽器開啟另外一個網頁:
# 瀏覽 Yahoo 首頁 remDr$navigate("https://tw.yahoo.com/")
若要讓瀏覽器回到上一頁,可以呼叫 goBack
函數:
# 回到上一頁 remDr$goBack()
若要前往下一頁,則可以呼叫 goForward
函數:
# 前往下一頁 remDr$goForward()
若要取得目前瀏覽器網址列中的網址,可以使用 getCurrentUrl
函數:
# 取的目前網頁的網址 remDr$getCurrentUrl()
[[1]] [1] "https://tw.yahoo.com/"
呼叫 refresh
可以讓瀏覽器重新整理網頁:
# 重新整理 remDr$refresh()
擷取網頁元素
在控制瀏覽器瀏覽網頁之後,我們可以進一步透過 RSelenium 擷取網頁中的元素與資料。這裡我們以 Google 搜尋 office
這個關鍵字的結果網頁作為示範:
# 用 Google 搜尋 office 關鍵字 remDr$navigate("https://www.google.com.tw/search?q=office")
在擷取網頁元素時,主要的方法就是使用 findElement
這個函數,配合各種條件篩選出自己想要的結果,以下是常見的一些應用實例。
以 id
擷取網頁元素
若要以指定的 id
擷取網頁元素,可以在呼叫 findElement
時,將 using
指定為 id
,並將 value
指定為網頁元素的 id
屬性值。
例如若要將網頁中 id
屬性值為 ires
的元素取出來,可以這樣寫:
# 依據 ID 取得網頁元素 web.elem <- remDr$findElement(using = "id", value = "ires")
將網頁元素擷取出來之後,就可以對該元素進行各項操作,例如取得網頁元素的各種屬性值:
# 取得網頁元素的 id 屬性值 web.elem$getElementAttribute("id")
[[1]] [1] "ires"
# 取得網頁元素的 data-async-context 屬性值 web.elem$getElementAttribute("data-async-context")
[[1]] [1] "query:office"
或是取得網頁元素的文字內容:
# 取得網頁元素的文字內容 web.elem$getElementText()
[[1]] [1] "Office 365 Login | Microsoft Officenhttps://www.office.com/n[略]
以 class
擷取網頁元素
若要使用網頁元素的 class
名稱來擷取網頁元素,可將 using
設定為 class name
,並在 value
指定網頁元素的 class
名稱:
# 依據 Class 取得網頁元素 web.elem <- remDr$findElement(using = 'class name', value = "r")
取出的網頁元素,操作方式都是相同的:
# 取得網頁元素的文字內容 web.elem$getElementText()
[[1]] [1] "Office 365 Login | Microsoft Office"
尋找子元素
如果想在指定的元素中,繼續尋找更下層的子元素,可以使用 findChildElement
。假設我們想以現有的 web.elem
為起始點,往下尋找超連結的元素(HTML 節點名稱為 a
的元素),可以這樣寫:
# 從 web.elem 往下尋找超連結的元素 a.elem <- web.elem$findChildElement(using = "tag name", value = "a")
找到之後,傳回的元素也是用相同的方式操作:
# 取出超連結的網址 a.elem$getElementAttribute("href")
[[1]] [1] "https://www.office.com/"
擷取多個元素
在網頁中可能會有多個元素都傭有相同的 class
名稱,若要一次取出所有符合的元素,可以改用 findElements
函數,其法相同,但可以一次將所有的符合條件的結果以 list
的方式傳回:
# 依據 Class 取得多個網頁元素 web.elem.list <- remDr$findElements(using = 'class name', value = "r")
得到所有符合條件的元素之後,即可使用一般 list
處理方式,取出想要的資料:
# 取出每個網頁元素的文字內容 unlist(lapply(web.elem.list, function(e) { e$getElementText() }))
[1] "Office 365 Login | Microsoft Office" [2] "Microsoft Office | 家用和辦公室用生產力工具" [3] "Office 產品- Microsoft Office" [4] "Office 下載 - Microsoft" [5] "微軟Office 2016 專業增強版(繁體中文下載+免費永久序號註冊) @ 呂 ..." [6] "UGAMail – Office 365" [7] "Office - Home | Facebook" [8] "My Account - Outlook.com" [9] "Office" [10] "The Office (U.S. TV series) - Wikipedia"
以 CSS 選擇器擷取網頁元素
在實務上擷取網頁,最常使用的方式應該就是 CSS 選擇器,只要將 using
設定為 css selector
,並在 value
中指定 CSS 選擇器的規則,即可快速篩選出指定的網頁元素:
# 依據 CSS 選擇器取得網頁元素 web.elem.list <- remDr$findElements(using = 'css selector', value = "div.rc h3.r a")
這我們取出每一個 Google 搜尋結果的超連結,並將實際的網址列出來:
# 取出每個超連結的網址 unlist(lapply(web.elem.list, function(e) { e$getElementAttribute("href") }))
[1] "https://www.office.com/" [2] "https://products.office.com/zh-tw/home" [3] "https://products.office.com/zh-tw/products" [4] "https://www.microsoft.com/zh-tw/download/office.aspx" [5] "http://a4287604.pixnet.net/blog/post/201669981-%E5%BE%AE%E8%BB%9F-office-2016-%E5%B0%88%E6%A5%AD%E5%A2%9E%E5%BC%B7%E7%89%88-%28%E7%B9%81%E9%AB%94%E4%B8%AD%E6%96%87%E4%B8%8B%E8%BC%89%2B%E5%85%8D" [6] "https://ugamail.uga.edu/" [7] "https://www.facebook.com/Office/" [8] "https://office.live.com/start/MyAccount.aspx" [9] "https://visitoffice.com/" [10] "https://en.wikipedia.org/wiki/The_Office_(U.S._TV_series)"
以 XPath 擷取網頁元素
# 依據 XPath 取得網頁元素 web.elem <- remDr$findElement(using = 'xpath', value = "//a[@href='https://www.office.com/']")
找到之後,用相同的方式操作傳回的元素:
# 取得網頁元素的文字內容 web.elem$getElementText()
[[1]] [1] "Office 365 Login | Microsoft Office"
參考資料:rOpenSci、Yao-Jen Kuo、Yao-Jen Kuo、張郎生活的筆記、RPubs
Luna
關於該主題,您也可以查看此博客文章-https://blog.gtwang.org/r/rselenium-r-selenium-browser-web-scraping-tutorial/,因為Selenium非常有用。