第1章 「TwitterのBotを作ってみる」 by object_1037 (73)

1.1 自己紹介と説明

皆さんこんにちは、73回生(中3)のobject_1037です。部誌を書くのは初めてなのですが、温かい目で見守って頂けると幸いです。

ぼくは今年の文化祭の部誌でTwitterのBotの作り方について書きました。Botは結構簡単に作れると聞いたので当時暇だった僕はBotを作ろうと決めたのですが、これが結構難しく、部誌に書こうと決めたわけです。(能力が低い)

1.2 Botについて

突然ですが皆さんTwitter使ってますか?Twitterを使ったことがある人ならわかると思いますが、TwitterにはBotと呼ばれるアカウントが数多く存在します。

Botとは

Botってなんやねんと思うかもしれませんが、

Bot(ボット)は、robot(ロボット)の短縮形・略称で、転じてコンピュータやインターネット関連の自動化プログラムの一種のこと。(Wikipediaより)

とのことです。要は普通のアカウントと違ってプログラムで動いているアカウントのことをBotとよぶわけです。

Botの種類

Botと一概に言ってもたくさん種類があるのですが、ざっと分けると

  • 決められた言葉の中からつぶやくもの。名言Botとかは大体これ。
  • フォロワーからのリプなどに反応してつぶやくもの。占う系のBotとか。
  • 天気予報Botなど、どこかのサイトから情報を持ってきてつぶやくもの。

このぐらいに分けられます。

僕は今回決められた時間につぶやく時報Botと単語をつぶやくBot,天気予報Botを作りました。

時報Bot

図1.1: 時報Bot

単語をつぶやくBot

図1.2: 単語をつぶやくBot

天気予報Bot

図1.3: 天気予報Bot

1.3 Botの作成

それでは実際にBotを作っていきます。前提環境は

  • OS: Windows 10 Home
  • Ruby: 2.2.6
  • gem: twitter 6.1.0, json 2.0.3, 1.8.1

です。異なるバージョンを使用している場合には一部操作が違う場合があるので注意してください。

作成手順

作成手順は大きく分けて

  1. 環境構築
  2. Twitterの設定
  3. プログラミング
  4. 運用

です。それでは作っていきましょう。

環境構築

まず、今回はRubyを使ってBotを作ったのでRubyのインストールが必要です。Rubyはhttps://rubyinstaller.org/downloads/からダウンロードできるのでダウンロード、インストールしておきましょう。*1

[*1] Rubyのバージョンは特にこだわりがない限り最新、または一つ前のバージョンがおすすめです。少なくとも2.0.0以降のものをインストールするようにしましょう。

次にDevKitをインストールします。DevKitはWindows環境でネイティブなC/C++拡張をビルドするためのツールキットです。gemのインストール時に必要になるので、https://rubyinstaller.org/downloads/からさきほどインストールしたRubyのバージョンに対応したDevKitをダウンロードするようにしましょう。そこでインストール時にこんな画面が出てくるはずです。

DevKitのインストール

図1.4: DevKitのインストール

このまま展開するとDownloadsフォルダに中身がバラけてしまうので、あらかじめDevKitのフォルダを作っておいてそこに展開するようにしましょう。

つぎにDevKitの初期設定を行います。コマンドライン(コマンドプロンプト等)を開いてさっきDevKitをインストールしたフォルダに移動してから、

$ ruby dk.rb init

と打ち込んでください。つぎにエディターでさっき展開した中にあるconfig.ymlというファイルを開きます。するとこんな感じになっているはずです。

リスト1.1: config.yml

# This configuration file contains the absolute path locations of all
# installed Rubies to be enhanced to work with the DevKit. This config
# file is generated by the 'ruby dk.rb init' step and may be modified
# before running the 'ruby dk.rb install' step. To include any installed
# Rubies that were not automagically discovered, simply add a line below
# the triple hyphens with the absolute path to the Ruby root directory.
#
# Example:
#
# ---
# - C:/ruby19trunk
# - C:/ruby192dev
#
---
- C:\Ruby22-x64

ここで一番下の行にあるパスをRubyをインストールしたフォルダのものに書き換えてください。(C:\Ruby等)

次にもう一度コマンドプロンプトを開いて

$ ruby dk.rb install

と打ちます。エラーが出なければDevKitの設定は完了です。

次はgemをインストールします。コマンドプロンプトを開いて

$ gem i twitter json

と打ちます。エラーが出なければ環境構築は完了です。

Twitterの設定

次にTwitter側の設定をしていきます。まず当然ですがBotを作るにはBotにするためのアカウントが必要なのでアカウントを作ります。

次にそのアカウントでログインしたままhttps://apps.twitter.com/にアクセスして、【Create New App】で新規アプリケーションを作ります。色々聞かれるので適当に埋めましょう。

ちなみに【Name】に入れた名前はTweetDeck等の他社製クライアントで開くときに【Name】から投稿された、と出ます。なので恥ずかしい名前にしないようにしましょう。(ブーメラン)

こんなかんじ

図1.5: こんなかんじ

また、すでに登録してある名前をつけることはできません。今回私は「JAPARIPARK」という名前をつけようとしたのですが、あいにくすでに登録してあったようで、後ろに半角スペースをつけ、「JAPARIPARK 」とすることで解決しました。

また、この名前(ここではJAPARIPARK )をクリックすると【Website】にいれたサイトに飛びます。

アプリを作ったら、【Keys and Access Tokens】タブから【Create My Access Token】というところを押して、表示されるConsumer Key、Consumer Secret、Access Token、Access Token Secretをそれぞれメモ帳にでもコピペしておきましょう。これでTwitterの設定は完了です。

プログラミング

今回のメインはここです。プログラミングと聞くと難しそうですが、結構かんたんです。

Hello,World!

早速定番の「Hello,World!」とつぶやくプログラムを作ってみましょう。

リスト1.2: hello.rb

  require 'twitter'

  client = Twitter::REST::Client.new(
    consumer_key:        "YOUR_CONSUMER_KEY",
    consumer_secret:     "YOUR_CONSUMER_SECRET",
    access_token:        "YOUR_ACCESS_TOKEN",
    access_token_secret: "YOUR_ACCESS_TOKEN_SECRET",
  )
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

  client.update "Hello,World!"

(プログラム内にあるYOUR_CONSUMER_KEY、YOUR_CONSUMER_SECRET、YOUR_ACCESS_TOKEN、YOUR_ACCESS_TOKEN_SECRETにはそれぞれTwitterの設定のときにのときにコピペしておいたConsumer Key、Consumer Secret、Access Token、Access Token Secretを入れてください。)

これを実行すると「Hello,World!」とつぶやかれるはずです。

Hello,World!

図1.6: Hello,World!

プログラムの説明をすると、まず一行目の

  require 'twitter'

はモジュール(ここではgem twitter)を呼び出すコードです。

また、3~8行目の長いのはTwiterのアカウントにOAuth接続するコードです。ただの変数代入ですから、ここは

  hoge = Twitter::REST::Client.new(
    consumer_key:        "YOUR_CONSUMER_KEY",
    consumer_secret:     "YOUR_CONSUMER_SECRET",
    access_token:        "YOUR_ACCESS_TOKEN",
    access_token_secret: "YOUR_ACCESS_TOKEN_SECRET",
  )

としておいて、最後のところを

  hoge.update "Hello,World!"

としても動作します。

また、9行目にある

  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

これはSSL証明書を確認しないという意味です。セキュリティ的に危ないですが、Windowsではなぜか証明書が更新されていないため、接続するにはこのオプションを付けるか証明書を書き換えるかする必要があります。(Mac OS Sierraではなくても接続できました。)

そして最後の

  client.update "Hello,World!"

ですが、これはTwitterに投稿するコードです。ほかにもフォローなどいろいろなことができます。*2

表1.1: できること

メソッド名利用例と意味
.updateclient.update "Hello" Helloとつぶやく
.followclient.follow "Apple" @Appleをフォロー
.unfollowclient.unfollow "Apple" @Appleをフォロー解除
.blockclient.block "Apple" @Appleをブロック
.unblockclient.unblock "Apple" @Appleをブロック解除
.useruser = client.user "Apple" @Appleの情報を取得
.iduser.id 上で取得した情報のうちユーザーID
.screen_nameuser.screen_name 上で取得した情報のうちユーザー名
.protected?user.protected? 上で取得した情報のうち非公開かどうか(true,false)
.tweets_countuser.tweets_count 上で取得した情報のうちツイート数
.followers_countuser.followers_count 上で取得した情報のうちフォロワー数
.friends_counuser.friends_count 上で取得した情報のうちフォロー数
.home_timelinclient.home_timeline 自分のタイムラインを取得
.user_timelinclient.user_timeline "Apple" @Appleのタイムラインを取得
.mentions_timelineclient.mentions_timeline メンションを取得

コマンドラインからつぶやく

さっきのプログラムを応用することでコマンドライン(コマンドプロンプト等)からつぶやくことができるようになります。いちいちブラウザを開かなくていいので便利です。

リスト1.3: cmd.rb

  require 'twitter'
  require 'kconv'

  client = Twitter::REST::Client.new(
    consumer_key:        "YOUR_CONSUMER_KEY",
    consumer_secret:     "YOUR_CONSUMER_SECRET",
    access_token:        "YOUR_ACCESS_TOKEN",
    access_token_secret: "YOUR_ACCESS_TOKEN_SECRET",
  )
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

  tweet = gets.chomp.toutf8
  client.update tweet

さっきと比べると呼び出しが追加されています。

  require 'kconv'

このkconvというのは文字コードを変更するためのモジュールです。なぜこんなものがいるかというと、Windowsの標準文字コードはShift-JISなのでコマンドラインから入力した文字列はShift-JISでフォーマットされるのに対しTwitterではUTF-8を使用しているためTwitter側では文字化けしてしまうからです。(Macだと標準でUTF-8を使っているのでこの部分はいりません。)

あと最後らへんに追加されている

  tweet = gets.chomp.toutf8

gets.chompというのはコマンドラインで受け取った文字列から改行を削除するメソッドで、.toutf8と言うのはさっき言ったkconvを使って文字コードをUTF-8に変換するメソッドです。

これを実行してからツイートしたい言葉を入力するとツイートされます。

最後の部分を

  print "いまどうしてる?>"
  tweet = gets.chomp.toutf8
  client.update tweet

みたいな感じにすると面白いかもしれません。

時報

いよいよBotらしいBotを作っていきます。今回の時報Botの仕様は5分おきに現在時刻を表示し、かつ昼か夜かわかりやすくするため6時から18時のあいだと18時から6時のあいだとでは表示様式を変えるというものです。

リスト1.4: chrono5.rb

  require "twitter"

  client = Twitter::REST::Client.new(
    consumer_key:        "YOUR_CONSUMER_KEY",
    consumer_secret:     "YOUR_CONSUMER_SECRET",
    access_token:        "YOUR_ACCESS_TOKEN",
    access_token_secret: "YOUR_ACCESS_TOKEN_SECRET",
  )
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

  loop do
    t = Time.now
    hour = t.hour
    min = t.min
    sec = t.sec
    mins = min.to_s

    if hour < 18 && hour >= 6 && min % 5 == 0 && sec == 0 && mins.length == 1
      client.update "----------#{hour}:0#{min}----------"
      sleep 295
    elsif hour < 18 && hour >= 6 && min % 5 == 0 && sec == 0 && mins.length == 2
      client.update "----------#{hour}:#{min}----------"
      sleep 295
    elsif (hour < 6 || hour >= 18) && min % 5 == 0 && sec == 0 && mins.length == 1
      client.update "■■■■■■■■■■#{hour}:0#{min}■■■■■■■■■■"
      sleep 295
    elsif (hour < 6 || hour >= 18) && min % 5 == 0 && sec == 0 && mins.length == 2
      client.update "■■■■■■■■■■#{hour}:#{min}■■■■■■■■■■"
      sleep 295
    end
  end

最初と比べて変わったのはloop内だけです。

loopの最初では変数代入をしています。Time.nowと言うのは現在時間、.hour, .min, .secはそれぞれ時、分、秒を取得するTimeクラスのメソッドです。

その次は条件分岐です。

  if hour < 18 && hour >= 6 && min % 5 == 0 && sec == 0 && mins.length == 1
    client.update "----------#{hour}:0#{min}----------"
    sleep 295
  elsif hour < 18 && hour >= 6 && min % 5 == 0 && sec == 0 && mins.length == 2
    client.update "----------#{hour}:#{min}----------"
    sleep 295
  elsif (hour < 6 || hour >= 18) && min % 5 == 0 && sec == 0 && mins.length == 1
    client.update "■■■■■■■■■■#{hour}:0#{min}■■■■■■■■■■"
    sleep 295
  elsif (hour < 6 || hour >= 18) && min % 5 == 0 && sec == 0 && mins.length == 2
    client.update "■■■■■■■■■■#{hour}:#{min}■■■■■■■■■■"
    sleep 295
  end

1本目の条件分岐は時間が6時から18時までの間で分が5で割り切れて、一桁(0分か5分)で秒が0のときに傍線と現在時間を表示するということです。一桁と二桁で分けたのは

----------12:5----------

みたいになって気持ち悪いと思ったからです。

また、投稿した後にsleepに入るようにしていますが、これは無限ループによる負荷を減らすために入れています。5分おきなんだから300秒のほうが効率的だと思うかもしれませんが、Twitterの投稿に数秒かかるので295秒にしています。ただし動かしてから最初の投稿までの間はsleepがきかず、高負荷がかかるので注意しましょう。

あとの条件分岐もあまり変わりませんね。

これで時報Botは完成です。投稿間隔を変えればn分おきの時報も作れます。

単語をつぶやくBot

次は2時間おきに決められた単語をつぶやくBotを作ります。大体のBotはこんな感じです。

リスト1.5: kemono.rb

  require "twitter"

  client = Twitter::REST::Client.new(
    consumer_key:        "YOUR_CONSUMER_KEY",
    consumer_secret:     "YOUR_CONSUMER_SECRET",
    access_token:        "YOUR_ACCESS_TOKEN",
    access_token_secret: "YOUR_ACCESS_TOKEN_SECRET",
  )
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

  loop do
    t = Time.now
    hour = t.hour
    min = t.min
    sec = t.sec
    words = ["わーい!", "たーのしー!", "すっごーい!", "なにあれ?", "なにこれ?",
      "おもしろーい!", "しゃべったああああああ!", "ひどいよー!", "どこここ?", "あーはー!","えっへん!",
      "そんなことないよ!", "あらーいさーん"]
    words.each do |tweet|
      if hour % 2 == 0 && min == 0 && sec == 0
        client.update tweet
        sleep 7195
      end
    end
  end

配列を作って、その中からツイートする単語を順番に選んでいく感じですね。

今回はwordsという配列の中に13個の単語があり、2時間ごとにそれを順番に投稿するので26時間で一周するようになっています。

ここで注意です。Twitterには投稿制限というものがあり、同一内容のツイートを短時間のうちには連続して投稿できないんですね。制限が解除される時間は、はっきりとはわからない(無責任)のですが、24時間挟めば確実に引っかからないです。よって単語の候補を増やせばもっと短い間隔で投稿できますし、候補が少なくても間隔を開ければ投稿できます。

今回はeachメソッドで順番に取り出していますが、こんな感じでランダムに取り出すこともできます。

  tweet = words.sample
  if hour == 10 && min == 0 && sec == 0
    client.update tweet
    sleep 86395
  end

ただしランダムにする場合は同じ単語が連続で当たる可能性もあるので上記の理由から投稿間隔を24時間以上にしておくのを忘れないようにしましょう。

また、後で詳しく述べますが、さっき作った時報Botのように時間の正確性および現在時間の把握などが必要ない今回のようなBotではプログラム内に投稿の周期を書くより、運用の際に設定したほうが楽です。

天気予報

最後に朝7時に大阪の天気を投稿する天気予報Botを作ります。天気と言ってもサイトによって予報が違うこともありますが、今回はLivedoor 天気予報のWeather Hacksから天気予報を取ってくることにしました。

リスト1.6: weather.rb

  require "twitter"
  require "net/http"
  require "uri"
  require "json"

  client = Twitter::REST::Client.new(
    consumer_key:        "YOUR_CONSUMER_KEY",
    consumer_secret:     "YOUR_CONSUMER_SECRET",
    access_token:        "YOUR_ACCESS_TOKEN",
    access_token_secret: "YOUR_ACCESS_TOKEN_SECRET",
  )
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

  loop do
    uri = URI.parse('http://weather.livedoor.com/forecast/webservice/json/v1?city=270000')
    json = Net::HTTP.get(uri)
    result = JSON.parse(json)
    today_tel = result['forecasts'][0]['telop']
    tomor_tel = result['forecasts'][1]['telop']
    min_tem = result['forecasts'][1]['temperature']['min']['celsius']
    max_tem = result['forecasts'][1]['temperature']['max']['celsius']
    t = Time.now
    hour = t.hour
    min = t.min
    sec = t.sec
    if hour == 7 && min == 0 && sec == 0
      client.update "#{result['title']}\n#{result['link']}\n予報の発表日時: #{result['publicTime']}\n今日: #{today_tel}\n明日: #{tomor_tel} 最低#{min_tem}度 最高#{max_tem}度"
      sleep 86395
    end
  end

まず呼び出しが追加されています。

  require "net/http"
  require "uri"
  require "json"

いずれもWeather Hacksのサイトから情報を取ってくるためのモジュールです。

また、loopの最初の

  uri = URI.parse('http://weather.livedoor.com/forecast/webservice/json/v1?city=270000')

ですが、このURIから天気情報を取ってくるという意味です。また、URIの最後のcity=270000の数字に他の値を入れると他の都市の天気情報を持ってこられます。例えば神戸の天気ならcity=280010、東京ならcity=130010みたいな感じです。各地域のIDはhttp://weather.livedoor.com/weather_hacks/webserviceに載っています。

あとはJSONで情報を読み込んで、変数に代入して投稿しているだけです。

これでプログラミングは終わり、いよいよ運用に入っていきます。

運用

さっきのプログラミングで一応Botそのものは完成です。ところが単純にコマンドプロンプト等で実行していると間違えて終了させてしまったり、またログインしていないと実行されないなどたくさんの問題があります。そこでどうにかして自動で実行させようというわけです。ありがたいことに、Windowsにはタスクスケジューラというアプリが標準ではいっていて、それを使うとかんたんに自動実行を設定できます。とはいっても流石に電源が切れていたりするとプログラムを実行できないので、常に電源の入ったPCが必要となります。

常に電源の入ったPCとは

サーバーが理想的ですが、基本的に常に電源が入っていればデスクトップでもノートパソコンでもいいです。充電が切れたり、シャットダウン、再起動、スリープ等しているときにBotのツイート時刻が被るとその時刻のツイートはされないので注意しましょう。

タスクスケジューラで回す

(注意) ここからは管理者権限でログインしているものとします。

まずタスクスケジューラを起動します。すると右の【操作】というパネルに【タスクの作成...】(【基本タスクの作成...】ではない。)というところがありますね。そこを押して、出てきた画面で【名前】と【説明】を適当に書き、下の方にあるラジオボタンを【ユーザーがログオンしているかどうかにかかわらず実行する】にしておきOKを押します。

次に【トリガー】タブを開き、左下にある【新規】をクリックします。開いたウィンドウで【タスクの開始】を【スタートアップ時】にしてからOKを押します。これで起動したときにプログラムが実行されます。

次に【操作】タブを開き、【新規】をクリックして、【操作】では【プログラムの開始】を選択、【プログラム/スクリプト】はrubyw.exeが存在する場所(C:\Ruby\bin\rubyw.exe等)を記述します。【引数の追加】はプログラミングのところでかいたプログラムの場所(C:\Ruby\samples\chrono5.rb等)を記述して、【開始】はそのプログラムが保存されているフォルダ(C:\Ruby\samples等)を記述します。

これでOKを押したらTwitterのBotは完成です。お疲れ様でした。

おまけ

プログラミングのところで時報Botのように時間の正確性および現在時間の把握などが必要ない単語をつぶやくBot、天気予報Botなどではプログラム内に投稿の周期を書くより、運用の際に設定したほうが楽だ、と言いました。たとえば単語のBotの場合、

リスト1.7: kemono-kai.rb

  require "twitter"

  client = Twitter::REST::Client.new(
    consumer_key:        "YOUR_CONSUMER_KEY",
    consumer_secret:     "YOUR_CONSUMER_SECRET",
    access_token:        "YOUR_ACCESS_TOKEN",
    access_token_secret: "YOUR_ACCESS_TOKEN_SECRET",
  )
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

  words = ["わーい!", "たーのしー!", "すっごーい!", "なにあれ?", "なにこれ?",
    "おもしろーい!", "しゃべったああああああ!", "ひどいよー!", "どこここ?", "あーはー!","えっへん!",
    "そんなことないよ!", "あらーいさーん"]
  client.update words.sample

プログラムをこういうふうに書き換えて、さっきの【トリガー】を設定するところで【タスクの開始】を【スケジュールに従う】にして、左にあるラジオボタンを【毎日】にします。

これで一日置きにランダムに単語をつぶやかせることができます。もちろん最初に言ったやり方でやっても何も問題ありません。

1.4 おわりに

これで2017年度の部誌「TwitterのBotを作ってみる」は終わりです。

今回作ったのは本当に最低限の機能しかないBotです。もっと高機能なBotも作ることができるのでこの部誌を読んでBotに興味が湧いてきたという人はぜひチャレンジしてみてください。

ここまで私の拙い文を読んでくださった皆さん、本当にありがとうございました。