dt {
clear: left;
float: left;
width: 15%;
font-weight: bold;
text-align: right;
padding: 3px 15px 3px 0;
}
dd {
margin: 0 0 0 20%;
padding-top: 3px;
padding-bottom: 3px;
}
img {
border: 1px solid #003366;
margin-left: 30px;
}
webshotパッケージとは、RでWebページのスクリーンショットを簡単に取ることができるパッケージです。このパッケージはPhantomJSというアプリケーションを利用してキャプチャします。
これだけの情報だとあまり面白くないように思えるかもしれませんが、最近のR事情を考えるとかなり使える場面が多くなります。そこで今回はパッケージのvignetteをなぞらえた後に、私が考えた応用パターンを紹介します。
まずはwebshotパッケージをインストールします:
# CRANから
install.packages("webshot")
# GithHub版
devtools::install_github("wch/webshot")
個人的にはCRAN版で十全に使えると思いますし、どちらからパッケージをインストールしてもらっても大丈夫でしょう。ただ、使用するマシンにPhantomJSが使える必要があります。PhantomJS公式サイトからダウンロードしてインストールし、PATH
を通しておく必要があります。あまりこういうのに慣れない方は抵抗が出てしまうかもしれません。
でもご安心ください。このパッケージにはそのPhantomJSをマシンにインストールするための関数が準備してあります。以下の関数を実行してください:
webshot::install_phantomjs()
これでOKです。この関数を実行してインストールしてすぐに、以下の内容を実行したけどうまくいかない時は、以下のを試してみてください。
install_phantomjs()
は各種OSに対応しているので基本大丈夫なはずですが、うまく動かないとしても1もしくは2で大丈夫なはずです。
まずは記念撮影がてらやってましょう。ためしにKazutan.Rというサイトでやってみます。
webshot関数にurlを引き渡すことで、その対象のスクリーンショットを撮影します:
library(webshot)
url <- "https://kazutan.github.io/kazutanR"
webshot(url, file = "pics/webshot_demo_01.png", delay = 0.5)
うまくいったならば,(上の例なら)pics
ディレクトリ内にwebshot_demo_01.png
というpngファイルが生成されているはずです。簡単ですね。
webshot()
関数について関数の引数と初期値の一覧は以下のとおりです:
webshot(url = NULL, file = "webshot.png", vwidth = 992, vheight = 744,
cliprect = NULL, selector = NULL, expand = NULL, delay = 0.2,
zoom = 1, eval = NULL)
訪問するURLsのベクトル。
outputファイルの名前で,ベクトル。ファイル名の最後は.png, .pdf, .jpegのいずれかで,要するにこれらの出力形式に対応。url
の引数に複数のURLを与えていて,このfile
引数では単一の値しかない場合,連番のファイル名で出力されます。
Viewportの幅。これがwebshotがブラウザで訪問した際のウィンドウ幅となります。
Viewportの高さ。これがwebshotがブラウザで訪問した際のウィンドウ高さとなります。
クリッピングするrectangleを指定します。もしcliprect
とselector
の両方を指定しない場合,訪問したURLのサイトをまるっとそのままクリッピングしてきます。 cliprect = "viewport"
と指定すると,vwidth
とvheight
で指定したウィンドウ幅でクリップしてきます。
cliprect = c(200, 100, 300, 400)
と4つの要素を指定すると,順にtop, left, width, heightという値として解釈してクリッピングします。この例だと,「上から200左から100の点基準に幅300高さ400をクリッピングする」という意味となります。
url
で複数のURLを指定している場合,listで束ねて上記内容のようにクリッピングを指定することができます。もちろんlistの長さとurl
で渡したベクトルの長さは同一にしてください。 なお,このオプションはselector
とは併用できずどちらか一方となります。
矩形でクリッピングするDOM要素を特定するような,一つ以上のCSSセレクタを指定します。もし指定したセレクタがページ内で複数ヒットした場合,一番最初の要素をクリッピングしてきます。
url
にURLを複数指定した場合,listで束ねてクリッピング対象を指定することができます。もちろんlistの長さとurl
で渡したベクトルの長さは同一にしてください。 なお,このオプションはcliprect
とは併用できずどちらか一方となります。
矩形でクリッピングしたターゲットに対して,何ピクセル広げるかを指定します。余白というわけではなく,クリップするために指定した矩形(対象)を,上下左右に広げるかどうかを指定します。
expand = 25
と単一の値であれば,それが上下左右すべてに指定されます。expand = c(10, 20, 5, 30)
と4値指定すれば,順に上・右・下・左の値となります。
url
にURLを複数指定した場合,listで束ねてクリッピング対象を指定することができます。もちろんlistの長さとurl
で渡したベクトルの長さは同一にしてください。
ブラウザで開いてからスクリーンショットを撮影するまでに待つ時間を秒で指定します。ブラウザでアクセスしてから表示に時間がかかるような重たいサイトの場合,この値を大きめに確保しておく必要があるでしょう。
ズーム比を指定します。
ページを開いてdelay
の時間待機した後で,スクリーンショットを撮影する前に,評価させたいJavaScriptコードを指定します。文字列で渡します。詳しいことはCasper APIに記載してあるということなので,興味がある方は参照してください。
cliprect
を利用cliprect = "viewport"
と指定すると,vwidth
とvheight
で指定したウィンドウサイズでスクリーンショットを撮影します:
webshot(url, file = "pics/webshot_demo_02.png",
cliprect = "viewport")
また,cliprect = c(200, 100, 300, 400)
と具体的な値で指定も可能です:
webshot(url, file = "pics/webshot_demo_03.png",
cliprect = c(200, 100, 300, 150))
selector
を利用セレクタを指定してみます:
webshot(url, file = "pics/webshot_demo_04.png",
selector = ".navbar")
idでも指定可能です:
webshot(url, file = "pics/webshot_demo_05.png",
selector = "#contents")
cssで指定するように絞り込んでいくことも可能ですし,expand
も当てることができます:
webshot(url, file = "pics/webshot_demo_06.png",
selector = "#contents div")
webshot(url, file = "pics/webshot_demo_07.png",
selector = "#contents div",
expand = c(10, 15, 30, 5))
この他の例については,CRAN上のvignetteを参照してください。
{webshot}パッケージには,このwebshot()
以外にもいくつか関数が準備してあります。
Shinyアプリケーションのスクリーンショットを撮影するための関数です:
appshot(app, file = "webshot.png", ..., port = getOption("shiny.port"),
envvars = NULL)
詳しくはこの関数のヘルプ?appshot
を参照してください。
画像をリサイズする関数です。なおこれを使用するためにはGraphicsMagickもしくはImageMagickがそのマシンにインストールされている必要があります。詳しくは関数のヘルプ?resize
を参照してください。
PNG画像のファイルサイズを縮小する関数です。なおこれを使用するためにはoptipngがそのマシンにインストールされている必要があります。詳しくは関数のヘルプ?shrink
を参照してください。
ここから,私が考えるwebshotパッケージの応用例について紹介します。
最近ではRによる可視化としてhtmlwidgetsを利用したものが多く,色々な場面で見かけます。これらの多くはhtmlに埋め込むことによりインタラクティブなコンテンツを提供してくれます。
しかしこれらhtmlwidgetsオブジェクトはhtmlであり,pdfドキュメントやdocxドキュメントに埋め込むことはできません。また画像として埋め込もうと思うと,画面に表示してキャプチャしてファイルで保存し,それを埋め込むという作業工程が必要となり,効率的はありません。そこで,webshotを利用して簡単に画像化してみます。
まず例として,{leaflet}パッケージによる地図を生成してみます:
library(dplyr)
library(leaflet)
m <- leaflet() %>% addTiles() %>%
addPopups(135, 35, "Popup!")
m
ではこれを{webshot}で画像するには以下のようにします:
library(htmlwidgets)
saveWidget(m, file = "leaflet2png.html")
webshot("leaflet2png.html", file = "pics/webshot_demo_08.png", delay = 6)
まず,htmlwidgetsオブジェクトをhtmlwidgets::saveWidgets()
関数でhtmlファイルに出力します。そのhtmlファイルをwebshotでキャプチャする,という流れです。htmlwidgetsを利用しているパッケージであるならば,これで全て画像化することが可能です。
おそらくこのテクニックと相性がいいのは{leaflet}あたりでしょう。逆に相性が悪いのは{DT}あたりで,DT::datatable()
でちょいちょい設定しておかないと,きれいなキャプチャが取れないと思います。
なお一時的に作成したhtmlファイルが邪魔である場合は,webshot()
を実行した後file.remove()
で削除してしまうといいでしょう。
# 不要なhtmlファイルを削除
file.remove("leaflet2png.html")
## [1] TRUE
R MarkdownでWebサイトを作っていたり,あるいは何らかの資料を作成していると,Webページをキャプチャしてそれをリサイズして埋め込みたい,と思うことがあります。もしこれをそのままやろうとするならば,(1)Webサイトを表示,(2)キャプチャアプリで画像に落としこむ,(3)Rmdに画像を入れる,という流れとなります。
これは非常に手間ですし,またキャプチャ元のページ内容が更新されるとまたキャプチャし直しとなります。というわけでKnitする度に自動的にwebshotでキャプチャを取得し,そのままRmd内に埋め込めるようにします。
これを実現するには,{htmltools}というパッケージを利用します:
library(htmltools)
img <- webshot(url = "https://www.r-project.org/",
file = "pics/r-project_top.png",
cliprect = "viewport", vheight = 400, vwidth = 780)
tags$a(href="https://www.r-project.org/",
tags$img(src=img, alt="")
)
このhtmltools::tags
はhtmlタグを生成するための関数群で,htmlタグをRでプログラマラブルに生成できます。また,R MarkdownでWebサイトを生成する場合,webshotで各ページサムネイルを生成し,それを活用していくことも可能です。以下のリンク先などを参照してみてください:
試しにサムネイルを実装してみます:
library(htmltools)
thumbnail <- function(title, img, href, caption = TRUE) {
tags$div(class = "col-sm-4",
tags$a(class = "thumbnail", title = title, href = href,
tags$img(src = img),
tags$div(class = ifelse(caption, "caption", ""),
ifelse(caption, title, "")
)
)
)
}
title <- c("stringr", "forcats", "leaflet")
urls <- c("https://kazutan.github.io/kazutanR/stringr-intro.html",
"https://kazutan.github.io/kazutanR/forcats_test.html",
"https://kazutan.github.io/kazutanR/leaflet_d.html")
imgs <- webshot(urls, file = "pics/thumb.png", cliprect = "viewport", delay = 1)
thumbs <- mapply(thumbnail, title = title, img = imgs, href = urls,
SIMPLIFY = FALSE, USE.NAMES = FALSE)
tags$div(class = "row", thumbs)
このようなことも自動的に取得することができます。あとは色々と応用できるはずです。ぜひ試してみてください。
Enjoy!