はじめに
RでのWebスクレイピングのやり方の1つとして、rvestパッケージを使う方法がある。
詳細は、過去の記事を参照
ただ、このパッケージだと、Webスクレイピングがやや難解なケースがある。 実際、Google検索のヒット件数項目を取得するのを、小一時間ほどやったけど、rvestではうまくいかなかった。
この記事では、RSeleniumを使って、Webブラウザを介して、Webスクレイピングをやる方法
を紹介する。RSeleniumは、Selenium*1 2.0 Remote WebDriver 用の R ラッパーである。使ってみたら、RSeleniumは、rvestがやや困難な部分を補完できそうである。また、htmlの扱い方は、rvestとの共通点もあり、rvestの経験も生かされる。
今回の内容は、基本的なRSeleniumの使い方が主で、「定期実行のプログラムを組んで、ブラウザを自動操作する」とかまでは含んでいない。
まずは、事前のセットアップを行う。
事前セットアップ
Webブラウザのダウンロード
FireFoxとGoogle Chromeをダウンロード・インストールする。
Webブラウザ操作用ドライバーのインストール
ターミナルを起動して、以下を実行する。
#ドライバーのインストール brew install geckodriver brew install chromedriver #実行時に許可が必要
Homebrewの詳細は、過去の記事を参照のこと。
Javaのインストール
こういうのがでたら、javaのインストールも必要である。
ターミナルを起動して、以下を実行する。
#JAVA セットアップ brew tap AdoptOpenJDK/openjdk brew install --cask adoptopenjdk12 #インストールの確認 java -version
詳細は、過去の記事を参照のこと。
selenium.jarのダウンロード・実行
RSeleniumの実行には、selenium-server-standalone が必要である。
R/RStudioを起動して、そのソフトウェアをダウンロードして、バックグラウンド実行する。
#ダウンロード実行: 2021年4月4日に、ダウンロード確認 download.file("https://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar", destfile = "selenium.jar") #バックグラウンド実行 system("java -jar selenium.jar &") #19:42:09.781 INFO [GridLauncherV3.parse] - Selenium server version: 3.141.59, revision: e82be7d358 #19:42:09.872 INFO [GridLauncherV3.lambda$buildLaunchers$3] - Launching a standalone Selenium Server on port 4444 #2021-04-04 19:42:09.977:INFO::main: Logging initialized @595ms to org.seleniumhq.jetty9.util.log.StdErrLog #19:42:10.249 INFO [WebDriverServlet.<init>] - Initialising WebDriverServlet #19:42:10.382 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 4444 #selenium.jarのジョブ確認 system("ps -A | grep 'java'") # 3921 ?? 0:01.50 /usr/bin/java -jar selenium.jar # 3925 ?? 0:00.00 sh -c ps -A | grep 'java' # 3927 ?? 0:00.00 grep java #OR #system("ps -A | grep 'selenium'") # 3921 ?? 0:01.52 /usr/bin/java -jar selenium.jar # 3928 ?? 0:00.01 sh -c ps -A | grep 'selenium' # 3930 ?? 0:00.00 grep selenium #selenium.jarの止め方 - 終了時に実行すること #上記コマンドで、プロセスのPIDを見つけて、そのIDをkillする system("kill 3921") system("ps -A | grep 'java'") # 3939 ?? 0:00.01 sh -c ps -A | grep 'java' # 3941 ?? 0:00.00 grep java
ここでは、selenium.jarのジョブが動いていれば、問題ない。
RSeleniumの使い方 - ブラウザ操作の基本
次に、RSeleniumパッケージをインストールする。
ここでは、Google Chromeを使ったやり方を紹介する。FireFoxでの実行例は、補足部分に記載している。
RSeleniumのポートは、「4444」を使用する。
#RSeleniumのインストール・ロード install.packages("RSelenium") library(RSelenium) #Google Chrome 起動の場合 rsChr <- RSelenium::remoteDriver(port = 4444L, browserName = "chrome") #[1] "Connecting to remote server" #19:44:57.403 INFO [ActiveSessionFactory.apply] - Capabilities are: { # "browserName": "chrome", # "javascriptEnabled": true, # "nativeEvents": true, # "version": "" #} #(中略)
この状態で、Webブラウザ操作ができる。
以下が、基本操作のコマンドである。
#基本操作 #Webブラウザを開く rsChr$open() #Googleページへ移動する rsChr$navigate("https://www.google.com") #Rページへ移動する rsChr$navigate("https://www.r-project.org/") #1つ前のページに戻る(ex. Rページ => Googleページ) rsChr$goBack() #1つ先のページに戻る(ex. Googleページ => Rページ) rsChr$goForward() #現在のページのURL取得 rsChr$getCurrentUrl() #[[1]] #[1] "https://www.r-project.org/" #ページの更新 rsChr$refresh() #Webブラウザウインドの最大化 rsChr$maxWindowSize() #ブラウザを閉じる rsChr$close()
Google検索とか情報取得とかをやってみる
まずは、基本の「キ」ということで、RSeleniumを使った、Google検索をやってみる。
簡単なGoogle検索だけなら、以下の4ステップできる。
#ブラウザを開く rsChr$open() #Googleページに移動する rsChr$navigate("https://www.google.co.jp/") ##Google検索の実行 #検索ウインドを選択 WebSearch <- rsChr$findElement(using = "css", "[name = 'q']") #検索語「R Cran」を入力して、実行 WebSearch$sendKeysToElement(list("R Cran", key = "enter"))
このように、「R Cran」での検索結果が表示されたら、うまくいっている。
検索結果を取得する
次に、検索結果を取得する。重複とか関係ないところがあるので、以下のように不要部分を切って、出力させる。
#検索結果(全部)を取得する ResultLink <- rsChr$findElements(using = "css", "[href]") getResultLink <- unlist(lapply(ResultLink, function(x) {x$getElementAttribute("href")})) #google関係を除外 + 重複除外 getResultLink <- unique(getResultLink[!grepl("[.]google|[.]gstatic[.]", getResultLink)]) getResultLink # [1] "https://cran.r-project.org/" # [2] "https://cran.r-project.org/bin/windows/" # [3] "https://cran.r-project.org/web/packages/available_packages_by_name.html" # [4] "https://cran.r-project.org/mirrors.html" # [5] "https://cran.r-project.org/web/packages/" # [6] "https://cran.r-project.org/bin/windows/base/" # [7] "https://cran.r-project.org/doc/contrib/manuals-jp/R-admin-jp.v15.pdf" # [8] "http://www.okadajp.org/RWiki/?CRAN%E5%9B%BD%E5%86%85%E3%83%9F%E3%83%A9%E3%83%BC%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9" # [9] "https://cran.ism.ac.jp/" #[10] "https://mjin.doshisha.ac.jp/iwanami/R/index.pdf" #[11] "https://staffblog.amelieff.jp/entry/2018/04/19/152233" #[12] "https://qiita.com/hoxo_m/items/ce478bf0debe963d9e40" #[13] "https://www.trifields.jp/statistical-analysis-r-cran-packages-341" #[14] "https://en.wikipedia.org/wiki/Rnn_(software)"
検索ヒット数を取得する
次に、検索ヒット数の結果である「約 23,300,000 件 ...」の項目を取得してみる。
#検索ヒット数を取得する ResultStats <- rsChr$findElements(using = "id", "result-stats") #テキストを取得 getResultStats <- unlist(lapply(ResultStats, function(x) {x$getElementText()})) getResultStats "約 23,300,000 件 (0.89 秒) " #数値に変換(日本語の場合) as.numeric(strsplit(gsub("[,]", "", sub("約 ", "", getResultStats)), split=" 件 ")[[1]][1]) #[1] 23300000
ヒットしたページに移動する
トップヒット、あるいはセカンド・ヒットのページに移動してみる。
今回、セカンド・ヒットは、トップヒットであるCRANのページ以外で最初に出てくるページを、セカンド・ヒットと定義したので、greplで少々整形してある。
#トップヒットのページに移動する rsChr$navigate(getResultLink[1]) #セカンド・ヒットのページに移動する rsChr$navigate(getResultLink[!grepl(getResultLink[1], getResultLink)][1])
ページ移動後に、ページのスクショを録る
#トップヒットのページに移動する rsChr$navigate(getResultLink[1]) #スクショを録る => Rの作業ディレクトリに保存 rsChr$screenshot(file = 'test.png') ##同じ結果だが #magick::image_writeで保存する場合 screenshot <- rsChr$screenshot(display = FALSE) magick::image_write(screenshot, "test1.png") #Rでスクショを表示させる Img <- magick::image_read(base64enc::base64decode(toString(screenshot), output = NULL)) Img
CRAN HPのスクショが作業ディレクトリに保存されていたら、動作OKである。
まとめ
「動作が遅い」という評価が多かったものの、 思いの外、サクサク動いて、結構良かった。
実際、自動操作して、数万回とかアクセスするときには、 スリープ時間を乱数で入れるとかで、実行は遅くなるのかもと。
補足
Google 検索の有料APIについて
Google 検索の有料APIは、結構高い。 1万回検索するのに、50ドルかかるみたい。
RSeleniumを覚える方が経済的だよね。
RSelenium / FirefoxでのGoogle検索実行
#Firefox起動の場合 rsFox <- RSelenium::remoteDriver(port = 4444L, browserName = "firefox") #ブラウザ起動 rsFox$open() #Googleページに移動 rsFox$navigate("https://www.google.co.jp/") #Google検索実行 WebSearch.Fox <- rsFox$findElement(using = "css", "[name = 'q']") WebSearch.Fox$sendKeysToElement(list("R Cran", key = "enter"))
Rで、Python版Seleniumを実行してみる
#pipの確認 system("which pip") #/usr/local/bin/pip system("pip -V") #pip 21.0.1 from /usr/local/lib/python3.8/site-packages/pip (python 3.8) #seleniumのインストール system("pip install selenium") #Collecting selenium # Downloading selenium-3.141.0-py2.py3-none-any.whl (904 kB) #Requirement already satisfied: urllib3 in /usr/local/lib/python3.8/site-packages (from selenium) (1.26.3) #Installing collected packages: selenium #Successfully installed selenium-3.141.0 #Pythonの選択 reticulate::use_python("/usr/local/bin/python", required =T) #ライブラリのロード selenium <- reticulate::import(module = "selenium") #Firefoxの起動 Firefox <- selenium$webdriver$Firefox() #Googleページに移動 Firefox$get('http://google.com/') #検索窓を選択 element <- Firefox$find_element_by_name("q") #検索を実行する element$send_keys('R Cran'); element$submit() #Firefoxを閉じる Firefox$quit()
Webスクレイピングについての関連図書
Webスクレイピングの関連図書を列挙しておきます。
参考資料
*1:Webアプリケーションをテストするためのポータブルフレームワークである。