LoginSignup
2
4

More than 5 years have passed since last update.

RSeleniumを使ってログインにcaptcha認証の必要なページをスクレイピングする

Posted at

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の確認にも使用する。

スクリーンショットをViewerペインに表示
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でも十分戦えるぞ。

image.png

解答率でソートすると様相が一変して面白い。ユーザー数が10名に満たないような言語が多く入ってくる(だからこそ上位に入りやすい、という見方もできるだろうが)。トップのStataは現時点でユーザー数16名だ。

image.png

参考

2
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4