Twitter bot 分析機能[拡張編]

Ruby

こんにちはkazutoです。今回は、分析機能を実装していきます。

事前準備

まずは事前準備を行っていきましょう。

下記のソースコードをコピペしてください。

require "./config.rb"
require "json"
require "open-uri"
require "csv"
require "./weather_class.rb"
require "./tweet.rb"
require "./search.rb"
require "./analysis.rb"

def execution
  puts "メニューを選択してください"
  puts "[1]天気予報を取得してツイートする"
  puts "[2]5日間の天気情報を表示"
  puts "[3]プロフィール編集"
  puts "[4]ユーザ検索"
  puts "[5]自己分析"
  num = gets.to_i
  case num
  when 1
    current_time_weather  =  wetaher(num)
    tweet(current_time_weather,num)
  when 2
    current_time_weather  =  wetaher(num)
  when 3
    tweet(current_time_weather,num)
  when 4
    search()
  when 5
    analysis()
  else
    puts "無効な値です"
  end
end

execution()

新たにAnalysisクラス(検索機能)を作成したいので、analysis.rbファイルを作成しましょう。

touch analysis.rb
ls  analysis.rb

ファイルが作成できたら、クラスを定義をし、分析機能の雛形を整えましょう。事前準備ですが、少しメソッドの解説をしておきます。

class Analysis<Tweet
  def initialize()
    super(client)
  end
  def analysis_menu
    puts "[1]タイムライン"
    puts "[2]フォロー数"
    puts "[3]フォロワー数"
    puts "[4]タイムライン全件取得"
    puts "[5]比較する"

    num = gets.to_i
    case num
        when 1
          timeline_style(@client.user.screen_name)
        when 2
          puts @client.user.friends_count
        when 3
          puts @client.user.followers_count
        when 4
          pages=number_of_pages_judgment(@client.user.screen_name)
          get_all_tweets(nil,pages,{mode: "WRITE"} )
        when 5
          comparison_user_decision()
        else
          puts "無効の値です"
        end
    end
  def comparison_user_decision()
      puts "比較したいユーザのidを入力してください。"
      user_name = gets.chomp
      search_account_information(user_name,true)
      comparison_user_menu(user_name)
    end

def comparison_user_menu(user_name,search=false,search_target=nil)
      puts "#{@client.user(user_name).name}さん"
      puts "どの項目を比較しますか"
      puts "[1]フォロー数"
      puts "[2]フォロワー数"
      puts "[3]ツイート数"
      puts "[4]いいね数"
      puts "[5]リツイート数"
      num = gets.to_i
      if search
        # 検索したいユーザ + 比較したいユーザ
        case num
          when 1
           #フォロー数を比較
          when 2
           #フォロワー数を比較
          when 3
           #ツイート数を比較
          when 4
           #いいね数を比較
          when 5
           #リツイート数を比較
        else
            puts "無効の値です"
        end
      else
     # マイアカウント + 比較したいユーザ
        case num
          when 1
           #フォロー数を比較
          when 2
           #フォロワー数を比較
          when 3
           #ツイート数を比較
          when 4
           #いいね数を比較
          when 5
            #リツイート数を比較
        else
          puts "無効の値です"
        end
      end
    end
end
class Analysis<Tweet

今回もSearchクラスと同様、Tweetクラスの

  • メソッド
  • 属性(@clinet)

を使っていきたいので、Tweetクラスを継承します。クラスを継承する事で、親クラスのメソッドや属性を引き継ぐ事ができます

def initialize()
    super(client)
end

Analysisクラスでは、特別に属性を持つ必要がないですが、アカウントの認証情報が格納されている、Tweetクラスの@clientは、いいね数などを取得するのに必要なので、Analysisクラスでも扱える様にsuperメソッドを用いています。
superメソッドとは親クラスにある同名のメソッドを呼び出すメソッドです

class Tweet
  attr_accessor :client
end

今回の場合、スーパークラス(親クラス)でattr_accessorを用いてゲッターとセッターを定義しています。したがって、Analysisクラスでも同様に@cilentを使って値を参照する事が可能になります。

 def analysis_menu
    puts "[1]タイムライン"
    puts "[2]フォロー数"
    puts "[3]フォロワー数"
    puts "[4]タイムライン全件取得"
    puts "[5]比較する"

    num = gets.to_i
    case num
        when 1
          timeline_style(@client.user.screen_name)
        when 2
          puts @client.user.friends_count
        when 3
          puts @client.user.followers_count
        when 4
          pages=number_of_pages_judgment(@client.user.screen_name)
          get_all_tweets(nil,pages,{mode: "WRITE"} )
        when 5
          comparison_user_decision()
        else
          puts "無効の値です"
        end
    end

まず初めにanalysis_menuメソッドを用いて、マイアカウントのメニュー欄を表示します。1~4までの項目は、「Twitter bot 検索機能[拡張編]」で同じ様な内容を実装したので、解説は省略させていただきます。分析機能のメインは「比較する」という項目です。なので今回は、比較する項目に関わる内容を重点的に解説していきます。

when 5
          comparison_user_decision()

比較するという項目を選択した場合は、comparison_user_decisionメソッドを呼び出します。

def comparison_user_decision()
      puts "比較したいユーザのidを入力してください。"
      user_name = gets.chomp
      search_account_information(user_name,true)
      comparison_user_menu(user_name)
    end

comparison_user_decisionメソッドでは、比較したいユーザのidを入力し、比較する対象を決定します。

user_name = gets.chomp
search_account_information(user_name,true)
comparison_user_menu(user_name)

具体的な処理内容は、変数user_nameにユーザidを格納します。
search_account_informationメソッドを用いて、比較したいユーザを決定します。その後、comparison_user_menuメソッドを呼び出して、メニューを表示します。

def comparison_user_menu(user_name,search=false,search_target=nil)
      puts "#{@client.user(user_name).name}さん"
      puts "どの項目を比較しますか"
      puts "[1]フォロー数"
      puts "[2]フォロワー数"
      puts "[3]ツイート数"
      puts "[4]いいね数"
      puts "[5]リツイート数"
      num = gets.to_i
      if search
        # 検索したいユーザ + 比較したいユーザ
        case num
          when 1
           #フォロー数を比較
          when 2
           #フォロワー数を比較
          when 3
           #ツイート数を比較
          when 4
           #いいね数を比較
          when 5
           #リツイート数を比較
        else
            puts "無効の値です"
        end
      else
     # マイアカウント + 比較したいユーザ
        case num
          when 1
           #フォロー数を比較
          when 2
           #フォロワー数を比較
          when 3
           #ツイート数を比較
          when 4
           #いいね数を比較
          when 5
            #リツイート数を比較
        else
          puts "無効の値です"
        end
      end
    end
end

comparison_user_menuメソッドでは2つのパターンで比較する事が可能です。

  • 検索したユーザ&比較するユーザ
  • マイアカウント&比較するユーザ
if search
        # 検索したユーザー +  比較したいユーザー
        case num
        end
 else
     # マイアカウント   +  比較したいユーザー
        case num
        end
    end

2つのパターンを再現をするために、上記の様に条件分岐をしています。

要するにユーザーが

  • 検索したユーザと比較したいのか?
  • マイアカウントと比較したいのか?

を選択できる様にプログラムを組みました。

以上で事前準備は、終了になります。次のトピックから本格的な実装になります

Twitter bot 分析機能[実装編]

  • 比較に必要なメソッドを作成しよう
  • フォロー&フォロワー&ツイート
  • いいね&リツイート
  • 検索機能と分析機能を連結させよう

比較に必要なメソッドを作成しよう

こちらのトピックでは、比較するという動作を再現するために必要なメソッドを作成していきます。分析機能の根幹部分なので、ポイントを抑えておきましょう。

  • make_users_informationメソッド
    →比較するデータをハッシュ形式にまとめるメソッド
  • display_resultメソッド
    →結果を表示するメソッド
  • result_of_comparisonメソッド
    →データを比較するメソッド

上記の3つのメソッドを用いて、分析機能の根幹部分を実装していきましょう。

def make_users_information(user_name,type,items,search_target=nil)
      case type
        when "analysis"
          myself=
          {
            name:@client.user.name,
            result:items[:myself]
            }
        comparison_user=
          {
            name:@client.user(user_name).name,
            result:items[:comparison_user]
            }
      return myself , comparison_user
        when "search"
          searchtarget=
          {
            name:@client.user(search_target).name,
            result:items[:search_target_user]
            }
        comparison_user=
          {
            name:@client.user(user_name).name,
            result: items[:comparison_user]
            }
          return searchtarget,comparison_user
      else
        puts "無効の値です"
      end
    end
def display_result(user,comparison_user,item_name)
          puts "-------------------------------"
          puts "#{item_name}"
          puts "#{user[:name]}:#{ user[:result]}"
          puts "#{comparison_user[:name]}:#{ comparison_user[:result]}"
          puts "-------------------------------"
          result_of_comparison(user,comparison_user)
    end

def result_of_comparison(user,comparison_user)
      puts  user[:result] > comparison_user[:result] ?   "#{ user[:name]}の方が#{user[:result]-comparison_user[:result]}多いです" :  "#{ comparison_user[:name]}の方が#{comparison_user[:result]-user[:result]}多いです"
end

では、各メソッドごとに解説していきます。

def make_users_information(user_name,type,items,search_target=nil)
      case type
        when "analysis"
          myself=
          {
            name:@client.user.name,
            result:items[:myself]
            }
        comparison_user=
          {
            name:@client.user(user_name).name,
            result:items[:comparison_user]
            }
      return myself , comparison_user
        when "search"
          searchtarget=
          {
            name:@client.user(search_target).name,
            result:items[:search_target_user]
            }
        comparison_user=
          {
            name:@client.user(user_name).name,
            result: items[:comparison_user]
            }
          return searchtarget,comparison_user
      else
        puts "無効の値です"
      end
    end

make_users_informationメソッドは、比較するデータをハッシュ形式にまとめるメソッドです。

case type
        when "analysis"
        when "search"
      else
        puts "無効の値です"
      end

case文を用いて、引数typeの値によって条件分岐を行っています。

  • typeの値がanalysisだった場合
    →マイアカウント&比較したいユーザの情報をハッシュ形式で返す
  • typeの値がsearchだった場合
    →検索したユーザ&比較したいユーザの情報をハッシュ形式で返す

となります。

処理自体は同じなのですが一部、記述を変える必要があったので、上記の様に条件分岐を行いました。

 #マイカウント
{
  name:@client.user.name,
  result:items[:myself]
}
 #検索したユーザ
{
  name:@client.user(search_target).name,
  result:items[:search_target_user]
}
 #比較したいユーザ
{
  name:@client.user(user_name).name,
  result: items[:comparison_user]
}

データ構造は、

  • name
    →そのアカウントの名前
  • result
    →選択した項目の数

となります。

return myself,comparison_user 
return searchtarget,comparison_user
a,b = make_users_information(#引数)

make_users_informationメソッドで重要な部分は、返り値が2つあるという事です。したがって返り値を受け取る際は、分割代入を用います。

以上で、make_users_informationメソッドの解説は終了です。続いて、結果を表示するメソッドdisplay_resultメソッドの解説をします。

def display_result(user,comparison_user,item_name)
          puts "-------------------------------"
          puts "#{item_name}"
          puts "#{user[:name]}:#{ user[:result]}"
          puts "#{comparison_user[:name]}:#{ comparison_user[:result]}"
          puts "-------------------------------"
          result_of_comparison(user,comparison_user)
    end

display_resultメソッドでは、make_users_informationメソッドで作成した、データを引数に受け取り、結果を表示していきます。

 puts "#{item_name}"

選択した項目名を表示します

 puts "#{user[:name]}:#{ user[:result]}"

マイアカウントまたは検索したユーザの

  • 名前
  • 選択した項目の数

を表示します。

puts "#{comparison_user[:name]}:#{ comparison_user[:result]}"

比較したいユーザの

  • 名前
  • 選択した項目の数

を表示します。

result_of_comparison(user,comparison_user)

最後の行で、データを比較するメソッドresult_of_comparisonメソッドを呼び出します。

def result_of_comparison(user,comparison_user)
      puts  user[:result] > comparison_user[:result] ?   "#{ user[:name]}の方が#{user[:result]-comparison_user[:result]}多いです" :  "#{ comparison_user[:name]}の方が#{comparison_user[:result]-user[:result]}多いです"
end

result_of_comparisonメソッドでは、

  • マイアカウントまたは検索したユーザ
  • 比較したいユーザー

の選択した項目の数を三項演算子で比較します。

user[:result] > comparison_user[:result] ?

「マイアカウントまたは検索したユーザは、比較したいユーザーより値が大きいか?」と条件を提示します。

"#{ user[:name]}の方が#{user[:result]-comparison_user[:result]}多いです" :  "#{ comparison_user[:name]}の方が#{comparison_user[:result]-user[:result]}多いです"

  • →マイアカウントまたは検索したユーザの方が多いと出力

  • →比較したユーザの方が多いと出力

となります。

まあどちらと共通して、差を求めて、どちらの方の数が多いかを求めています。以上で、メソッド部分の解説は終了になります。

フォロー&フォロワー&ツイート

こちらのトピックでは、

  • フォロー
  • フォロワー
  • ツイート

を比較してみましょう。

上記の3つの項目を比較する際のロジック自体は、同じで、渡すデータを少し変更すれば良いだけなので、まとめて実装していきます。

  if search
        case num
          when 1
            items={search_target_user:@client.user(search_target).friends_count,comparison_user:@client.user(user_name).friends_count}
            search_target_user ,comparison_user= make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"フォロー数")
          when 2
            items={search_target_user:@client.user(search_target).followers_count,comparison_user:@client.user(user_name).followers_count}
            search_target_user,comparison_user = make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"フォロワー数")
          when 3
            items={search_target_user:@client.user(search_target).tweets_count,comparison_user:@client.user(user_name).tweets_count}
            search_target_user,comparison_user =  make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"ツイート数")
  else
        case num
          when 1
            items={myself:@client.user.friends_count,comparison_user:@client.user(user_name).friends_count}
            myself ,comparison_user= make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"フォロー数")
          when 2
            items={myself:@client.user.followers_count,comparison_user:@client.user(user_name).followers_count}
            myself,comparison_user = make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"フォロワー数")
          when 3
            items={myself:@client.user.tweets_count,comparison_user:@client.user(user_name).tweets_count}
            myself,comparison_user =  make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"ツイート数")

記述量が少し多いですが、実装している内容は、シンプルなので落ち着いて、ロジックを読み取りましょう。今回は、処理内容がほぼ一緒なので、フォロー数を例に解説をしていきます。

items={myself:@client.user.friends_count,comparison_user:@client.user(user_name).friends_count}

まず初めにmake_users_informationメソッドに送るデータを作成します。したがって、変数itemsにそれぞれのユーザーの比較する項目をハッシュ形式で格納します。

 myself ,comparison_user= make_users_information(user_name,"analysis",items)

make_users_informationメソッドを呼び出して返り値を

  • myself 0R search_target_user
  • comparison_user

に格納します(分割代入)。

display_result(myself,comparison_user,"フォロー数")

最終的にdisplay_resultメソッドを呼び出して、比較結果を出力をします。この作業を他の項目でも繰り返しているだけです。

以上でフォロー&フォロワー&ツイートの実装を終了します。

いいね&リツイート

次のトピックでは、いいね数とリツイート数を比較する処理を実装しましょう。先程、実装した、3つの項目とは違って、Twitter::REST::Clientクラスの中に合計を簡単に求めてくれるメソッドがなかったので、一度、タイムラインの情報を全て取得して、いいね数・リツイート数を独自のメソッドを用いて合計数を求める必要があります。

独自のメソッドで求める必要があると書きましたが、「Twitter bot 検索機能[拡張編]」で作成したTweetクラスの

  • number_of_pages_judgmentメソッド
  • get_all_tweetsメソッド

を軸にして実装していきます。

get_all_tweetsメソッドに以下の記述を足してください。

def get_all_tweets(user_name,pages,type )
  total_repetition = 0
  total_like=0
  total_retweeet = 0
  case type[:mode]
    when "WRITE"
      CSV.open("#{user_name}.csv","w") do |data|
          data << ["id","投稿日","投稿内容","いいね数","リツイート数"]
          pages.each do |page|
          @client.user_timeline(user_name,{ count: 200 ,page:page} ).each do |timeline|
            tweet = @client.status(timeline.id)
            puts"--"*100
            puts  tweet.created_at.getlocal.strftime('%Y年%m月%d日 %H時%M分%S秒' )
            puts tweet.text
            puts "いいね数#{tweet.favorite_count}"
            puts "リツート#{tweet.retweet_count}"
            puts "--"*100
            total_repetition+=1
            total_like+=tweet.favorite_count
            total_retweeet+=tweet.retweet_count
            data << [timeline.id,tweet.created_at.getlocal.strftime('%Y年%m月%d日 %H時%M分%S秒' ),tweet.text,tweet.favorite_count,tweet.retweet_count]
          end
        end
        puts "ツイート数#{@client.user(user_name).tweets_count}"
        # puts "繰り返すた回数#{total_repetition}"
        puts "トータルいいね数#{total_like}"
        puts "トータルリツイート#{total_retweeet}"
        data << ["", "",@client.user(user_name).tweets_count,total_like,total_retweeet]
    end
    when "COMPARISON"
     #ここから追加
      pages.each do |page|
        @client.user_timeline(user_name,{ count: 200 ,page:page} ).each do |timeline|
          tweet = @client.status(timeline.id)
          type[:item] =="like" ? total_like+=tweet.favorite_count : total_retweeet+=tweet.retweet_count
          end
        end
        case type[:item]
          when "like"
            total_like
          when "retweet"
            total_retweeet
        else
          puts "無効の値です"
        end
  else
    puts "無効の値です"
  end

追加した内容は、軽く解説しておきます。

 pages.each do |page|
 @client.user_timeline(user_name,{ count: 200 ,page:page} ).each do |timeline|
          tweet = @client.status(timeline.id)
          type[:item] =="like" ? total_like+=tweet.favorite_count : total_retweeet+=tweet.retweet_count
    end
end

こちらの記述は前回の内容とほぼ一緒です。pagesという変数に格納されている、ページ数をばらして、そのブロック内で、Twitter::REST::Clientクラスのメソッドのuser_timelineメソッドを用いて、タイムライン情報を取得しています。

tweet = @client.status(timeline.id)
type[:item] =="like" ? total_like+=tweet.favorite_count : total_retweeet+=tweet.retweet_count

タイムラインID情報を、変数tweetに格納し、引数typeのitemキーのバリューが”like”だった場合は、いいね数の合計を求めます。条件に一致しない場合は、リツイート数の合計を求めます。

 case type[:item]
          when "like"
            total_like
          when "retweet"
            total_retweeet
        else
          puts "無効の値です"
        end

その後、case文を用いて、引数typeのキーのバリューの値によって条件分岐を行い、呼び出し側に返す返り値を決定します。

  • itemのバリューが”like”だった場合
    →total_likeを返す
  • itemのバリューが”retweet”だった場合
    →total_retweeetを返す

となります。

続いて、get_retweets_or_likesメソッドを作成します。

def get_retweets_or_likes(user_name,get)
      pages=number_of_pages_judgment(user_name)
      get_all_tweets(user_name,pages,{item: get,mode: 'COMPARISON'})
end

get_retweets_or_likesメソッドは

  • number_of_pages_judgmentメソッド
  • get_all_tweetsメソッド

を呼び出して、いいね数||リツイート数の合計値を求めるメソッドです。このメソッドの返り値にいいね数| |リツイート数の合計値が返ってきます。

ここまで実装できたら、後はパズルの様に当てはめていくだけですね。以下の様にget_all_tweetsメソッドに追加しましょう。

  if search
        case num
        when 4
            comparison_user_like = get_retweets_or_likes(user_name,"like")
            search_target_user_like = get_retweets_or_likes(search_target,"like")
            items={search_target_user:search_target_user_like,comparison_user:comparison_user_like}
            search_target_user,comparison_user = make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"いいね数")
           when 5
            comparison_user_retweet = get_retweets_or_likes(user_name,"retweet")
            search_target_user_retweet = get_retweets_or_likes(search_target,"retweet")
            items={search_target_user: search_target_user_retweet,comparison_user:comparison_user_retweet}
            search_target_user,comparison_user = make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"リツイート")
  else
        case num
           when 4
            comparison_user_like = get_retweets_or_likes(user_name,"like")
            myself_like = get_retweets_or_likes(nil,"like")
            items={myself:myself_like,comparison_user:comparison_user_like}
            myself,comparison_user = make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"いいね数")
           when 5
            comparison_user_retweet = get_retweets_or_likes(user_name,"retweet")
            myself_retweet = get_retweets_or_likes(nil,"retweet")
            items={myself:myself_retweet,comparison_user:comparison_user_retweet}
            myself,comparison_user = make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"リツイート")
 

処理内容がほぼ一緒なので、いいね数を例に解説をしていきます。

comparison_user_like = get_retweets_or_likes(user_name,"like")
myself_like = get_retweets_or_likes(nil,"like")

まず初めに先程、作成したget_retweets_or_likesメソッドを用いて、それぞれいいね数の合計値を取得し、各変数に格納していきます。

items={myself:myself_like,comparison_user:comparison_user_like}

次に、make_users_informationメソッドに送るデータを作成します。なので変数itemsに先程、取得したいいね数の合計値が格納している変数をハッシュの中にセットします。

myself,comparison_user = make_users_information(user_name,"analysis",items)

make_users_informationメソッドを呼び出して返り値を

  • myself 0R search_target_user
  • comparison_user

に格納します(分割代入)。

 display_result(myself,comparison_user,"いいね数")

最終的にdisplay_resultメソッドを呼び出して、比較した結果を出力をします。この作業を他の項目でも繰り返しているだけです。

以上でいいね&リツイートの実装を終了します。「比較に必要なメソッドを作成しよう」で作成したメソッドを使い回しているだけなので、シンプルに実装できました。メソッド間のロジックをテンプレート化すると簡単に実装できます。

検索機能と分析機能を連結させよう

分析機能は実装できたので、検索機能と連結させていきます。連結と聞くと難しく感じると思いますが、Searchクラス(検索機能)の中でAnalysisクラス(分析機能)のインスタンスを生成するだけですので、簡単に実装できます。

Searchクラスのsearch_targetメソッドの中に以下の記述を追加してください。

def search_target(user_name)
    puts "#{@client.user(user_name).name}さんどの情報が知りたいですか?"
    puts "[1]タイムライン"
    puts "[2]フォロー数"
    puts "[3]フォロワー数"
    puts "[4]タイムライン情報全件取得"
    puts "[5]比較する"

    num =  gets.to_i
    case num
      when 1
        timeline_style(user_name)
      when 2
        puts "フォロー数:#{@client.user(user_name).friends_count}"
      when 3
        puts "フォローワー数#{client.user(user_name).followers_count}"
      when 4
        pages=number_of_pages_judgment(user_name)
        get_all_tweets(user_name,pages,{mode: "WRITE"} )
      when 5
        #ここから追加
        target_user = user_to_compare()
        analysis = Analysis.new()
        analysis.comparison_user_menu(user_name,true,target_user)
    end
   end

では、解説していきます。

 def user_to_compare()
    puts "比較したいユーザのidを入力してください。"
    target_user  = gets.chomp
    search_account_information(target_user,true)
    target_user
  end
target_user = user_to_compare()

user_to_compareメソッドを呼び出して、比較したいユーザのアカウントIDを変数target_userに格納します。

analysis = Analysis.new()

Analysisクラスのインスタンスを生成します。
インスタンス生成する事でSearchクラス内で、Analysisクラスのメソッドを呼び出す事が可能になります。

 analysis.comparison_user_menu(user_name,true,target_user)

Analysisクラスのcomparison_user_menuメソッドを呼び出して、「比較するメニュー欄」につなげ、連結をします。

以上で、「検索機能と分析機能を連結させよう」実装を終了し、 Twitter botの全ての実装が完了しました。なので、完成したソースコードを貼り付けておきます。

require './analysis.rb'
require 'csv'

class Search<Tweet
    def initialize()
      super(client)
    end

  def search()
    puts "ユーザー名を入力してください。"
    input = gets.chomp
    search_account_information(input)
  end

  def search_target(user_name)
    puts "#{@client.user(user_name).name}さんどの情報が知りたいですか?"
    puts "[1]タイムライン"
    puts "[2]フォロー数"
    puts "[3]フォロワー数"
    puts "[4]タイムライン情報全件取得"
    puts "[5]比較する"

    num =  gets.to_i
    case num
      when 1
        timeline_style(user_name)
      when 2
        puts "フォロー数:#{@client.user(user_name).friends_count}"
      when 3
        puts "フォローワー数#{client.user(user_name).followers_count}"
      when 4
        pages=number_of_pages_judgment(user_name)
        get_all_tweets(user_name,pages,{mode: "WRITE"} )
      when 5
        target_user = user_to_compare()
        analysis = Analysis.new()
        analysis.comparison_user_menu(user_name,true,target_user)
    end
   end

   def user_to_compare()
    puts "比較したいユーザのidを入力してください。"
    target_user  = gets.chomp
    search_account_information(target_user,true)
    target_user
  end

end

  def search
    search= Search.new
    search.search()
  end
class Analysis<Tweet
  def initialize()
    super(client)
  end
  def analysis_menu

    puts "[1]タイムライン"
    puts "[2]フォロー数"
    puts "[3]フォロワー数"
    puts "[4]タイムライン全件取得"
    puts "[5]比較する"

    num = gets.to_i
    case num
        when 1
          timeline_style(@client.user.screen_name)
        when 2
          puts @client.user.friends_count
        when 3
          puts @client.user.followers_count
        when 4
          pages=number_of_pages_judgment(@client.user.screen_name)
          get_all_tweets(nil,pages,{mode: "WRITE"} )
        when 5
          comparison_user_decision()
        else
          puts "無効の値です"
        end
    end

    def comparison_user_decision()
      puts "比較したいユーザのidを入力してください。"
      user_name = gets.chomp
      search_account_information(user_name,true)
      comparison_user_menu(user_name)
    end

    def comparison_user_menu(user_name,search=false,search_target=nil)
      puts "#{@client.user(user_name).name}さん"
      puts "どの項目を比較しますか"
      puts "[1]フォロー数"
      puts "[2]フォロワー数"
      puts "[3]ツイート数"
      puts "[4]いいね数"
      puts "[5]リツイート数"
      num = gets.to_i
      if search
        case num
          when 1
            items={search_target_user:@client.user(search_target).friends_count,comparison_user:@client.user(user_name).friends_count}
            search_target_user ,comparison_user= make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"フォロー数")
          when 2
            items={search_target_user:@client.user(search_target).followers_count,comparison_user:@client.user(user_name).followers_count}
            search_target_user,comparison_user = make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"フォロワー数")
          when 3
            items={search_target_user:@client.user(search_target).tweets_count,comparison_user:@client.user(user_name).tweets_count}
            search_target_user,comparison_user =  make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"ツイート数")
          when 4
            comparison_user_like = get_retweets_or_likes(user_name,"like")
            search_target_user_like = get_retweets_or_likes(search_target,"like")
            items={search_target_user:search_target_user_like,comparison_user:comparison_user_like}
            search_target_user,comparison_user = make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"いいね数")
          when 5
            comparison_user_retweet = get_retweets_or_likes(user_name,"retweet")
            search_target_user_retweet = get_retweets_or_likes(search_target,"retweet")
            items={search_target_user: search_target_user_retweet,comparison_user:comparison_user_retweet}
            search_target_user,comparison_user = make_users_information(user_name,"search",items,search_target)
            display_result(search_target_user,comparison_user,"リツイート")
        else
            puts "無効の値です"
        end
      else
        case num
          when 1
            items={myself:@client.user.friends_count,comparison_user:@client.user(user_name).friends_count}
            myself ,comparison_user= make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"フォロー数")
          when 2
            items={myself:@client.user.followers_count,comparison_user:@client.user(user_name).followers_count}
            myself,comparison_user = make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"フォロワー数")
          when 3
            items={myself:@client.user.tweets_count,comparison_user:@client.user(user_name).tweets_count}
            myself,comparison_user =  make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"ツイート数")
          when 4
            comparison_user_like = get_retweets_or_likes(user_name,"like")
            myself_like = get_retweets_or_likes(nil,"like")
            items={myself:myself_like,comparison_user:comparison_user_like}
            myself,comparison_user = make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"いいね数")
          when 5
            comparison_user_retweet = get_retweets_or_likes(user_name,"retweet")
            myself_retweet = get_retweets_or_likes(nil,"retweet")
            items={myself:myself_retweet,comparison_user:comparison_user_retweet}
            myself,comparison_user = make_users_information(user_name,"analysis",items)
            display_result(myself,comparison_user,"リツイート")
        else
          puts "無効の値です"
        end
      end
    end

    def display_result(user,comparison_user,item_name)
          puts "-------------------------------"
          puts "#{item_name}"
          puts "#{user[:name]}:#{ user[:result]}"
          puts "#{comparison_user[:name]}:#{ comparison_user[:result]}"
          puts "-------------------------------"
          result_of_comparison(user,comparison_user)
    end


    def make_users_information(user_name,type,items,search_target=nil)
      case type
        when "analysis"
          myself=
          {
            name:@client.user.name,
            result:items[:myself]
            }
        comparison_user=
          {
            name:@client.user(user_name).name,
            result:items[:comparison_user]
            }
      return myself , comparison_user
        when "search"
          searchtarget=
          {
            name:@client.user(search_target).name,
            result:items[:search_target_user]
            }
        comparison_user=
          {
            name:@client.user(user_name).name,
            result: items[:comparison_user]
            }
          return searchtarget,comparison_user
      else
        puts "無効の値です"
      end
    end

    def result_of_comparison(user,comparison_user)
      puts  user[:result] > comparison_user[:result] ?   "#{ user[:name]}の方が#{user[:result]-comparison_user[:result]}多いです" :  "#{ comparison_user[:name]}の方が#{comparison_user[:result]-user[:result]}多いです"
    end

    def get_retweets_or_likes(user_name,get)
      pages=number_of_pages_judgment(user_name)
      get_all_tweets(user_name,pages,{item: get,mode: 'COMPARISON'})
    end
end


def analysis
  analysis= Analysis.new
  analysis.analysis_menu
end
require "./config.rb"
require "json"
require "open-uri"
require "csv"
require "./weather_class.rb"
require "./tweet.rb"
require "./search.rb"
require "./analysis.rb"

def execution
  puts "メニューを選択してください"
  puts "[1]天気予報を取得してツイートする"
  puts "[2]5日間の天気情報を表示"
  puts "[3]プロフィール編集"
  puts "[4]ユーザ検索"
  puts "[5]自己分析"
  num = gets.to_i
  case num
  when 1
    current_time_weather  =  wetaher(num)
    tweet(current_time_weather,num)
  when 2
    current_time_weather  =  wetaher(num)
  when 3
    tweet(current_time_weather,num)
  when 4
    search()
  when 5
    analysis()
  else
    puts "無効な値です"
  end
end

execution()
require 'date'
  require 'csv'

  class Wetaher

    def initialize(citys)
      @citys=citys
    end

    def select_city
      @citys.each do |city|
        puts "#{city['id']}:#{city['city']}"
      end
      # puts "天気予報を確認したい都市を選択してください"
      puts "天気情報を取得したい都市を選択してください"
      input = gets.to_i-1
      @citys[input]
    end

    def get_weather_forecast(city)
      response = open(WEATHER_URL + "?q=#{city['english']}&appid=#{WEATHER_API_KEY}&units=metric&lang=ja")
      data=JSON.parse(response.read)
      json_to_parse(data['list'])
      datas= {list: data['list'],city_name:data['city']['name']}
    end

    def display_weather_forecast(weathers)
      CSV.open("#{weathers[:city_name]}.csv","w") do |data|
        data<<["id","時間","天気","気温"]
        puts "地区:#{weathers[:city_name]}"
        id = 0
        weathers[:list].each do|weather|
          id+=1
          puts "------------------------------"
          puts "時間#{weather['dt_txt']}"
          puts "天気:#{weather['weather'][0]['description']}"
          puts "気温:#{weather['main']['temp']}℃"
          puts "------------------------------"
          data<<[id,Time.parse(weather['dt_txt']).strftime('%Y年%m月%d日 %H時%M分' ),weather['weather'][0]['description'],weather['main']['temp']]
        end
      end
    end

    def json_to_parse(weathers)
      weather=JSON.pretty_generate(weathers)
      File.open("tenki.json", mode = "w"){|f|
        f.write(weather)
      }
    end

    def display_weather_text(weathers)
      File.open("tenki.txt", mode = "w"){|f|

        f.write(
          weathers[:list].each do|weather|
            puts "------------------------------"
            puts "時間#{weather['dt_txt']}"
            puts "天気:#{weather['weather'][0]['description']}"
            puts "気温:#{weather['main']['temp']}℃"
            puts "------------------------------"
          end
        )
      }
    end

    def current_time_weather(wethers)

        wethers[:list].map{|wether|wether['dt_txt']= Time.parse(wether['dt_txt'])}
        current_weather  = wethers[:list].select{|wether|wether['dt_txt']>=Time.now}.first
        dt_txt = current_weather['dt_txt'].strftime('%Y年%m月%d日 %H時%M分%S秒' )

        data =  {
          city:wethers[:city_name] ,
          dt_txt:  dt_txt,
          description:current_weather['weather'][0]['description'],
          temperature: current_weather['main']['temp'],
          icon:current_weather['weather'][0]['icon']
          }
    end
  end

  def wetaher(num)
    citys=CSV.read("./citys.csv",headers: true)
    wether = Wetaher.new(citys)
    city=wether.select_city
    datas=wether.get_weather_forecast(city)
    case num
      when 1
        wether.current_time_weather(datas)
      when 2
        wether.display_weather_forecast(datas)
    end
  end
require 'twitter'
require './config.rb'
require 'csv'

class Tweet
  attr_accessor :client
  def initialize(current_time_weather)
    @client = Twitter::REST::Client.new do |config|
      config.consumer_key        =  CONSUMER_KEY
      config.consumer_secret     =  CONSUMER_SECRET
      config.access_token        =  ACCESS_TOKEN
      config.access_token_secret =  ACCESS_TOKEN_SECRET
    end
    @current_time_weather =  current_time_weather
  end

  def updata
    text = "#{@current_time_weather[:dt_txt]}\n#{@current_time_weather[:city]}の天気\n天気:#{@current_time_weather[:description]}\n気温:#{@current_time_weather[:temperature]}"
    @client.update(text)
  end

  def account_setting
    puts "アカウント名:#{@client.user.name}"
    puts "プロフィール文\n#{@client.user.description }"
    puts "[1]アカウント名を変更する"
    puts "[2]プロフィール文を変更する"
    puts "[3]閉じる"
    num = gets.to_i

      case num
        when 1
          name =gets.chomp
          @client.update_profile({name:name} )
        when 2
          description = gets.chomp
          @client.update_profile({description:description} )
        when 3
          return
      end
  end


  def search_account_information(user_name,analsis=false)
   puts  @client.user(user_name).screen_name   # アカウントID
   puts  @client.user(user_name).name          # アカウント名
   puts  @client.user(user_name).description   # プロフィール
   puts "こちらのアカウントのでお間違い無いですか?"
   puts "[1]YES"
   puts "[2]NO"
   num = gets.to_i
   case num
    when 1
      if analsis
        nil
      else
        search_target(user_name)
      end
    when 2
      return
    else
      puts"無効な値です"
   end
  end

   def timeline_style(user_name)
    puts "CSVファイルにデータを書き込みますか❓"
    puts "[1]YES"
    puts "[2]NO"
    num = gets.to_i
    case num
      when 1
        timeline_write(user_name)
      when 2
        timeline(user_name)
    else
      puts "無効の値です"
    end
   end

   def timeline(user_name,write=false)
      total_repetition = 0
      likes = 0
      retweets = 0
      data=[] if write
        @client.user_timeline(user_name).each do  |tweet|
          puts "---------------------------------------------"
          puts "更新日#{tweet.created_at.getlocal.strftime('%Y年%m月%d日 %H時%M分%S秒' )}"
          puts tweet.full_text
          puts "いいね数:#{tweet.favorite_count}"
          puts "リツイート数:#{tweet.retweet_count}"
          puts "---------------------------------------------"
          likes += tweet.favorite_count
          retweets +=tweet.retweet_count
          total_repetition +=1
          data << [ total_repetition,tweet.created_at.getlocal.strftime('%Y年%m月%d日 %H時%M分%S秒' ),tweet.text,tweet.favorite_count.to_i,tweet.retweet_count] if write
        end
        puts "ツイート数:#{ total_repetition}"
        puts "トータルいいね数:#{likes}"
        puts "トータルリツイート数:#{retweets}"
        data if write
   end


   def timeline_write(user_name)
    puts "ss"
    CSV.open("#{user_name}timeline.csv","w") do |data|
      data << ["id","投稿日","投稿内容","いいね数","リツイート数"]
      tweets=timeline(user_name,true)
      tweets.each do |tweet|
        data<<tweet
      end
    end
  end

def get_all_tweets(user_name,pages,type )
  total_repetition = 0
  total_like=0
  total_retweeet = 0
  case type[:mode]
    when "WRITE"
      CSV.open("#{user_name}.csv","w") do |data|
          data << ["id","投稿日","投稿内容","いいね数","リツイート数"]
          pages.each do |page|
          @client.user_timeline(user_name,{ count: 200 ,page:page} ).each do |timeline|
            tweet = @client.status(timeline.id)
            puts"--"*100
            puts  tweet.created_at.getlocal.strftime('%Y年%m月%d日 %H時%M分%S秒' )
            puts tweet.text
            puts "いいね数#{tweet.favorite_count}"
            puts "リツート#{tweet.retweet_count}"
            puts "--"*100
            total_repetition+=1
            total_like+=tweet.favorite_count
            total_retweeet+=tweet.retweet_count
            data << [timeline.id,tweet.created_at.getlocal.strftime('%Y年%m月%d日 %H時%M分%S秒' ),tweet.text,tweet.favorite_count,tweet.retweet_count]
          end
        end
        puts "ツイート数#{@client.user(user_name).tweets_count}"
        puts "トータルいいね数#{total_like}"
        puts "トータルリツイート#{total_retweeet}"
        data << ["", "",@client.user(user_name).tweets_count,total_like,total_retweeet]
      end
    when "COMPARISON"
      pages.each do |page|
        @client.user_timeline(user_name,{ count: 200 ,page:page} ).each do |timeline|
          tweet = @client.status(timeline.id)
          type[:item] =="like" ? total_like+=tweet.favorite_count : total_retweeet+=tweet.retweet_count
          end
        end
        case type[:item]
          when "like"
            total_like
          when "retweet"
            total_retweeet
        else
          puts "無効の値です"
        end
  else
    puts "無効の値です"
  end
end


  def number_of_pages_judgment(user_name)
    pages =[]
    if @client.user(user_name).tweets_count < 200
        count = 1
    elsif @client.user(user_name).tweets_count % 200==0
        count = @client.user(user_name).tweets_count / 200
    else
      remainder =  (@client.user(user_name).tweets_count / 200)
      count = remainder+1
      remainder_num=@client.user(user_name).tweets_count-200*remainder
    end
    1.upto(count) do |num|
      pages.push(num)
    end
    pages
  end
end

def tweet(current_time_weather,num)
  tweet = Tweet.new(current_time_weather)
  case num
  when 1
    tweet.updata()
    puts "ツイートが完了しました。"
  when 3
    tweet.account_setting()
  else
    puts "無効の値です"
  end
end
WEATHER_API_KEY       =  ENV['WEATHER_API_KEY']
WEATHER_URL           =  ENV['WEATHER_URL']

CONSUMER_KEY          =  ENV['CONSUMER_KEY']
CONSUMER_SECRET       =  ENV['CONSUMER_SECRET']
ACCESS_TOKEN          =  ENV['ACCESS_TOKEN']
ACCESS_TOKEN_SECRET   =  ENV['ACCESS_TOKEN_SECRET']
id,city,english
1,東京都,Tokyo
2,大阪,Osaka
3,沖縄,Okinawa
4,北海道,Hokkaido

まとめ:Twitter bot 分析機能[拡張編]

今回でTwitter botシリーズは終了になります。作成したTwitter botは大まかに、

  • ツイート機能(天気情報)
  • プロフィール編集機能
  • 検索機能
  • 分析機能

と上記の4つの機能を実装していきました。更に実用的なTwitter botになりました。皆さんもオリジナルなTwitter botを作成してみましょう。

以上、kazutoでした。

関連記事

※この記事は、下記の4つの記事をご覧いただき、天気予報botを作成してから読み始めていきましょう。