ついけしを知らせるBot作ってみた
目次
- 本文の前に
- Botの説明
- コードと説明(各自Session有り)
- まとめ
本文の前に
この記事はTwitterAPIに触れたことはないけど他のAPIなら触ったことあるお!ってぐらいのレベルの人向けですので、あしからず
Twitterって便利ですよね。リアルタイムに皆が思ってることを投げまくって、TLにリスト表示してくれて。
けどその反面、炎上とか炎上とか自宅特定とか、あることないこととか、色々投稿されてて割りと怖い
(いつ炎上するか割と怯えてる)
そんで、Twitterには削除機能というものがある。編集機能も早くつけて欲しいが、削除はある。
削除があるってことは、自分がフォローしてるフォロワーさんの投稿を見逃す可能性があるということだ、これは悲しいと言うか
悔しい気持ちになる(知らぬが仏)後で、有名な人のツイ消しが話題になったりして、見逃した日には、夜も寝れないことだろう
なので、つい消しされたらSlackに消された文章と一緒に通知してくれる、迷惑なBotを作ってみた。
Botの説明
TwitterにはAPIがある。まあどこのサービスにもAPIはあるのだが、TwitterにはTweetが消された場合にアクションを起こす物がある。
今回はそれを使って、つい消しを判定することにした。だが!そのTwitterから送られてくるDeleteActionに
メッセージ(本文)などは付いておらす、前世の記憶はTwieetIDしかしらないらしい。ので!普通のStreamingActionが送られてきた時には、以下の写真のように、色々なデータが入ってくる。これを受信するたびにDBに保存して、削除された時に呼び出してこよう!って魂胆である。
サービスのモデルに関してはこんな感じ
BotはTwitterAPIと常に対話させておき、データが飛んできたらSinatraAPI(自作API)にJSONでデータを飛ばして、DBにSinatraAPIが保存させるといった感じで、それそれの機能ごとに分割してます。
コードの説明
コードの全文はGitHubこちらら(変更しまくってるので、応用編的なのりで見てください)
そんでもって、まずはBotの作り方、コードはRubyで書いていきます。
RubyにはTwitter gemというTwitter非公式のTwitter専用のgemがあるので、それを使うと簡単に実装ができます。
ではまず適当に、Botとかいうフォルダーを作りましょう
$ mkdir TweetDeletedAlertBot
Gem(ライブラリ)のインストール
GemをインストールするのにGemfileを作成してその中に必要なGemを入れましょう($ bundle init で簡単に作成できます)
bundlerをインストールしてない方はまず[gem install bundler]でbundlerをインストールしてください
gem 'twitter'
gem 'rake'
gem 'sinatra'
gem 'sinatra-activerecord'
gem 'curb'
gem 'sqlite3'
次に$ bundle install --path vondor/をしてgemをインストールします。これでgemのインストールは完了です!
DataBaseの作成
ではでは、次にDBを作成するために'config.ru','database.yml','models.rb’,’Rakefile’ を作成していきます
cnfig.ru
requie 'bundler'
Bundler.require
require './app'
run Sinatra::Application
database.yml
development:
adapter: sqlite3
database: db/development.db
pool: 20
timeout: 5000
models.rb
require 'bundler/setup'
Bundler.require
after do
ActiveRecord::Base.connection.close
end
if development?
ActiveRecord::Base.establish_connection("sqlite3:db/development.db")
end
class Tweet < ActiveRecord::Base
end
Rakefile
require 'sinatra/activerecord'
require 'sinatra/activerecord/rake'
namespace :db do
task :load_config do
require File.expand_path('../app', __FILE__)
end
end
これでDBの下準備は整いました!
次は、テーブルの作成をしていきましょう!!
$ bundle exec rake db:create_migration NAME=create_tweets
とやって、migrationファイルを作成します。
vimやらなんやらで、db/migrate/*************create_tweets.rb みたいのを開きましょう
そしたら、つい消しされた時に見たい内容を入れるためのcolumnをを追加していきましょう
ちなみに僕は、UserNameとTextとUserID(必須)だけの簡単な仕様にしてみました。もし他にも入れたいものがあったら各自設定してください
class CreateTweets < ActiveRecord::Migration
def change
create_table :tweets do |t|
t.string :tweet_id #こいつは必須
t.string :user_name
t.string :icon_url
t.text :text
end
end
end
では、いよいよ、DB作成編も終了間近です。最後に
$ bundle exec rake:db migrate
とやって、DBの完成です!
次に作るのはDataBaseさんと対話してくれるSinatraAPIを作成していきます
SinatraAPI
まずは
$ touch app.rb
で、app.rbというファイルを作成してください
そしたらまず、ライブラリ(gem)を読み込みます。
require 'bundler/setup'
Bundler.require
require './models.rb'
require 'json'
を記述したら、Bot.rbからTweetデータを受け取り保存するコードを書いていきます
post '/stocking_tweet', provides: :json do
data = JSON.parse(request.body.read)
Tweet.create(
tweet_id: data["tweet_id"],
user_name: data["user_name"],
text: data["text"],
icon: data["icon"],
url: data["url"]
)
end
これで、TweetData をjsonで受け取るコードはできました
次に作るのは、DeleteActionが来た時にBotは、「このTweetIDと一致するデータって持ってる?」
と聞いてくるので、それを受信して、返信する、コードを書いていきます
get '/find_tweet/:id' do
if tweet = Tweet.find_by(tweet_id: params[:id])
{ tweet_id: tweet.tweet_id, user_name: tweet.user_name, text: tweet.text , icon: tweet.icon, url: tweet.url}.to_json
else
{error: "404"}.to_json
end
end
end
Bot(本体)の作成
いよいよ、本番!Botの作成です!!!!まずはさっきと同じく
$ touch bot.rb
でBot.rbのファイルを作成してください
まずインストールしたライブラリ(gem)をインポートします
require 'twitter'
require 'curb'
次に、Twitter API の設定をしていきます。
Twitter API を使うには TwitterDeveloper 登録をして AccessKey を取得してください
ここから取得してきてください-> Application Management
#bot.rbに記述
client = Twitter::Streaming::Client.new do |config|
config.consumer_key = QCxSr1Fq6We9C8xhIx5agkTOs
config.consumer_secret = V6mAznyD2mdTxCoYYkQvkDbsdAz1au52KTojS1SwZ9yrkba3T3
config.access_token = 1793252213-6L9Vda4qXYzrgg2vDlcJ7MWZqhCZHpim5ZayDa1
config.access_token_secret = FifsbD45igXiLLw7698ykNLD1h4hmyGd374RS9jYDmx75
end
Configの設定が終わったら次は削除された時のActionを取得してきます
#bot.rbに記述↓
client.user do |tweet|
case tweet #なんのアクションが起きてるかのcase文
when Twitter::Tweet #普通のTweetだった場合
puts "#{tweet.user.name} -> #{tweet.full_text}\n\n" #テストコード
database_post(tweet) #DataBase に保存するために database_post という関数にデータを投げる
when Twitter::Streaming::DeletedTweet #削除アクションだった場合
data = JSON.parse(Curl.get("http://localhost:4567/find_tweet/#{tweet.id}").body_str)
if "#{tweet.id}" == data["tweet_id"]# SinatraAPIから撮ってきたデータが有ってるかどうか
deleted_tweet(data) #あっていた場合削除通知をSlackにPostするためのDeleted_tweetという関数に投げる
else
puts ("誰かがつい消ししたっぽい")#もし削除されたものがDataBaseに保存されてなかったらLogとして残す
end
end
end
ここまでで一応動くようにはなってます(嘘)関数を幾つか呼び出しているので、関数の定義してあげましょう
def database_post(bot.rb)
#これはSinatraAPIに流し込む
def database_post(tweet)
Curl.post(
"http://localhost:4567/stocking_tweet",
({
tweet_id: tweet.id,
user_name: tweet.user.name,
text: tweet.full_text,
url:tweet.uri,
icon: tweet.user.profile_image_url,
}).to_json)
end
def database_postでは、SinatraAPI にTweetのデータを投げるためのcurlを定義してます
次に、DeleteActionが起こった時の関数を定義していきます
def deleted_tweet(bot.rb)
#これはslackに直接流しこむ
def deleted_tweet(tweet)
web_hooks = "https://hooks.slack.com/services/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"
#↑こいつはSlackのWebHooksってやつで、これの取得方法はSlack Incoming WebHooks でぐぐってくれ
attachments = { attachments: [{
author_icon: tweet["icon"],
author_name: tweet["user_name"],
text: "Delete:\n #{tweet["text"]}",
author_link: tweet["url"],
color: "red",
}]
})
conf = { channel: "#random", username: "TwitterBot", icon_url: "http://goo.gl/5sotqB"}.merge(attachments)
Curl.post( web_hooks,JSON.pretty_generate(conf))
end
これですべての準備が整いました!ではapp.rbとbot.rbの両方を一気に実行してみましょう!
できましたかね?これで取り敢えずコードの説明は、終了です
まとめ
実際ヤッてみてどうでした?疲れました?でも記事書いてる僕はもう90代のおっさんみたいな格好して記事書いてます
最後、コードの全文見て終わりにしますかね
app.rb
require 'bundler/setup'
Bundler.require
require './models.rb'
require 'json'
post '/stocking_tweet', provides: :json do
data = JSON.parse(request.body.read)
Tweet.create(
tweet_id: data["tweet_id"],
user_name: data["user_name"],
text: data["text"],
icon: data["icon"],
url: data["url"]
)
end
get '/find_tweet/:id' do
if tweet = Tweet.find_by(tweet_id: params[:id])
{ tweet_id: tweet.tweet_id, user_name: tweet.user_name, text: tweet.text , icon: tweet.icon, url: tweet.url}.to_json
else
{error: "404"}.to_json
end
end
end
bot.rb
require 'twitter'
require 'curb'
client = Twitter::Streaming::Client.new do |config|
config.consumer_key = QCxSr1Fq6We9C8xhIx5agkTOs
config.consumer_secret = V6mAznyD2mdTxCoYYkQvkDbsdAz1au52KTojS1SwZ9yrkba3T3
config.access_token = 1793252213-6L9Vda4qXYzrgg2vDlcJ7MWZqhCZHpim5ZayDa1
config.access_token_secret = FifsbD45igXiLLw7698ykNLD1h4hmyGd374RS9jYDmx75
end
def deleted_tweet(tweet)
web_hooks = "https://hooks.slack.com/services/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"
#↑こいつはSlackのWebHooksってやつで、これの取得方法はSlack Incoming WebHooks でぐぐってくれ
attachments = { attachments: [{
author_icon: tweet["icon"],
author_name: tweet["user_name"],
text: "Delete:\n #{tweet["text"]}",
author_link: tweet["url"],
color: "red",
}]
})
conf = { channel: "#random", username: "TwitterBot", icon_url: "http://goo.gl/5sotqB"}.merge(attachments)
Curl.post( web_hooks,JSON.pretty_generate(conf))
end
def database_post(tweet)
Curl.post(
"http://localhost:4567/stocking_tweet",
({
tweet_id: tweet.id,
user_name: tweet.user.name,
text: tweet.full_text,
url:tweet.uri,
icon: tweet.user.profile_image_url,
}).to_json)
end
client.user do |tweet|
case tweet #なんのアクションが起きてるかのcase文
when Twitter::Tweet #普通のTweetだった場合
puts "#{tweet.user.name} -> #{tweet.full_text}\n\n" #テストコード
database_post(tweet) #DataBase に保存するために database_post という関数にデータを投げる
when Twitter::Streaming::DeletedTweet #削除アクションだった場合
data = JSON.parse(Curl.get("http://localhost:4567/find_tweet/#{tweet.id}").body_str)
if "#{tweet.id}" == data["tweet_id"]# SinatraAPIから撮ってきたデータが有ってるかどうか
deleted_tweet(data) #あっていた場合削除通知をSlackにPostするためのDeleted_tweetという関数に投げる
else
puts ("誰かがつい消ししたっぽい")#もし削除されたものがDataBaseに保存されてなかったらLogとして残す
end
end
end
~雑談~
TwitterAPIのDeleteActionも不親切だよなあーIDだけしか渡してこないから、こっちでDB作らなきゃいけなくなったし、
そのせいでconfigfileとか作るから、ファイルが増えるし管理めんどいしで、なんかもう。。。メンドーッて感じっだった
まあActiveRecordとSinatraがあるから楽に実装出来たっちゃできたから◎
ではではーおつかれさまですー