Rのパッケージ chromote を確認します。
chromoteは、RからGoogle Chrome(またはChromium系ブラウザ)をプログラム的に操作するためのパッケージです。
ボタンをクリックして、JavaScriptによって動的に表示されるデータを取得
HTMLページの作成
まずは、テスト用のHTMLページを作成してローカル環境に保存します。
作成しましたテスト用ページはこちらで確認してください。
# HTMLソースコードを文字列として定義
chromote_samplepage01 <- '
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Dynamic Page Test</title>
</head>
<body>
<h1>JavaScript操作テスト</h1>
<!-- 初期状態のテキスト -->
<div id="data-container">初期データ(未クリック)</div>
<!-- クリックするとJavaScriptを実行するボタン -->
<button id="load-btn" onclick="loadData()">データを読み込む</button>
<script>
function loadData() {
// ボタンがクリックされたらテキストを書き換える
document.getElementById("data-container").innerText = "JavaScriptによって読み込まれたシークレットデータ";
}
</script>
</body>
</html>
'
# 一時ファイルとしてHTMLを保存
tmp_html <- tempfile(fileext = ".html")
writeLines(chromote_samplepage01, tmp_html)今回の目的は、ボタンをクリックした後に表示される「JavaScriptによって読み込まれたシークレットデータ」という文字列を取得することです。
Rコード
chromoteを利用して、裏側で実際のChromeブラウザを動かし、「ボタンをクリックさせる」という操作をJavaScript経由で実行し、変化後のデータを取得します。
library(chromote)
# 裏側でHeadless Chromeのセッションを立ち上げる
session <- ChromoteSession$new()
# ローカルファイルのパスをURL形式(file://...)に変換してブラウザで開く
file_url <- paste0("file://", normalizePath(tmp_html, winslash = "/"))
session$Page$navigate(file_url)
# ページの読み込み完了を待つ
Sys.sleep(1)
# ブラウザ上でJavaScriptを実行し、ボタンをクリックさせる
session$Runtime$evaluate('document.getElementById("load-btn").click();')
# ボタンクリック後、変化した要素のテキストをJavaScript経由で取得する
res <- session$Runtime$evaluate('document.getElementById("data-container").innerText;')
# 取得した結果から値を抽出
text_chromote <- res$result$value結果の確認
cat("chromoteでの取得結果:\n", text_chromote, "\n\n")
# 最後にセッション(ブラウザ)を閉じる
session$close()chromoteでの取得結果:
JavaScriptによって読み込まれたシークレットデータ
[1] TRUE実際のブラウザが裏で動いているため、ボタンクリック(click())が発火し、JavaScriptの関数が実行されました。その結果、目的のテキストを取得できています。
テキストボックスに文字を入力し、検索ボタンを押す
HTMLページの作成
作成しましたテスト用ページはこちらで確認してください。
chromote_samplepage02 <- '
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Input Test</title>
</head>
<body>
<h1>検索フォーム入力テスト</h1>
<!-- 文字を入力するテキストボックス -->
<input type="text" id="search-box" value="">
<!-- 検索ボタン -->
<button id="search-btn" onclick="executeSearch()">検索する</button>
<br><br>
<!-- 結果が表示されるエリア -->
<div id="result-area">【検索結果はここに表示されます】</div>
<script>
function executeSearch() {
// テキストボックスの中身を取得
var keyword = document.getElementById("search-box").value;
// 入力があった場合のみ、結果を書き換える
if(keyword !== "") {
document.getElementById("result-area").innerText =
"「" + keyword + "」の極秘データをデータベースから取得しました";
} else {
document.getElementById("result-area").innerText =
"キーワードが入力されていません。";
}
}
</script>
</body>
</html>
'
tmp_html <- tempfile(fileext = ".html")
writeLines(chromote_samplepage02, tmp_html)今回の目的は、テキストボックスに任意のキーワード(例:“地球温暖化”)を入力してボタンを押し、動的に生成される検索結果のテキストを取得することです。
Rコード
chromoteを利用して、JavaScript経由で「テキストボックスに文字を代入する」→「検索ボタンをクリックする」という一連の操作を行います。
library(chromote)
# セッションを立ち上げてページを開く
session <- ChromoteSession$new()
file_url3 <- paste0("file://", normalizePath(tmp_html, winslash = "/"))
session$Page$navigate(file_url3)
Sys.sleep(1)
# JavaScript経由でテキストボックス(inputタグ)に「地球温暖化」という文字を入力する
session$Runtime$evaluate('document.getElementById("search-box").value = "地球温暖化";')
# 検索ボタンをクリックさせる
session$Runtime$evaluate('document.getElementById("search-btn").click();')
# 処理が完了するのを少し待つ
Sys.sleep(1)
# ボタンクリック後の結果を取得する
res_input <- session$Runtime$evaluate('document.getElementById("result-area").innerText;')結果の確認
cat("chromoteでの取得結果:\n", res_input$result$value, "\n\n")
# 最後にセッションを閉じる
session$close()chromoteでの取得結果:
「地球温暖化」の極秘データをデータベースから取得しました
[1] TRUE動的に生成されたテキストを取得できています。
同様に、Webスクレイピングにおける、「ログインIDとパスワードを入力してログインボタンを押す」「検索窓にキーワードを入れて検索する」といった操作が、chromoteの利用により可能となります。
<canvas>要素に描画された画像データ(ピクセルデータ)の取得
Webサイトによっては、HTMLのテキストとしてではなく、JavaScriptを使って<canvas>という領域にグラフ、画像、あるいは文字を表示している場合があります。
chromoteは「ブラウザの画像レンダリング機能」を使えるため、この「描かれた絵」を画像データとして抽出することができます。
HTMLページの作成
HTML上には空の<canvas>タグだけを用意し、JavaScriptでそこに「Secret_Code: XYZ-777」という文字を描画するページを作成します。
作成しましたテスト用ページはこちらで確認してください。
chromote_samplepage03 <- '
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Canvas Test</title>
</head>
<body>
<h1>Canvas画像データ抽出テスト</h1>
<p>以下の枠内には、JavaScriptによって文字が「画像として」描かれています。</p>
<!-- Canvas要素(静的なHTML上ではただの空のタグです) -->
<canvas id="myCanvas" width="300" height="100"></canvas>
<script>
// ブラウザの機能を使って、Canvasに文字を描画する
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
// 背景を薄いグレーで塗りつぶす
ctx.fillStyle = "#f0f0f0";
ctx.fillRect(0, 0, 300, 100);
// 青い文字でシークレットコードを描画する
ctx.font = "24px sans-serif";
ctx.fillStyle = "blue";
ctx.fillText("Secret_Code: XYZ-777", 20, 50);
</script>
</body>
</html>
'
tmp_html <- tempfile(fileext = ".html")
writeLines(chromote_samplepage03, tmp_html)今回の目的は、Canvasに描かれた内容を、画像データ(Base64形式の文字列)として取得することです。
Rコード
chromoteは実際のブラウザエンジンを動かしているため、Canvasに描かれたピクセルデータを認識できます。
JavaScriptの toDataURL() という標準機能を使うことで、描画内容を「PNG画像のデータ(Base64文字列)」として取得することができます。
library(chromote)
session <- ChromoteSession$new()
file_url4 <- paste0("file://", normalizePath(tmp_html, winslash = "/"))
session$Page$navigate(file_url4)
Sys.sleep(1)
# JavaScript経由で、Canvasの描画内容をPNG画像データ(Base64形式)として取得する
res_canvas <- session$Runtime$evaluate('document.getElementById("myCanvas").toDataURL("image/png");')
# 取得した画像データ(文字列)を取り出す
base64_img <- res_canvas$result$value結果の確認
cat("chromoteでの取得結果:\n")
# データが非常に長いため、最初の60文字だけを表示します
cat(substring(base64_img, 1, 60), " ... (以下略)\n\n")
# 最後にセッションを閉じる
session$close()chromoteでの取得結果:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAABkCAYAAA ... (以下略)
[1] TRUE“data:image/png;base64,…” という文字列は画像データですので、実際のPNGファイルとして出力してみます。
library(magick)
library(base64enc)
# 1. ヘッダーを削除してバイナリにデコード
pure_b64_string <- sub("^data:image/png;base64,", "", base64_img)
raw_data <- base64decode(pure_b64_string)
# 2. magickパッケージでバイナリを画像として読み込む(アスペクト比を維持してリサイズ)
img <- image_read(raw_data) %>% image_resize("600")
# 3. 画像を表示(または画像情報を確認)する
print(img)
# 4. バイナリデータを直接ファイルとして書き出す場合
# writeBin(raw_data, "secret_code.png") format width height colorspace matte filesize density
1 PNG 600 200 sRGB TRUE 0 72x72以上です。


