LoginSignup
2
3

More than 3 years have passed since last update.

Rselenium + Rvest でログインが必要なページの向こうのデータをスクレイピングする

Posted at

ログインが必要なページとかもざくざく掘ってみよう

以前の記事で基本的なRseleniumの使い方を書いたのですが:
https://qiita.com/taiyodayo/items/def80bc3503766b24a89
ログインが必要なサイトやインタラクティブなページからデータを抜くのに苦労されてる方が多いようで、
僕がやったことをまとめてみました。
Rvest使うと、html/cssの知識とかそんなに無くてもサクサク行けますよ。

開発は二通りのやり方がある:

・selenium-web-driverを起動したマシンでリアルタイムに要素名見ながらやる
・remDr$screenshot(display=TRUE) を見ながらチクチクやる

自分は後者が案外快適でした。
docker上で動くRStudioでちくちくインタラクティブに作っていきました。
「スクショ見る -> htmlファイルに落とす -> Chromeで開く -> xpath取ってコマンド書く」を繰り返すやり方です。

「スクショ取る」「今のページをhtmlに落として保存する」は頻繁にやるのでこれ用に関数書いた:

docker上で動くRStudioでちくちくインタラクティブに作っていきました。

devcode.R
# 開発・デバッグ用
remss <- function(){
  remDr$screenshot(display=TRUE)
}
remhtml <- function(){
  filename <- paste0("page_", today(), ".html")
  write(unlist(remDr$getPageSource()), paste0("debug_", ymd_hms(now(tz="Asia/Tokyo")), ".html")) 
}

中身は、殆どが下記の繰り返しです
・remDr$findElement  で要素拾う (xpathで指定)
・webElem$sendKeysToElement  で必要であれば要素代入
・webElem$clickElement()  クリックイベントを送信

実際の所を御覧下さい:ログイン作業

sitefunctions.R
# 某サイトにログインする関数
sitelogin <- function(){
  # ログイン画面
  url <- "https://www.hoge.hoge/zzh/"
  remDr$navigate(url)

  ## Login - Page 1 
  # userid
  webElem <- remDr$findElement(using="xpath", value = '//*[@id="searchBlock"]/div/div/div/div[1]/ul/li[1]/label/input')
  webElem$sendKeysToElement(list("XXXUSERIDXXX"))
  # password
  webElem <- remDr$findElement(using="xpath", value = '//*[@id="searchBlock"]/div/div/div/div[1]/ul/li[2]/label/input')
  webElem$sendKeysToElement(list("XXXPASSWORDXXX"))
  # panel - fakepassword - 偽装パラメタを入れないとログイン蹴られる仕様
  webElem <- remDr$findElement(using="xpath", value = '//*[@id="contentBody"]/form/input[1]')
  webElem$sendKeysToElement(list("XXXX"))
  # action
  webElem <- remDr$findElement(using="xpath", value = '//*[@id="contentBody"]/form/input[2]')
  webElem$sendKeysToElement(list("login"))

  # Click login
  webElem <- remDr$findElement(using="xpath", value = '//*[@id="searchBlock"]/div/div/div/div[2]/div/span')
  webElem$clickElement()

  message("STATUS - Login success.")
  return(TRUE)
}

こんな感じです。
(実際にはエラーハンドリング等をもう少し手厚く書いています)

上記が動いたら、必要な商品IDなどを入れて狙ったデータを表示させられると思います。

必要な情報が表示されたら、そのページのhtmlをRvestでパース

はじめとっつきが悪いかもなんですが、基本こんな感じにtidyなパイプでどんどん処理できます。
殆どはhtml_table()とhtml_text()で取得出来ると思います。

parsesales.R
  sales <- read_html(remDr$getPageSource()[[1]]) %>%
    html_node(xpath = '//*[@id="salesTrend"]/div[2]/table') %>%
    html_table(fill = TRUE)
  colnames(sales) <- c("stockdate","v_sold","v_souhin","v_soldcum","dummy","v_henpin","v_henpinratio")
  sales %<>% select(-dummy) # remove junk col
  sales %<>% mutate_at(c("v_sold", "v_souhin", "v_soldcum"), as_integer)

  status_check <- read_html(remDr$getPageSource()[[1]]) %>% 
    html_node(xpath = '//*[@id="errorMsg"]/span') %>% 
    html_text

saveRDS(sales, "todaysdata.RDS")

あんがい簡単です。
取得時にfactorにしたり色々出来るので、.CSVにしてアホみたいに容量が膨らむ事も防げます。後処理に回しやすい。

すごいぞ便利だRvest

「スクレーピングとか、データサイエンスと離れた所は誰かにやって欲しい...」と感じる方も多いかと思うんですが、
Rvest + RSeleniumだと本当に簡単に自動化出来るんで、いっそ自分で書いちゃうのもありだと思って頂けたら幸いです。
取得データを、そのままRで触りやすい形で保存できるので便利ですよ〜

(取得は適切にsys.sleep()を挟むなどして、相手サイトさんの負担が多すぎないように実行しましょうね)

続きは本家サイトをチェックや

2
3
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
3