[翻訳] RSelenium vignette: RSeleniumの基本

この文書は John Harrison によるRパッケージ [`RSelenium`](https://cran.r-project.org/web/packages/RSelenium/) (version 1.4.0) のビネット "[RSelenium basics](https://cran.r-project.org/web/packages/RSelenium/vignettes/RSelenium-basics.html)" の翻訳です.
ただし文中の注は全て訳者によるものです．

License: [AGPL-3](https://opensource.org/licenses/AGPL-3.0)

----

# RSeleniumの基本

<!--
  prettydoc::html_pretty:
    theme: architect
    highlight: github
-->

## はじめに
`RSelenium`の目的は，RからSeleniumサーバやリモートSeleniumサーバへの接続を容易にすることです．`RSelenium`はSelenium WebDriver APIのRバインディングを提供します．[Selenium](http://docs.seleniumhq.org/)はwebブラウザの自動化を中心とするプロジェクトです．`RSelenium`によって，webアプリやwebページの単体テストや回帰テストを様々なブラウザとOSの組み合わせに対して実行することができます．これにより，[shiny](http://www.rstudio.com/shiny/), [sauceLabs](https://saucelabs.com/)といった人気のあるプロジェクトのテストと操作をRの中から統合的に行えるようになります．

このビネットは6つの節に分かれています．

それぞれの節はSeleniumの主要なアイディアへの入門となっており，他のビネットでのより詳細な解説への案内が付いています．

## Seleniumサーバへの接続

### Seleniumサーバって何？
Seleniumサーバは様々なブラウザでHTMLテストスイートを実行し，オプションとしてレポーティング等も可能なスタンドアロンのJavaプログラムです．Selenium WebDriver (Rselenium)を使う目的によっては，Seleniumサーバを実行することが必要なこともそうでないこともあります．

### Seleniumサーバを実行する必要ある？
`RSelenium`を実行しているのと同じマシンでブラウザを操作するつもりなら，そのマシンでSeleniumサーバを実行する必要があります．

### Seleniumサーバのスタンドアロンバイナリはどうやって入手するの？
`RSelenium`にはスタンドアロンのJavaバイナリをダウンロードして`RSelenium`パッケージの`/bin/`ディレクトリに配置する関数が組み込まれています．他の場所にバイナリをインストールしたければ，この関数の`dir`引数を使います．また，既存のバイナリを更新することもできます．

```r
RSelenium::checkForServer()
```
もし手動でバイナリをダウンロードしたい場合，現在は[ここ](http://selenium-release.storage.googleapis.com/index.html)からダウンロードできます．`selenium-server-standalone-x.xx.x.jar`を探してください．

### Seleniumサーバはどうやって実行するの？
`RSelenium`にはSeleniumサーバのスタンドアロンバイナリを実行するためのユーティリティ関数が含まれています．[^1]

```r
# RSelenium::startServer()
srv <- RSelenium::startServer()
```
デフォルトの設定では`RSelenium`パッケージの`/bin/`ディレクトリにバイナリを探しに行きます．バイナリが別の場所にある場合は`dir`引数で選択できます．また，手動でバイナリを実行することもできます．OSのコンソールを開き，バイナリのある場所に行って実行してください．

```bash
java -jar selenium-server-standalone-x.xx.x.jar
```
デフォルトの設定ではSeleniumサーバはポート4444で接続を待ち受けます．

### 実行中のサーバにはどうやって接続するの？
`RSelenium`には`remoteDriver`という名前の主要な参照クラスがあります．サーバに接続するためには適切なオプションを与えて新たな`remoteDriver`インスタンスを作成する必要があります．

```r
# RSelenium::startServer() （必要であれば）
require(RSelenium)
remDr <- remoteDriver(
  remoteServerAddr = "localhost",
  port = 4444,
  browserName = "firefox"
)
```
この場合には`remDr <- remoteDriver()`を呼ぶだけでもよかったのですが，任意のIPアドレス・ポート・ブラウザに接続する方法を示すために明示的にオプションを指定しています．さらなる詳細は`sourceLabs`ビネットで見つけられるでしょう．サーバに接続するには`open`メソッドを使います．

```r
remDr$open()
```

これで`RSelenium`がSeleniumサーバに接続されているはずです．リモートサーバの状態は`getStatus`メソッドで問い合わせることができます．

```r
remDr$getStatus()
```

```
## $build
## $build$version
## [1] "2.53.1"
## 
## $build$revision
## [1] "a36b8b1"
## 
## $build$time
## [1] "2016-06-30 17:37:03"
## 
## 
## $os
## $os$name
## [1] "Windows 7"
## 
## $os$arch
## [1] "x86"
## 
## $os$version
## [1] "6.1"
## 
## 
## $java
## $java$version
## [1] "1.8.0_101"
```

## RSeleniumを使ったページ移動
### 基本的な移動

まずはURLへ移動してみます．

```r
remDr$navigate("http://www.google.com/ncr")
```

次に二つめのページに移動します．

```r
remDr$navigate("http://www.bbc.co.uk")
```

`goBack`メソッドと`goForward`メソッドを使ってページを戻ったり進んだりできます．


```r
remDr$goBack()
remDr$getCurrentUrl()
```

```
## [[1]]
## [1] "https://www.google.com/#gws_rd=ssl"
```

```r
remDr$goForward()
remDr$getCurrentUrl()
```

```
## [[1]]
## [1] "http://www.bbc.com/"
```

現在のページを更新するには`refresh`メソッドが使えます．

```r
remDr$refresh()
```

## DOM要素へのアクセス
DOMとはドキュメント・オブジェクト・モデル（Document Object Model）のことを表しています．DOMはHTML，XHTML，XMLのオブジェクトを表現し操作するための，クロスプラットフォームで言語に依存しない規約です．DOMの操作はSeleniumを使う我々にとって非常に重要です．WebDriverはDOM操作のための多くのメソッドを提供します．基本的なHTMLページは以下のようになっています．

```html
<!DOCTYPE html>
<html>
<body>

<h1>My First Heading</h1>

<p>My first paragraph.</p>

</body>
</html>
```

`http://www.google.com`のフロントページにある検索フォームには`input id="lst-ib" class="gsfi"`というHTMLのコードが関連付けられています．`input`タグに関連付けられたHTMLの全体は以下のようになっています．[^2]

```html
<input class="gsfi" id="lst-ib" maxlength="2048" name="q" autocomplete="off" title="Search" type="text" value="" aria-label="Search" aria-haspopup="false" role="combobox" aria-autocomplete="both" style="border: none; padding: 0px; margin: 0px; height: auto; width: 100%; position: absolute; z-index: 6; left: 0px; outline: none; background: url(&quot;data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw%3D%3D&quot;) transparent;" dir="ltr" spellcheck="false">
```

### idで検索する
この要素をDOMの中で見つけるには様々な方法が使えます．
まずidで検索することができます．


```r
remDr$navigate("http://www.google.com/ncr")
webElem <- remDr$findElement(using = 'id', value = "lst-ib")
webElem$getElementAttribute("id")
```

```
## [[1]]
## [1] "lst-ib"
```

```r
webElem$getElementAttribute("class")
```

```
## [[1]]
## [1] "gsfi lst-d-f"
```

### classで検索する
classの名前でも検索することができます．

```r
webElem <- remDr$findElement(using = 'class name', "gsfi")
webElem$getElementAttribute("class")
```

```
## [[1]]
## [1] "gsfi lst-d-f"
```

```r
webElem$getElementAttribute("type")
```

```
## [[1]]
## [1] "text"
```

<!-- ### Search using css-selectors -->
### cssセレクタを使って検索する
cssセレクタを使う場合，classは`.`を用いて表現されます．cssセレクタを使ってclassで検索するなら以下のようになるでしょう．

```r
webElem <- remDr$findElement(using = 'css selector', "input.gsfi")
```

また，cssセレクタを使ってidで検索するなら以下のようにします．

```r
webElem <- remDr$findElement(using = 'css selector', "input#lst-ib")
```

cssセレクタを使った検索の良い例が[ここ](http://saucelabs.com/resources/selenium/css-selectors)にあります．

### nameで検索する
nameが与えられている場合に，これを使って検索するには以下のようにします．与えられたHTMLページでidはユニークですが，nameは必ずしもユニークにならないことに注意してください．

```r
webElem <- remDr$findElement(using = 'name', "q")
webElem$getElementAttribute("name")
```

```
## [[1]]
## [1] "q"
```

```r
webElem$getElementAttribute("id")
```

```
## [[1]]
## [1] "lst-ib"
```

### xpathを使って検索する
最後の検索方法はxpathを使うものです．通常，デフォルトではxpathを使って検索することになります．xpathでidを使って検索するには次のようにします．

```r
webElem <- remDr$findElement(using = 'xpath', "//*/input[@id = 'lst-ib']")
```

xpathでclassを使う場合は以下のようになります．

```r
webElem <- remDr$findElement(using = 'xpath', "//*/input[@class = 'gsfi']")
```

## DOM要素にイベントを送信する

DOM要素とやりとりする方法を示すため，再び`http://www.google.com/ncr`を例に取ります．

### DOM要素にテキストを送信する

googleで`R Cran`を検索したいとしましょう．それには検索フォームの要素を見つけて適切なテキストをそこに送る必要があります．`webElement`クラスの`sendKeysToElement`メソッドを使えばこれが可能です．

```r
remDr$navigate("http://www.google.com/ncr")
webElem <- remDr$findElement(using = "xpath", "//*/input[@id = 'lst-ib']")
webElem$sendKeysToElement(list("R Cran"))
```

### キーの押下をDOM要素に送信する
さて，検索フォームに`R Cran`と入力されたのが見えているはずですが，Enterキーはどうやって押したらよいでしょうか．単に検索フォームにEnterキーを送信すればよいのです．Enterキーは`"\uE007"`で表現されるので，以下のようにできます．

```r
remDr$navigate("http://www.google.com/ncr")
webElem <- remDr$findElement(using = "xpath", "//*/input[@id = 'lst-ib']")
webElem$sendKeysToElement(list("R Cran", "\uE007"))
```

適切なキーのUTF8コードを記憶しておくのはあまり簡単ではないので，`RSelenium`ではキーとUTF8コードの変換表を提供しています．`?selKeys`と入力すれば変換表について解説したヘルプページが開きます．`selKeys`では[ここ](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelementidvalue)に書かれているUTF8のコードが覚えやすい名前に変換されています．

`selKeys`を使うには，以下のようにしてキーを送信します．


```r
remDr$navigate("http://www.google.com/ncr")
webElem <- remDr$findElement(using = "xpath", "//*/input[@id = 'lst-ib']")
webElem$sendKeysToElement(list("R Cran", key = "enter"))
```

`selKeys`とタイプすればコンソールに変換表のリストが表示されます．

### マウスのイベントをDOM要素に送信する
以下の例では，googleのフロントページに戻って`R Cran`を検索した後，`The Comprehensive R Archive Network`へのリンクをクリックします．

```r
remDr$navigate("http://www.google.com/ncr")
webElem <- remDr$findElement(using = "xpath", "//*/input[@id = 'lst-ib']")
webElem$sendKeysToElement(list("R Cran", key = "enter"))
```

検索結果が含まれているのは`<div class="g">`要素であり，`findElements`メソッドを使えば1ページ目の検索結果の全てのエントリを見つけることができます．さらに，各リンクのヘッダは`<h3 class = "r">`タグに含まれています，まずは`h3`ヘッダにアクセスします．cssセレクタを使って要素を見つけるのが簡潔です．

```r
webElems <- remDr$findElements(using = 'css selector', "div.g h3.r")
resHeaders <- unlist(lapply(webElems, function(x){x$getElementText()}))
resHeaders
```

```
##  [1] "The Comprehensive R Archive Network"       
##  [2] "Download R for Windows"                    
##  [3] "Contributed Packages"                      
##  [4] "CRAN"                                      
##  [5] "R for Windows"                             
##  [6] "R for Mac OS X"                            
##  [7] "CRAN - Mirrors"                            
##  [8] "R: The R Project for Statistical Computing"
##  [9] "The Comprehensive R Archive Network"       
## [10] "CRAN - Package evaluate"                   
## [11] "CRAN - Package backtest"                   
## [12] "CRAN - Package bit"                        
## [13] "CRAN - Package bitops"
```

最初のリンクが欲しいものであることがわかりますが，googleの検索結果が変わった場合に備えて，以下のようにしてアクセスします[^3]．

```r
# webElem <- webElems[[which(resHeaders == "The Comprehensive R Archive Network")]]
webElem <- webElems[[which(resHeaders == "The Comprehensive R Archive Network")[1]]]
```

クリックはどうすればよいかというと，`clickElement`メソッドが使えます．

```r
webElem$clickElement()
remDr$getCurrentUrl()
```

```
## [[1]]
## [1] "https://www.google.com/#q=R+Cran"
```

```r
remDr$getTitle()
```

```
## [[1]]
## [1] "R Cran - Google Search"
```

## JavaScriptを注入する

時には現在のURLとJavaScriptを使ってやりとりする必要があります．これが必要になるのは，特定の目的のために書かれたメソッドを呼ぶためかもしれませんし，`JQuery`ライブラリがページにない場合にこれを加えてよりページを制御しやすくするためかもしれません．`Selenium`にはJavaScriptを実行するのに使える`remoteDriver`クラスの2つのメソッド，すなわち`executeScript`と`executeAsyncScript`とがあります．googleのフロントページに戻ってこれらのメソッドについて調べてみましょう．

### 同期的にJavaScriptを注入する
googleのホームページに戻ると，`google`の画像の要素が見つかります．この画像は`id = "hplogo"`となっており，これをxpathやid等による検索で要素を選択するのに使うことができます．今回はcssセレクタを使って選択します．

```r
remDr$navigate("http://www.google.com/ncr")
webElem <- remDr$findElement("css selector", "img#hplogo")
```

```r
remDr$executeScript("return document.getElementById('hplogo').hidden;", args = list())
```

```
## [[1]]
## [1] FALSE
```

うまくいきました．`FALSE`が示している通り，画像は隠されてはいません．簡単なJavaScriptを実行すれば画像を隠すことができます．

```r
remDr$executeScript("document.getElementById('hplogo').hidden = true;", args = list())
```

```
## [[1]]
## [1] FALSE
```

```r
remDr$executeScript("return document.getElementById('hplogo').hidden;", args = list())
```

```
## [[1]]
## [1] TRUE
```

こうして画像が隠れました．ここでは`id = "hplogo"`で与えられる要素を使いました．要素にアクセスするにはJavaScriptの`getElementByID`関数を使う必要がありましたが，もしさきほど特定しておいた`webElem`が使えればもっと便利でしょう．`webElement`オブジェクトを`executeScript`か`executeAsyncScript`に引数として渡すと，`RSelenium`はこれを適切な形式にしてJavaScriptに渡してくれます．

```r
remDr$executeScript(script = "return arguments[0].hidden = false;", args = list(webElem))
```

```
## [[1]]
## [1] FALSE
```

`executeScript`メソッドへの`webElement`の渡し方に注目してください．`script`引数は実行するスクリプトを関数のボディの形式で定義します．この関数が返す値はクライアントに返されます．関数は与えられた`args`引数とともに呼び出されます．もし関数がDOM要素を返すものであれば，`webElement`クラスのオブジェクトとして返されます．

```r
test <- remDr$executeScript("return document.getElementById('lst-ib');", args = list())
test[[1]]
```

```
## [1] "remoteDriver fields"
## $remoteServerAddr
## [1] "localhost"
## 
## $port
## [1] 4444
## 
## $browserName
## [1] "firefox"
## 
## $version
## [1] ""
## 
## $platform
## [1] "ANY"
## 
## $javascript
## [1] TRUE
## 
## $autoClose
## [1] FALSE
## 
## $nativeEvents
## [1] TRUE
## 
## $extraCapabilities
## list()
## 
## [1] "webElement fields"
## $elementId
## [1] "20"
```

```r
class(test[[1]])
```

```
## [1] "webElement"
## attr(,"package")
## [1] "RSelenium"
```

### 非同期的にJavaScriptを注入する
非同期呼び出しと同期呼び出しについてここで簡単に触れておきます．著者の場合，現在のFirefoxとSeleniumサーバの組み合わせ（Firefox 26.0, Selenium server 2.39.0）において，非同期JavaScript呼び出しで`nativeEvents = TRUE` （デフォルトの設定）とした時に問題が発生しました．

以下の例では`nativeEvents = FALSE`と設定しました．


```r
remDr <- remoteDriver(nativeEvents = FALSE)
remDr$open()
```

```
## [1] "Connecting to remote server"
## $applicationCacheEnabled
## [1] TRUE
## 
## $rotatable
## [1] FALSE
## 
## $handlesAlerts
## [1] TRUE
## 
## $databaseEnabled
## [1] TRUE
## 
## $version
## [1] "41.0.2"
## 
## $platform
## [1] "WINDOWS"
## 
## $nativeEvents
## [1] FALSE
## 
## $acceptSslCerts
## [1] TRUE
## 
## $webdriver.remote.sessionid
## [1] "1b3c6552-7483-4442-a6cb-03a8db6bb73c"
## 
## $webStorageEnabled
## [1] TRUE
## 
## $locationContextEnabled
## [1] TRUE
## 
## $browserName
## [1] "firefox"
## 
## $takesScreenshot
## [1] TRUE
## 
## $javascriptEnabled
## [1] TRUE
## 
## $cssSelectorsEnabled
## [1] TRUE
## 
## $id
## [1] "1b3c6552-7483-4442-a6cb-03a8db6bb73c"
```

```r
remDr$navigate("http://www.google.com/ncr")
remDr$setAsyncScriptTimeout(10000)
```

以下の2つのコードを比べてみてください[^4]．

```r
remDr$executeAsyncScript("setTimeout(function(){ alert('Hello'); arguments[arguments.length -1]('DONE');},5000); ", args = list())
```

```r
remDr$executeScript("setTimeout(function(){ alert('Hello');},5000); return 'DONE';", args = list())
```

非同期バージョンではコールバック（最後の引数で定義されています）が呼ばれるまで待機します．

## フレームとウィンドウ
webブラウザの文脈では，フレームとはwebページやブラウザのウィンドウの一部分であって，自身のコンテナとは独立にコンテンツを表示し，ロードできるもののことです．

### Seleniumにおけるフレーム
フレームとのやりとりを例で示します．[Rプロジェクト](http://www.r-project.org/)のページは好都合なことにフレームを含んでいるので，`RSelenium`を使ってやりとりしてみます[^5]．`remoteDriver`は開いてあるものとします．

```r
remDr$navigate("http://cloud.r-project.org/")
htmlParse(remDr$getPageSource()[[1]])
```

```
## <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
## <html xmlns="http://www.w3.org/1999/xhtml">
## <head>
## <title>The Comprehensive R Archive Network</title>
## <meta content="text/html; charset=utf-8" http-equiv="content-type">
## <link type="image/x-icon" href="favicon.ico" rel="icon">
## <link type="image/x-icon" href="favicon.ico" rel="shortcut icon">
## <link href="R.css" type="text/css" rel="stylesheet">
## </head>
## <frameset style="border: none;" cols="1*, 4*">
## <frameset rows="120, 1*">
## <frame frameborder="0" name="logo" src="logo.html">
## <frame frameborder="0" name="contents" src="navbar.html">
## </frameset>
## <frame frameborder="0" name="banner" src="banner.shtml">
## <noframes>
## &lt;h1&gt;The Comprehensive R Archive Network&lt;/h1&gt;
## 
## Your browser seems not to support frames,
## here is the &lt;A href="navbar.html"&gt;contents page&lt;/A&gt; of CRAN.
## </noframes>
## </frameset>
## </html>
## 
```

3つのフレームにコンテンツが含まれていることが分かりますが，フレームの中のコンテンツにはアクセスできないようです．見ているブラウザの中に全てのコンテンツを表示させてみます．

```r
remDr$maxWindowSize()
remDr$screenshot(display = TRUE)
```

![tmpScreenShot-ja.png](https://qiita-image-store.s3.amazonaws.com/0/58917/00fd52fe-43d9-1652-a83d-e0ba5b5142ee.png)

フレームの中のコンテンツにアクセスするには`remoteDriver`クラスの`switchToFrame`メソッドを使ってフレームを切り替える必要があります．

```r
webElems <- remDr$findElements(using = "tag name", "frame")
# webElems <- remDr$findElements("//frame") # xpathを使う場合

sapply(webElems, function(x){x$getElementAttribute("src")})
```

```
## [[1]]
## [1] "https://cloud.r-project.org/logo.html"
## 
## [[2]]
## [1] "https://cloud.r-project.org/navbar.html"
## 
## [[3]]
## [1] "https://cloud.r-project.org/banner.shtml"
```

```r
remDr$switchToFrame(webElems[[2]])  

htmlParse(remDr$getPageSource()[[1]])
```

```
## <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
## <html xmlns="http://www.w3.org/1999/xhtml">
## <head>
## <title>R Contents</title>
## <meta content="text/html; charset=utf-8" http-equiv="content-type">
## <link href="R.css" type="text/css" rel="stylesheet">
## </head>
## <body>
## 
## <em class="navigation">CRAN</em><br><a target="banner" href="mirrors.html">Mirrors</a><br><a target="banner" href="//www.R-project.org/news.html">What's new?</a><br><a target="banner" href="web/views/">Task Views</a><br><a target="banner" href="search.html">Search</a><br><!--<a href="pkg_submit.html" target="_top">Submit</a><BR>--><p>
## <em class="navigation">About R</em><br><a target="_top" href="//www.R-project.org/">R Homepage</a><br><a target="_top" href="http://journal.R-project.org/">The R Journal</a>
## 
## </p>
## <p>
## <em class="navigation">Software</em><br><a target="banner" href="sources.html">R Sources</a><br><a target="banner" href="bin/">R Binaries</a><br><a target="banner" href="web/packages/">Packages</a><br><a target="banner" href="other-software.html">Other</a>
## 
## </p>
## <p>
## <em class="navigation">Documentation</em><br><a target="banner" href="manuals.html">Manuals</a><br><a target="banner" href="faqs.html">FAQs</a><br><a target="banner" href="other-docs.html">Contributed</a><br></p>
## </body>
## </html>
## 
```

こうして案内用のサイドパネルのソースコードが見えるようになりました．`switchToFrame`メソッドにおける`webElement`の使い方に注目してください．今このフレームの「中に」いることをさらに明らかにするために，全ての`href`属性を取得してみましょう．

```r
webElems <- remDr$findElements("css selector", "[href]")
unlist(sapply(webElems, function(x){x$getElementAttribute("href")}))
```

```
##  [1] "https://cloud.r-project.org/R.css"              
##  [2] "https://cloud.r-project.org/mirrors.html"       
##  [3] "https://www.r-project.org/news.html"            
##  [4] "https://cloud.r-project.org/web/views/"         
##  [5] "https://cloud.r-project.org/search.html"        
##  [6] "https://www.r-project.org/"                     
##  [7] "http://journal.r-project.org/"                  
##  [8] "https://cloud.r-project.org/sources.html"       
##  [9] "https://cloud.r-project.org/bin/"               
## [10] "https://cloud.r-project.org/web/packages/"      
## [11] "https://cloud.r-project.org/other-software.html"
## [12] "https://cloud.r-project.org/manuals.html"       
## [13] "https://cloud.r-project.org/faqs.html"          
## [14] "https://cloud.r-project.org/other-docs.html"
```

`switchToFrame`メソッドに`NULL`を渡せばデフォルトのビューに戻ることに注意してください．

```r
remDr$switchToFrame(NULL)
htmlParse(remDr$getPageSource()[[1]])
```

```
## <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
## <html xmlns="http://www.w3.org/1999/xhtml">
## <head>
## <title>The Comprehensive R Archive Network</title>
## <meta content="text/html; charset=utf-8" http-equiv="content-type">
## <link type="image/x-icon" href="favicon.ico" rel="icon">
## <link type="image/x-icon" href="favicon.ico" rel="shortcut icon">
## <link href="R.css" type="text/css" rel="stylesheet">
## </head>
## <frameset style="border: none;" cols="1*, 4*">
## <frameset rows="120, 1*">
## <frame frameborder="0" name="logo" src="logo.html">
## <frame frameborder="0" name="contents" src="navbar.html">
## </frameset>
## <frame frameborder="0" name="banner" src="banner.shtml">
## <noframes>
## &lt;h1&gt;The Comprehensive R Archive Network&lt;/h1&gt;
## 
## Your browser seems not to support frames,
## here is the &lt;A href="navbar.html"&gt;contents page&lt;/A&gt; of CRAN.
## </noframes>
## </frameset>
## <body><canvas id="fxdriver-screenshot-canvas" style="display: none;" width="1824" height="1009"></canvas></body>
## </html>
## 
```

最後になりましたが，名前を使ってメインパネルに切り替えることができます．

```r
remDr$switchToFrame("banner")
htmlParse(iconv(remDr$getPageSource()[[1]], from="UTF-8"))
```

```
## <!DOCTYPE html PUBLIC "-//IETF//DTD HTML//EN">
## <html xmlns="http://www.w3.org/1999/xhtml">
## <head>
## <title>The Comprehensive R Archive Network</title>
## <link href="R.css" type="text/css" rel="stylesheet">
## </head>
## <body>
## 
## <h1>The Comprehensive R Archive Network</h1>
## 
## <div align="center">
## <table width="80%" border="1"><tbody>
## <tr>
## <td>
## <h3>Download and Install R</h3>
##       Precompiled binary distributions of the base system and
##       contributed packages, <strong>Windows and
##       Mac</strong> users most likely want one of these versions of R:
## 	<ul>
## <li><a href="bin/linux/">Download R for Linux</a></li>
## 	  <li>
## <a href="bin/macosx/">Download R for (Mac) OS X</a>
## 	  </li>
## <li><a href="bin/windows/">Download R for Windows</a></li>
## 	</ul>
##     R is part of many Linux distributions, you should check with your Linux package management system in addition to the link above.
##     </td>
##   </tr>
## <tr>
## <td>
## <h3>Source Code for all Platforms</h3>
##       Windows and Mac users most likely want to download the
##       precompiled binaries listed in the upper box, not the source
##       code. The sources have to be compiled before you can use
##       them. If you do not know what this means, you probably do not
##       want to do it!
## 	<ul>
## <li>The latest release (Tuesday 2016-06-21, Bug in Your Hair)
## 	      <a href="src/base/R-3/R-3.3.1.tar.gz">R-3.3.1.tar.gz</a>, read
## 	      <a href="doc/manuals/r-release/NEWS.html">what's new</a> in the latest
## 	      version.<p>
##  	  </p>
## </li>
## <li>Sources of
## 	  <a href="src/base-prerelease/">R alpha and beta releases</a>
## 	  (daily snapshots, created only in time periods before a planned release).</li>
## 	  <p>
## 	  </p>
## <li>Daily snapshots of current patched and development
##               versions are 
## 	      <a target="_blank" href="https://stat.ethz.ch/R/daily">available
## here</a>. Please read about <a href="doc/manuals/r-devel/NEWS.html">new features and bug
## fixes</a> before filing corresponding feature requests or bug reports.</li>
## <p>
## 	  </p>
## <li>Source code of 
## 	  older versions of R is <a href="src/base/">available here</a>.<p>
## 	  	  </p>
## </li>
## <li>Contributed extension
## 	  <a href="web/packages/index.html">packages</a>
## 
## 	</li>
## </ul>
## </td>
##   </tr>
## <tr>
## <td>
## <h3>Questions About R</h3>
##       <ul><li>
##       If you have questions about R like how to download and install
##       the software, or what the license terms are,
##       please read our <a href="faqs.html">answers to frequently asked
##       questions</a> before you send an email.
## 	</li></ul>
## </td>
##   </tr>
## </tbody></table>
## </div>
## 
## <h2>What are R and CRAN?</h2>
## 
## <p> R is ﾂ‘GNU Sﾂ’, a freely available language and environment for
## statistical computing and graphics which provides a wide variety of
## statistical and graphical techniques: linear and nonlinear modelling,
## statistical tests, time series analysis, classification, clustering,
## etc. Please consult the <a target="_top" href="https://www.R-project.org/">R project homepage</a> for further information.
## </p>
## 
## <p> CRAN is a network of ftp and web servers around the world that
## store identical, up-to-date, versions of code and documentation for
## R. Please use the CRAN <a href="mirrors.html">mirror</a> nearest to you to minimize network
## load.
## </p>
## 
## <h2 id="submitting">Submitting to CRAN </h2>
## 
## <p>
## To ﾂ“submitﾂ” a package to CRAN,
## check that your submission meets the
## <a href="https://CRAN.R-project.org/web/packages/policies.html">CRAN
##   Repository Policy</a> and then use the
## <a href="https://xmpalantir.wu.ac.at/cransubmit/">web form</a>.
## </p>
## 
## <p>
## If this fails, upload to
## <a target="_blank" href="ftp://CRAN.R-project.org/incoming/">ftp://CRAN.R-project.org/incoming/</a>
## and send an email to
## <a href="mailto:CRAN@R-project.org">CRAN@R-project.org</a> following the policy.
## Please do not attach submissions to emails, because this will clutter up
## the mailboxes of half a dozen people.
## </p>
## 
## <p>
## Note that we generally do not accept submissions of precompiled
## binaries due to security reasons. All binary distribution listed above
## are compiled by selected maintainers, who are in charge for all
## binaries of their platform, respectively.
## </p>
## 
## <p>
## </p>
## <hr>
## <!--#if expr="$CRAN_HOST" --><!--#echo  encoding="none" var="CRAN_HOST"--><br><!--#endif -->
## </body>
## </html>
## 
```

### Seleniumにおけるウィンドウ

`RSelenium`におけるウィンドウについて説明するには，やはり例を見るのが最も簡単です．Rプロジェクトのウェブサイトを例に使います．まずメインのフレームの`Download R`要素を選択します．

```r
remDr$navigate("http://cloud.r-project.org")
remDr$switchToFrame("banner")
webElem <- remDr$findElement("partial link text", "Download R")

webElem$getElementText()
```

```
## [[1]]
## [1] "Download R for Linux"
```

それから，この要素が指し示しているリンクを新しいウィンドウで開くためのキーの組み合わせを送信します．もし手動でやるとすれば，マウスをこの要素まで移動させ，リンクを右クリックし，下向き矢印を2回押してからEnterを押すことになるでしょうが，これと同じことをやります．

```r
loc <- webElem$getElementLocation()

loc[c('x','y')]
```

```
## $x
## [1] 197
## 
## $y
## [1] 124
```

```r
remDr$mouseMoveToLocation(webElement = webElem) # マウスを選択した要素に移動
remDr$click(2) # 2はマウスの右クリックを表す
remDr$sendKeysToActiveElement(list(key = 'down_arrow', key = 'down_arrow', key = 'enter'))
```

リモートブラウザで新しいウインドウが開かれたことに注目してください．

```r
remDr$getCurrentWindowHandle()
```

```
## [[1]]
## [1] "{cc17d1d7-d0b9-4f82-99c3-6d2322b5506b}"
```

```r
remDr$getWindowHandles()[[1]][2]
```

```
## [1] "{d12548bb-3bad-4d0d-b494-ccde0bc508f1}"
```

```r
remDr$getTitle()
```

```
## [[1]]
## [1] "The Comprehensive R Archive Network"
```

```r
remDr$switchToWindow(remDr$getWindowHandles()[[1]][2])
remDr$getTitle()
```

```
## [[1]]
## [1] "Index of /bin/linux"
```

上記のコードによって，リモートブラウザの異なるウィンドウ間を切り替える方法が分かります．[^6]


[^1]: 原文では`startServer()`の戻り値を捨てているが，戻り値のオブジェクトにはSeleniumサーバを停止するための`stop()`メソッドが含まれるので，戻り値を捨てない方がよいと思う（さもないとRの外でサーバプロセスを停止する必要がある）．

[^2]: 例に使われているgoogle.comの構造は原文が書かれた頃から変化しているため，以下では訳者の環境で意図した動作をするようにコードを適宜変更している．

[^3]: 原文のコードでは`which(resHeaders == "The Comprehensive R Archive) Network"`が2つ以上の要素を返すとエラーとなるため，1番目の要素を使用するようコードを変更している．

[^4]: 訳者の環境では2つのコードは両方とも下記のようなエラーとなった．

    ```
    Error: Summary: UnexpectedAlertOpen
    Detail: A modal dialog was open, blocking this operation
    class: org.openqa.selenium.UnhandledAlertException
    ```

[^5]: 現在では`http://www.r-project.org/`にフレームがないため，以下の例では代わりにCRANミラーのひとつ`http://cloud.r-project.org/`を例として使用し，コードも適切に動作するよう適宜原文から変更している．

[^6]: 作業が終わった後に`remoteDriver`を閉じてSeleuniumサーバを停止するには，以下のコードを実行する．．

    
    ```r
    remDr$close()
    srv$stop()
    ```
    最後に訳者の環境を示しておく．
    
    ```r
    devtools::session_info()
    ```
    
    ```
    ## Session info --------------------------------------------------------------
    ```
    
    ```
    ##  setting  value                       
    ##  version  R version 3.2.5 (2016-04-14)
    ##  system   x86_64, mingw32             
    ##  ui       RTerm                       
    ##  language (EN)                        
    ##  collate  Japanese_Japan.932          
    ##  tz       Asia/Tokyo                  
    ##  date     2016-08-30
    ```
    
    ```
    ## Packages ------------------------------------------------------------------
    ```
    
    ```
    ##  package       * version  date       source        
    ##  bitops        * 1.0-6    2013-08-17 CRAN (R 3.2.3)
    ##  caTools         1.17.1   2014-09-10 CRAN (R 3.2.5)
    ##  devtools        1.11.1   2016-04-21 CRAN (R 3.2.5)
    ##  digest          0.6.9    2016-01-08 CRAN (R 3.2.5)
    ##  evaluate        0.9      2016-04-29 CRAN (R 3.2.5)
    ##  formatR         1.4      2016-05-09 CRAN (R 3.2.5)
    ##  htmltools       0.3.5    2016-03-21 CRAN (R 3.2.5)
    ##  knitr           1.13     2016-05-09 CRAN (R 3.2.5)
    ##  magrittr        1.5      2014-11-22 CRAN (R 3.2.5)
    ##  memoise         1.0.0    2016-01-29 CRAN (R 3.2.5)
    ##  Rcpp            0.12.5   2016-05-14 CRAN (R 3.2.5)
    ##  RCurl         * 1.95-4.8 2016-03-01 CRAN (R 3.2.3)
    ##  RevoUtilsMath * 3.2.5    2016-05-03 local         
    ##  RJSONIO       * 1.3-0    2014-07-28 CRAN (R 3.2.3)
    ##  rmarkdown       1.0      2016-07-08 CRAN (R 3.2.5)
    ##  RSelenium     * 1.4.0    2016-07-30 CRAN (R 3.2.5)
    ##  stringi         1.1.1    2016-05-27 CRAN (R 3.2.5)
    ##  stringr         1.0.0    2015-04-30 CRAN (R 3.2.5)
    ##  withr           1.0.1    2016-02-04 CRAN (R 3.2.5)
    ##  XML           * 3.98-1.4 2016-03-01 CRAN (R 3.2.3)
    ##  yaml            2.1.13   2014-06-12 CRAN (R 3.2.5)
    ```