0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

R & WebDriver & Firefox & Ubuntu24 でスクレイピングしてみる

Posted at

なんでこんなことを?ニッチすぎやしないか?

昔、 RSelenium を使ってスクレイピングしたとき、 Google Chrome と対応する WebDriver を用意したり、 Java や Selenium をセットアップしたり、最後に RSelenium をインストールしたりと、いろいろ準備が面倒だった覚えがあって。

そんなこともすっかり忘れて、最近、 Ubuntu24 に環境を変えて、何気なく snap info firefox って打ってみたら、 firefox.geckodriver が表示されることを発見!さらに firefox.geckodriver って打ってみたところ、 localhost:4444 ポートで待機する状態になることをさらに発見。なんと Firefox の WebDriver は標準でインストールされていたという衝撃的な事実、しかも Ubuntu22 でもそうだったかもしれないという、さらなる衝撃的な事実が。※何かの過程でインストールされただけで標準じゃないかもですが、その時はそう思ったって事で。

で、過去の RSelenium 使ったコードを見返してみたら、 rvest あたりを併用してたせいか、 RSelenium の機能はほんのちょっとしか使ってなかった。てことは「R から Firefox の WebDriver にアクセスするコードを書けば、事前準備ゼロで同じようなことができちゃうんじゃない?うん、これはいいぞ、おもしろそうだ」てな話です。

WebDriverの情報はどこに?

https://w3c.github.io/webdriver/https://w3c.github.io/webdriver/ あたりにそれぽいことが書いてあったので、そのあたりを参考に試してみようと思います。

で作ってみた(検証コードだけど)

で、作ったのが以下のとおりです。 WebDriver ではクリック等の操作のみで、それ以外は rvest を使うことを想定しています。あと、検証コードなのでステータスの確認とかエラー処理とかは一切していないので、要注意です。

WebDriverを操作する検証コード
library(dplyr)
library(httr)
library(rvest)
library(glue)

start_webdriver <- function() {
	stop_webdriver()
	system("firefox.geckodriver &")
	Sys.sleep(3)
}
stop_webdriver <- function() {
	system("pkill geckodriver")
	Sys.sleep(1)
}
webdriver_url <- function() {
	return('localhost:4444')
}
new_session <- function() {
    httr::set_config(verbose())
	httr::POST(glue("{webdriver_url()}/session")
		,body = list(capabilities = list(alwaysMatch = list(acceptInsecureCerts = T)))
		,encode = "json"
		,timeout(30)
	) %>% content %>% "$"(value) %>% "$"(sessionId) %>% return()
}
delete_session <- function(session_id) {
	httr::DELETE(glue("{webdriver_url()}/session/{session_id}"))
}
navigate_to <- function(session_id, url) {
	httr::POST(glue("{webdriver_url()}/session/{session_id}/url")
		,body = list(url = url)
		,encode = "json"
	)
}
get_page_source <- function(session_id) {
	httr::GET(glue("{webdriver_url()}/session/{session_id}/source")
	) %>% content %>% "$"(value) %>% return()
}
get_current_url <- function(session_id) {
	httr::GET(glue("{webdriver_url()}/session/{session_id}/url")
	) %>% content %>% "$"(value) %>% return()
}
find_element <- function(session_id, using, value) {
	httr::POST(glue("{webdriver_url()}/session/{session_id}/element")
		,body = list(using = using, value = value)
		,encode = "json"
	) %>% content %>% "$"(value) %>% unlist %>% return()
}
find_elements <- function(session_id, using, value) {
	httr::POST(glue("{webdriver_url()}/session/{session_id}/elements")
		,body = list(using = using, value = value)
		,encode = "json"
	) %>% content %>% "$"(value) %>% unlist %>% return()
}
switch_to_frame <- function(session_id, id) {
	if (id %>% is.character()) {
		id <- list("element-6066-11e4-a52e-4f735466cecf" = id)
	}
	httr::POST(glue("{webdriver_url()}/session/{session_id}/frame")
		,body = list(id = id)
		,encode = "json"
	)
}
switch_to_parent_frame <- function(session_id) {
	httr::POST(glue("{webdriver_url()}/session/{session_id}/frame/parent")
		,body = '{}'
	)
}
send_keys_to_element <- function(session_id, element_id, text) {
	httr::POST(glue("{webdriver_url()}/session/{session_id}/element/{element_id}/value")
		,body = list(text = text)
		,encode = "json"
	)
}
click_element <- function(session_id, element_id) {
	httr::POST(glue("{webdriver_url()}/session/{session_id}/element/{element_id}/click")
		,body = "{}"
	)
}

テストしてみるよ

テストとして The Comprehensive R Archive Network にアクセスして検索してみたいと思います。流れは以下のとおりです。

テストの流れ

The Comprehensive R Archive Network にアクセス

左側フレーム内の「Search」をクリック

右側のフレーム内の「search.r-project.org」をクリック

「abc」で検索

結果を取得

テスト
#開始&Rのページ(The Comprehensive R Archive Network)を開く
start_webdriver()
Sys.sleep(3) #ちょっと待つ
session_id <- new_session()
navigate_to(session_id, url="https://cran.r-project.org/")
Sys.sleep(3) #ちょっと待つ

#左フレームの「Search」をクリック
find_elements(session_id, using="xpath", value='//frame')[2] %>%
	switch_to_frame(session_id, .)
find_element(session_id, using="xpath", value='//A[text()="Search"]')[1] %>%
	click_element(session_id, .)
Sys.sleep(3) #ちょっと待つ

#右フレームの「search.r-project.org」をクリック
switch_to_parent_frame(session_id)
find_elements(session_id, using="xpath", value='//frame')[3] %>%
	switch_to_frame(session_id, .)
find_element(session_id, using="xpath", value='//A[text()="search.r-project.org"]') %>%
	click_element(session_id, .)
Sys.sleep(3) #ちょっと待つ

#キーワードに「abc」を入力し「Search」をクリック
find_element(session_id, using="xpath", value='//input[@id="omega-autofocus"]') %>%
	send_keys_to_element(session_id, ., "abc")
find_element(session_id, using="xpath", value='//input[@type="submit" and @value="Search"]') %>%
	click_element(session_id, .)
Sys.sleep(3) #ちょっと待つ

#検索結果を取得
switch_to_parent_frame(session_id)
get_page_source(session_id) %>% read_html %>%
	html_elements(xpath="//table[1]//td[2]/b/a") %>% as.character %>%
	data.frame() %>% rename(t = 1) %>%
	rowwise() %>%
	mutate(title = t %>% read_html() %>% html_text()) %>%
	mutate(url = t %>% read_html() %>% html_elements("a") %>% html_attr("href")) %>%
	ungroup %>%
	mutate(absolute_url = url_absolute(url, get_current_url(session_id))) %>% 
	select(title, absolute_url) %>% as.data.frame
結果
                                                               title                                                                 absolute_url
1                                                   R: Class '"abc"'         https://search.r-project.org/CRAN/refmans/forams/html/abc-class.html
2                           R: the ABC procedure for model selection                https://search.r-project.org/CRAN/refmans/lamme/html/abc.html
3                                                             R: ABC          https://search.r-project.org/CRAN/refmans/inventorize/html/ABC.html
4            R: Convert Simulation Results to abc's Parameter Format   https://search.r-project.org/CRAN/refmans/coala/html/create_abc_param.html
5                   R: ABC algorithm for network reverse-engineering           https://search.r-project.org/CRAN/refmans/networkABC/html/abc.html
6                                                    R: ABC analysis              https://search.r-project.org/CRAN/refmans/tsutils/html/abc.html
7  R: An automated analysis applying all ABC.RAP functions in one...  https://search.r-project.org/CRAN/refmans/ABC.RAP/html/process.ABC.RAP.html
8     R: Summaries of posterior samples generated by ABC algortithms          https://search.r-project.org/CRAN/refmans/abc/html/summary.abc.html
9    R: Convert Simulation Results to abc's Summary Statistic Format https://search.r-project.org/CRAN/refmans/coala/html/create_abc_sumstat.html
10                                      R: ABC Customer Satisfaction                 https://search.r-project.org/CRAN/refmans/Gifi/html/ABC.html

後片付けも忘れずに

今回のコードは、検証って言う位置づけなので、作成したセッション削除していませんし、 firefox.geckodriver をバックグラウンドで実行するものの、それっきりになっていますので、必要に応じて後片付けする必要あるかもです。

おわりです

とりあえず動いたという感じです。実際に使えるかはなんともですが、意外と簡単に操作できたので、必要な操作があれば追加も簡単そうです。とりあえずはあえずめでたし、めでたし、ということで。

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?