【R/Shiny】「ツイート収集webアプリ」を作る2 ~timeline収集機能追加~
こちらの続きです。
●やること
本記事では過去記事で作ったツイートを収集するwebアプリに特定のアカウントのツイートを収集する機能を追加します。
For English speakers.
In this article, I'm going to add a function to collect tweets from a specified account to the web app that collects tweets created in the previous article.
The program code is in English only, but the text is in Japanese, so please use a translation site to read it.
If you want to contact me, you can DM me on Twitter in English.
●前書き
こんなのを作ります。
前回記事で作成した部分に加えて、get_timelineタブを作り、指定されたアカウントの3200ツイートを収集できる機能を追加します。
自分のツイートでどんなツイートが人気があったのか?
競合はどんなツイートをしているのか?ウォッチング対象の過去ツイート保存やツイートを消していないか監視に便利です。
ストーキングもちろん検索された側にはインプレッションが1増える以外にバレないのでやりたい放題。
●作り方
基本的な作り方は前回記事をご参考ください。
すでに前回記事で基本形ができているのならば、今回やることはRstudioでコードを書き換えるだけです。
コードを以下のように書き換えます。全コードですのでこのままRstudioのapp.Rに貼り付けてください。
過去記事と同様、 app = "YOUR APP NAME"のところはTwitter API keyで設定したアプリの名前に書き換えてください。
# tweet_collection
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
# cache clear
rm(list=ls())
gc(); gc();
library("shiny")
library("shinymanager")
library("shinythemes")
library("shinybusy")
library("rtweet")
library("tidyverse")
library("DT")
library("lubridate")
library("jsonlite")
# set credentials
credentials <- data.frame(
user = c("shiny123", "user1234"), #
password = c("azerty123", "pass1234"), #
start = c("2019-04-15"), # optinal (all others)
expire = c(NA, NA),
admin = c(TRUE, TRUE),
comment = "",
stringsAsFactors = FALSE
)
# read API key from json
keys <- read_json("config.json", simplifyVector = TRUE)
twitter_token <- create_token(
app = "YOUR APP NAME", # ← Enter your app name
consumer_key = keys$consumer_key,
consumer_secret = keys$consumer_secret,
access_token = keys$access_token,
access_secret = keys$access_secret
)
# Define UI for app
ui <- navbarPage(
theme = shinytheme("spacelab"),
# Application title
br(),
tabPanel(
title = "search_tweets",
h2("Search tweets"),
"You can only download a total of ",
span("18,000 tweets per 15 minutes and tweets within the last seven days. ", style = "color:blue"),
"If it does not work, please try again later.",
# Sidebar
sidebarLayout(
sidebarPanel(
width = 2,
numericInput("num_tweets_to_download",
label = "Number of tweets to download",
min = 100,
max = 18000,
value = 100,
step = 100
),
textInput("word_to_search",
label = "word to search",
value = "#cat"
),
actionButton("get_data", "Get data", class = "btn-primary"),
br(), br(),
"Download",
br(),
downloadButton("download_data", ".csv")
),
# Show results
mainPanel(
width = 10,
DT::dataTableOutput("tweet_table")
)
)
),
tabPanel(
title = "get_timeline",
h2("Get user timeline"),
"You can get ",
span("3,200 tweets from a user's timeline. Up to 18,000 per hour. ", style = "color:blue"),
"If it does not work, please try again later.",
# Sidebar
sidebarLayout(
sidebarPanel(
width = 2,
numericInput("num_tweets_to_download2",
label = "Number of tweets to download",
min = 100,
max = 3200,
value = 100,
step = 100
),
textInput("user_name",
label = "user ID to search",
value = "@DLsite"
),
actionButton("get_data2", "Get data", class = "btn-primary"),
br(), br(),
"Download",
br(),
downloadButton("download_data2", ".csv")
),
# Show user timeline results
mainPanel(
width = 10,
DT::dataTableOutput("ut_table")
)
)
)
)
# Wrap your UI with secure_app
ui <- secure_app(ui)
# Define server logic
server <- function(input, output, session) {
# check_credentials returns a function to authenticate users
res_auth <- secure_server(
check_credentials = check_credentials(credentials)
)
# tweet collection
tweet_df <- eventReactive(
input$get_data,
{
show_modal_spinner()
x <- search_tweets(input$word_to_search, n = input$num_tweets_to_download, include_rts = FALSE)
x
}
)
# tweet_data cleansing
tweet_table_data <- reactive({
req(tweet_df())
x2 <- tweet_df() %>%
mutate(created_at = ymd_hms(created_at) + 32400) %>% # UST to JST
select(
created_at,
screen_name, text, favorite_count, retweet_count,
status_url, description, followers_count, friends_count,
source
)
x2 <- x2 %>% mutate(
url = status_url,
status_url = paste0("<a href='", x2$status_url, "'>", x2$status_url, "</a>")
)
remove_modal_spinner()
x2
})
# output
output$tweet_table <- DT::renderDataTable(
tweet_table_data() %>%
select(-url),
escape = FALSE,
options = list(
lengthMenu = c(10, 30, 100),
autoWidth = TRUE,
pageLength = 30,
scrollY = "800px",
scrollX = TRUE,
scrollCollapse = TRUE
)
)
# download button server logic
output$download_data <- downloadHandler(
filename = function() {
paste(Sys.Date(), input$word_to_search, "_", ".csv", sep = "")
},
content = function(file) {
rtweet::write_as_csv(tweet_table_data() %>%
select(-status_url),
file,
na = "NA", fileEncoding = "CP932"
)
}
)
# user timeline collection
ut_df <- eventReactive(
input$get_data2,
{
show_modal_spinner()
x <- rtweet::get_timeline(input$user_name, n = input$num_tweets_to_download2)
x
}
)
# user_timeline cleansing
ut_table_data <- reactive({
req(ut_df())
x3 <- ut_df() %>%
mutate(created_at = ymd_hms(created_at) + 32400) %>% # UST to JST
select(
created_at,
screen_name, text, favorite_count, retweet_count,
status_url, followers_count, friends_count,
source
)
x3 <- x3 %>% mutate(
url = status_url,
status_url = paste0("<a href='", x3$status_url, "'>", x3$status_url, "</a>")
)
remove_modal_spinner()
x3
})
# output user timeline
output$ut_table <- DT::renderDataTable(
ut_table_data() %>%
select(-url),
escape = FALSE,
options = list(
lengthMenu = c(10, 30, 100),
autoWidth = TRUE,
pageLength = 30,
scrollY = "800px",
scrollX = TRUE,
scrollCollapse = TRUE
)
)
# download button server logic
output$download_data2 <- downloadHandler(
filename = function() {
paste(Sys.Date(), input$user_name, "_", ".csv", sep = "")
},
content = function(file) {
rtweet::write_as_csv(ut_table_data() %>%
select(-status_url),
file,
na = "NA", fileEncoding = "CP932"
)
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
# shinyapps
# tmp.enc <- options()$encoding
# options(encoding = "UTF-8")
# library(rsconnect)
# rsconnect::deployApp()
# options(encoding = tmp.enc)
上の様にコードを書き換え、前回記事と同じようにRun Appから起動、またはshinyappsにdeployしてやればOKです。
●主な変更点
・UI部分
# Define UI for app
ui <- navbarPage(
theme = shinytheme("spacelab"),
# Application title
br(),
tabPanel(
title = "search_tweets",
h2("Search tweets"),
...(中略)...
tabPanel(
title = "get_timeline",
h2("Get user timeline"),
...
前回の記事ではui <- fluidPage( theme = …としていたところを、navbarPageとtabPanelを利用してツイート検索機能とユーザーツイート収集機能をタブで切り替えられるようにしました。
これにより
ここの部分で機能を切り替えられるようになっています。
またUI部分ではアカウントのツイート を収集するget_timeline部分で、search_tweetと同様に以下を追加しています。
tabPanel(
title = "get_timeline",
h2("Get user timeline"),
"You can get ",
span("3,200 tweets from a user's timeline. Up to 18,000 per hour. ", style = "color:blue"),
"If it does not work, please try again later.",
# Sidebar
sidebarLayout(
sidebarPanel(
width = 2,
numericInput("num_tweets_to_download2",
label = "Number of tweets to download",
min = 100,
max = 3200,
value = 100,
step = 100
),
textInput("user_name",
label = "user ID to search",
value = "@DLsite"
),
actionButton("get_data2", "Get data", class = "btn-primary"),
br(), br(),
"Download",
br(),
downloadButton("download_data2", ".csv")
),
# Show user timeline results
mainPanel(
width = 10,
DT::dataTableOutput("ut_table")
)
)
)
基本的な構成は全くsearch_tweetと一緒ですが、rtweetのget_timeline関数の最大取得数は3200ですのでnumericInputのmaxを3200にしています。
検索ワードのtextInputはTwitter IDの@を含むID(screen_name)を引数とするので、その旨も表示してやります。
・server部分
以下を追加してやります。
# user timeline collection
ut_df <- eventReactive(
input$get_data2,
{
show_modal_spinner()
x <- rtweet::get_timeline(input$user_name, n = input$num_tweets_to_download2)
x
}
)
# user_timeline cleansing
ut_table_data <- reactive({
req(ut_df())
x3 <- ut_df() %>%
mutate(created_at = ymd_hms(created_at) + 32400) %>% # UST to JST
select(
created_at,
screen_name, text, favorite_count, retweet_count,
status_url, followers_count, friends_count,
source
)
x3 <- x3 %>% mutate(
url = status_url,
status_url = paste0("<a href='", x3$status_url, "'>", x3$status_url, "</a>")
)
remove_modal_spinner()
x3
})
# output user timeline
output$ut_table <- DT::renderDataTable(
ut_table_data() %>%
select(-url),
escape = FALSE,
options = list(
lengthMenu = c(10, 30, 100),
autoWidth = TRUE,
pageLength = 30,
scrollY = "800px",
scrollX = TRUE,
scrollCollapse = TRUE
)
)
# download button server logic
output$download_data2 <- downloadHandler(
filename = function() {
paste(Sys.Date(), input$user_name, "_", ".csv", sep = "")
},
content = function(file) {
rtweet::write_as_csv(ut_table_data() %>%
select(-status_url),
file,
na = "NA", fileEncoding = "CP932"
)
}
)
こちらも前回のsearch_tweetとほぼ中身は一緒。
関数としてユーザーのタイムラインを収集するrtweet::get_timelineを入れてやっただけです。
各場所の引数はui側で新たに設定したオブジェクトを使う様に設定してやります。
●できあがり
特定のユーザーの3200ツイートを収集できます。
こちらはsearch_tweetと違って最新7日間の制限はなく、3200ツイートきっちり遡って取得することができます。
このため、自分または特定のアカウントについてツイートを取得し、
・RT数降順にソートしてどんなツイートが人気があったかを分析
・どんな話題やタグが多いのかを分析
・sourceを見てどんな端末を使っているかを分析
・いつくらいにツイートしているのかを分析
・過去に過去3200ツイートをログのように保存
・Twitterの検索ではなかなか出てこないツイートを検索
というような監視またはストーキングことに使用することができます。
●終わりに
今回はrtweetパッケージのget_timeline関数の機能を追加してみました。
このようにrtweetの関数であれば簡単に機能を追加することが可能です。
このため、アカウントのフォローを取得するget_followers、フォロワーを取得するget_friends、ツイート頻度を取得するts_plot、複数のアカウント間の交流データを取得するlookup_friendships…などなど、rtweetにはたくさんの関数があります。
これら関数、またその他パッケージと組み合わせればかなり高度なTwitter分析アプリケーションを自作することも可能です。
興味があればCRANの説明書をご覧ください。
本記事について分からない点、何かお気づきの点がございましたらTwitterのDMまでご連絡ください。
何かリクエストがあれば作ったり対応するかもしれません。
以上です。
ありがとうございました。