以前、こんな記事を書いた。
しかし最近は Twitter アカウントなどで OAuth を使ってログインできるサイトが増えてきた。
私も Qiita は Twitter ID を紐づけて OAuth でログインしている。
rvest を使って OAuth 認証するのは、上記記事のやり方にひと手間加える必要があるので、ここで紹介しよう。
Qiita に Twitter ID でログイン
例として、Qiita に Twitter ID でログインしてみる。
library(rvest)
# Qiita の Twitter 用認証ページ
login_page <- html_session("https://qiita.com/auth/twitter")
# 認証ページのログインフォームにアカウント名とパスワードを入れる
login_form <- html_form(login_page)[[1]] %>%
set_values(`session[username_or_email]`="hoxo_m", `session[password]`="****")
# Submit するとリダイレクトページが表示される
redirect_page <- submit_form(login_page, login_form)
まず、Qiita の Twitter 認証ページにアクセスする。
すると、Twitter 側の認証ページへリダイレクトされるので、そこでログインフォームにアカウント名とパスワードを入力する。
これを Submit すると、今度は Qiita 側へ認証情報を返すためにリダイレクトしようとするのだが、rvest では自動的に遷移しない。
したがって、この redirect_page
ページから、認証情報を返すためのリンクを探してそのリンクをたどらなければならない。
redirect_page %>% html_node(xpath='//body')
(省略)
<div id="bd" role="main">
<div class="happy notice callback">
<h2>アプリケーションに戻ります。しばらくお待ちください。</h2>
<p>自動的に移動しない場合は<a class="maintain-context" href="https://qiita.com/auth/twitter/callback?oauth_token=***&oauth_verifier=***">こちら</a>をクリックしてください</p>
</div>
</div>
(省略)
この「自動的に移動しない場合はこちらをクリックしてください」というのが認証情報を返すためのリンクである。
このリンクを rvest でたどるには、次のようにする。
session <- redirect_page %>%
follow_link(xpath = '//*[@id="bd"]/div/p/a')
以上で、Qiita に Twitter ID でログインしたセッションを作成することができた。
あとは通常どおり、ログインした状態でスクレイピングできる。
session %>%
jump_to("http://qiita.com") %>%
html_nodes(xpath='//div[@class="userInfo"]/div/div') %>%
html_text
[1] "hoxo_m" "753Contribution"
hoxo_m アカウントでログインできていることが確認できた。
Qiita の通知情報をスクレイピング
ここからは完全に余談で、Qiita の通知一覧のページから、通知情報をスクレイピングしてみる。
library(lambdaR)
library(pforeach)
npforeach(i=1:99, .c=rbind)({
url <- sprintf("http://qiita.com/notifications?page=%d", i)
message(url)
nodes <- session %>%
jump_to(url) %>%
html_nodes(xpath = '//div[@class="notification_actionWrapper"]')
Sys.sleep(1)
nodes %>%
Map_(node: {
action <- tryCatch({
node %>% html_node(xpath='span[@class="action"]') %>% html_text
}, error = f_(e: {
# action が「編集」「投稿」の場合
node %>% html_node(xpath='*/span[@class="action"]') %>% html_text
}))
if(action == "ツイート") {
who <- ""
} else {
who <- node %>% html_node(xpath='span[@class="notification_user"]') %>% html_text
}
if(action %in% c("フォロー", "ツイート", "Thank!")) {
url <- ""
} else if(action %in% c("編集", "投稿")) {
url <- node %>% html_node(xpath='a') %>% html_attr("href")
} else {
url <- node %>% html_node(xpath='span[@class="action"]/a') %>% html_attr("href")
}
if(action == "フォロー") {
title <- "あなた"
} else if(action == "採用") {
title <- "編集リクエスト"
} else if(action == "Thank!") {
title <- "あなたのコメント"
} else {
title <- node %>% html_node(xpath='span[@class="title"]') %>% html_text
}
data.frame(who, action, title, url, stringsAsFactors = FALSE)
}) %>%
Reduce_(rbind)
}) -> result
knitr::kable(head(result))
who | action | title | url |
---|---|---|---|
kisy | ストック | "rvest すげえ。#rstatsj" | http://qiita.com/hoxo_m/items/264b45684fcb657cf285 |
garam | ストック | "read.table() でヘッダ..." | http://qiita.com/hoxo_m/items/b77f1566d3a848e46c92 |
uri | 編集 | "【gifアニメつき】テキストエディ..." | http://qiita.com/uri/items/a4a6e9abdbe9a913d657/revisions |
uri | 編集 | "【gifアニメつき】テキストエディ..." | http://qiita.com/uri/items/a4a6e9abdbe9a913d657/revisions |
dichika | メンション | "readr::parse_date..." | http://qiita.com/dichika/items/4255bc4b5949c9b367f1 |
ddintokyo | ストック | "RStudio Shiny チュー..." | http://qiita.com/hoxo_m/items/c8365117f3444fb51df4 |
このデータから、ストック情報だけを取り出して、自分の記事をよくストックするユーザを見つけてみよう。
library(dplyr)
stock_ranking <- result %>%
filter(action == "ストック") %>%
count(who) %>%
arrange(desc(n))
knitr::kable(head(stock_ranking, 20))
who | n |
---|---|
HirofumiYashima | 47 |
uri | 39 |
Reds | 32 |
ytakky | 26 |
kasumani | 19 |
cof | 17 |
horihorio | 16 |
P_tan | 12 |
soogie | 11 |
hiro_matsuno2 | 10 |
kaz-yos | 10 |
st450 | 10 |
tktz | 10 |
ginmaru | 8 |
selious | 8 |
wakuteka | 8 |
R_beginner | 7 |
hayashiyus | 7 |
heliac2000 | 7 |
ksomemo | 6 |
ここは @uri さんが一位であってほしかった。
Enjoy!