Project EulerのStatisticsページ(Statistics - Project Euler)から使用言語別の統計情報を得ることを目標とする。このページはログインしないと閲覧することができず、またログインには画像認証が必要である。今回、画像認証を(半手動で)突破するためにRSelenium
パッケージを用いる。
準備
Selenium Serverの起動
まず、何らかの方法でSelenium Serverを起動しておく必要がある。現在、RSeleniumのVignette(RSelenium: Basics)ではDockerコンテナの利用が推奨されており、Dockerを使用する場合のためのvignettも別途用意されている(RSelenium: Docker)。
今回は推奨の手順に従ってSeleniumを導入し、ローカルでSelenium Sereverが起動されているものとする。
% docker run -d -p 4445:4444 selenium/standalone-firefox
使用するパッケージ
下記のパッケージを利用する。
# install.packages("RSelenium", "rvest") # インストールしていなければインストール
library(RSelenium)
library(rvest)
rvest
は今回取得したhtmlの取扱いに用いた。データの取得自体はRSeleniumから行った。
スクレイピング
Webサイトへ接続する
まず、remoteDriver
クラスのインスタンスを作成する。このとき、Selenium Server起動時に指定した情報を入力する。
remDr <- remoteDriver(remoteServerAddr = "localhost",
port = 4445L,
browserName = "firefox")
Serverへの接続はopen
メソッドを用いる。
remDr$open()
正常に接続できていれば、getStatus()
メソッドでステータスが取得できるはずだ。
> remDr$getStatus()
$ready
[1] TRUE
(...以下略)
また、screenshot()
メソッドを用いれば現在の画面のスクリーンショットを取得できる。display=TRUE
を指定すればRStudioならViewerペインで内容を確認できるので、現在の状況を確認したくなったら適宜実行すると良い。また、今回captchaの確認にも使用する。
remDr$maxWindowSize()
remDr$screenshot(display=TRUE)
ログイン情報を入力する
フォームへの情報入力はwebElement
クラスのsendKeysToElement
メソッドを用いる。
## usernameとpassword入力
webElem <- remDr$findElement(using="id", value = "username")
webElem$sendKeysToElement(list("your_username")) # 自身のユーザー名に置き換える
webElem <- remDr$findElement(using="id", value = "password")
webElem$sendKeysToElement(list("your_password")) # 自身のパスワードに置き換える
captcha部分は見ないと分からないので、見て入力する。screenshot
を使おう。
## captcha情報確認のためスクリーンショットをとる
remDr$maxWindowSize()
remDr$screenshot(display=TRUE)
## captcha入力
webElem <- remDr$findElement(using="name", value = "captcha")
webElem$sendKeysToElement(list(readline("confirmation code: "))) # 確認した値を入力
情報を入力したらサインインしよう。
## サインインボタンクリック
webElem <- remDr$findElement(using="name", value = "sign_in")
webElem$clickElement()
データの取得
getPageSource
メソッドでhtmlを取得できるので、後はrvest
を使うなり何なり。
## 目的のページへ移動
remDr$navigate("https://projecteuler.net/languages")
## rvestでテーブル取得
df <- remDr$getPageSource()[[1]] %>% read_html %>% html_table %>% `[[`(1)
おまけ
せっかくなのでplotしてみた。
library(ggplot2)
plotdf <- function(target){
df %>%
filter(rank(eval(target)) > nrow(df)/2) %>%
ggplot(aes(x = reorder(Language, eval(target)), y = eval(target))) +
geom_col() +
coord_flip() +
xlab("Language") +
ylab(target) +
theme_classic()
}
plotdf(quote(`Total Number of Members`))
plotdf(quote(`Mean Percentage of Problems Solved`))
言語別のランク。Project Eulerは速度を求められないので、Rでも十分戦えるぞ。
解答率でソートすると様相が一変して面白い。ユーザー数が10名に満たないような言語が多く入ってくる(だからこそ上位に入りやすい、という見方もできるだろうが)。トップのStataは現時点でユーザー数16名だ。