複数のTwitterユーザーの情報を長期的に記録し続けるプログラム
はじめに
Aqoursキャストさんたちのフォロワー数の推移を長期的に観測したかったので、即席で作ってみました。なるべく汎用性の高いように作ったので、ご自身の好きなユーザーの好きなステータスを記録することも可能になっています。もしよろしければ私に影響の出ない範囲でご利用ください。
データ保存用データベースを作る
ご利用するデータベース サーバーにアクセスして以下のような構造になるようにセットアップしてください。(Sakuraのレンタルサーバーの場合はコントロールパネルからMySQLのサーバーにアクセスできます。)
- mysql***.db.sakura.ne.jp
- yoshipc_aqours
- Aikyan_
- date (種別: date)
- followers_count (種別: int(11))
- aina_suzuki723
- anju_inami
- box_komiyaarisa
- furihata_ai
- Kanako_tktk
- Rikako_Aida
- Saito_Shuka
- suwananaka
- Aikyan_
- yoshipc_aqours
テーブル名を@idに、その中のフィールドをそれそれdate, followers_countに分けていきます。
情報を集め、記録する
まず必要な情報を集めて記録する必要があります。ユーザーに表示するのはその後です。
本プログラムは任意のユーザーのフォロワー数を長期的に観測できるようにしたものです。
<?php require_once __DIR__.'/twitteroauth/autoload.php'; use Abraham\TwitterOAuth\TwitterOAuth; $consumer_key = '*************************'; $consumer_secret = '**************************************************'; $access_token = '**************************************************'; $access_token_secret = '*********************************************'; $connection = new TwitterOAuth($consumer_key, $consumer_secret, $access_token, $access_token_secret); //調べたいユーザーの@idを配列にして格納します $target_array = Array( "box_komiyaarisa", "Kanako_tktk", "Saito_Shuka", "Rikako_Aida", "aina_suzuki723", "furihata_ai", "suwananaka", "anju_inami", "Aikyan_" ); $i = (int)"0"; $result_array = Array(); while (true) { //まずユーザー情報を全て取得します $followers = $connection->get("users/show",["screen_name" => $target_array[$i]]); $followers_array = json_decode(json_encode($followers),true); //フォロワー数を抜き取り、配列に追加します array_push($result_array, $followers_array["followers_count"]); if($i == 8) { break; } else { $i++; } } date_default_timezone_set('Asia/Tokyo'); $today = date('Y-m-d'); //データベース接続情報 //予めデータ保存用のデータベースを作っておく必要があります $sql = mysql_connect("mysql***.db.sakura.ne.jp","*******","*************"); $db_connection = mysql_select_db("yoshipc_******",$sql); $i = "0"; while (true) { //保存用クエリ $query = "INSERT INTO {$target_array[$i]} (date, followers_count) VALUES ('{$today}', '{$result_array[$i]}')"; //クエリを叩きます $query_result = mysql_query($query); if($i == "8") { break; } else { $i++; } } ?>
上記プログラムがフォロワー数をデータベースに保存するためのものです。実行するたびに保存してしまうので、cronで毎日0時00分に実行するように登録しておいてください。
データを表示する
データベースに保存しただけでは参照するにも推移がよく分かりませんので、Webページ上でデータを閲覧できるようにしていきます。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="author" content="yoshipc" /> <title>Aqoursキャスト フォロワー数統計</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" /> <link rel="stylesheet" href="style/main.css" /> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> </head> <body> <?php date_default_timezone_set('Asia/Tokyo'); $today = date('Y-m-d'); //データベース接続情報 $sql = new mysqli("mysql***.db.sakura.ne.jp","*******","*************","yoshipc_aqours"); //ここで表示したい全員の情報を以下のフォーマットで配列に格納 //Array(@ID, 表示名, カラーコード, カラーコード) //後ろ2つのカラーコードはグラフの色になりますので、なるべくユニークなものを登録してください $target_name_array = Array( Array("box_komiyaarisa","小宮有紗","rgba(255,0,0,1.0)","rgba(255,0,0,.6)"), Array("Kanako_tktk","高槻かなこ","rgba(240,240,30,1.0)","rgba(240,240,30,.6)"), Array("Saito_Shuka","斉藤朱夏","rgba(127,247,250,1.0)","rgba(127,247,250,.6)"), Array("Rikako_Aida","逢田梨香子","rgba(250,112,140,1.0)","rgba(250,112,140,.6)"), Array("aina_suzuki723","鈴木愛奈","rgba(232,30,242,1.0)","rgba(232,30,242,.6)"), Array("furihata_ai","降幡愛","rgba(247,158,248,1.0)","rgba(247,158,248,.6)"), Array("suwananaka","諏訪ななか","rgba(0,247,178,1.0)","rgba(0,247,178,.6)"), Array("anju_inami","伊波杏樹","rgba(245,193,51,1.0)","rgba(245,193,51,.6)"), Array("Aikyan_","小林愛香","rgba(192,192,192,1.0)","rgba(192,192,192,.6)") ); ?> <div id="wrapper"> <header class="col-lg-10 col-lg-offset-1"> <h1>Aqoursキャスト フォロワー数統計</h1> </header> <div class="col-lg-10 col-lg-offset-1"> <!--// ここにグラフが表示されます //--> <canvas id="followers_graph"></canvas> </div> <div class="col-lg-10 col-lg-offset-1"> <div class="container col-lg-12"> <table class="table table-striped"> <thead> <tr> <th></th> <th>全期間平均変化量(/日)</th> <th>5日間平均変化量(/日)</th> <th>最新変化量</th> <th>最新データ</th> </tr> </thead> <tbody> <?php $k = (int)"0"; //表示されたときに綺麗にソースを見せたいので... $indent = " "; //データを表示するためのテーブルをwhileループで出力 while(true) { echo "<tr>"; echo "<td>{$target_name_array[$k][1]}</td>"; echo "<td id=\"{$target_name_array[$k][0]}\"></td>"; echo "<td id=\"{$target_name_array[$k][0]}_5days\"></td>"; echo "<td id=\"{$target_name_array[$k][0]}_1day\"></td>"; echo "<td id=\"{$target_name_array[$k][0]}_latest\"></td>"; echo "</tr>\r\n{$indent}"; if($k == "8") { echo "\r\n"; break; } else { $k++; } } ?> </tbody> </table> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script> <script> $(function() { var data = { type: 'line', data: { datasets: [ <?php $i = (int)0; $count = (int)"0"; $indent = (string)" "; //ソースで綺麗に見せるため //各種データを保存できるように配列を用意 $avg = Array(); $avg_5days = Array(); $avg_1day = Array(); $latest = Array(); while (true) { //各人のフォロワー数データセットをwhileで出力 //指定されたjson形式で出力 echo "\r\n" . $indent . "{\r\n"; echo $indent . "label: '{$target_name_array[$i][1]}',\r\n"; echo $indent . "fill: false,\r\n"; echo $indent . "borderColor: '{$target_name_array[$i][2]}',\r\n"; echo $indent . "pointBackgroundColor: '{$target_name_array[$i][3]}',\r\n"; echo $indent . "data: ["; $query = "SELECT * FROM {$target_name_array[$i][0]} ORDER BY date ASC LIMIT 50"; $result_query = $sql->query($query); $count = $result_query->num_rows; //全員レコード数は同じはずなので //その人の統計値を出すために変数初期化 $j = (int)"0"; $diff_sum = (int)"0"; $diff_start = (int)"0"; $diff_end = (int)"0"; $diff_5days_start = (int)"0"; $diff_5days_sum = (int)"0"; $diff_yesterday = (int)"0"; $diff_1day = (int)"0"; while ($data = $result_query->fetch_assoc()) { //1日ずつ出力 //ここのwhileループがjsonでの各日データになる echo "{$data["followers_count"]}"; //全期間平均 if ($diff_start == "0") { $diff_start = $data["followers_count"]; } else if ($j == ($count - 1)) { $diff_end = $data["followers_count"]; } //5日間平均 if ($j == ($count - 5)) { $diff_5days_start = $data["followers_count"]; } //最新増加量 if ($j == ($count - 2)) { $diff_yesterday = $data["followers_count"]; } //最新データ if ($j == ($count - 1)) { array_push($latest, $data["followers_count"]); } if($j != ($count - 1)) { echo ","; $j++; } } //各日データループはここでおしまい //各統計値計算 $diff_sum = $diff_end - $diff_start; $diff_5days_sum = $diff_end - $diff_5days_start; $diff_1day = $diff_end - $diff_yesterday; //統計値を保存用の配列に格納 array_push($avg, round(($diff_sum / ($count - 1)))); array_push($avg_5days, round($diff_5days_sum / 4)); array_push($avg_1day, $diff_1day); echo "]"; //ここまでがdata:[] if($i == 8) { echo "}\r\n"; //ここまでがdata: {} break; } else { echo "},\r\n"; $i++; } } //各日ループはここでおしまい ?> ], labels: [ <?php //今日までの日付を連番で出力 $i = $count - 1; while (true) { echo "'" . date("Y-m-d",strtotime("- {$i} day")) . "'"; if($i == 0) { echo "\r\n"; break; } else { echo ","; $i--; } } ?> ] }, options: {} }; new Chart(document.getElementById("followers_graph"), data); <?php //このパート以降は各統計値のデータは使わないので、色々と改造しちゃう //コード上の事情でテーブルへの値代入はjQuery使います $k = "0"; $indent = " "; $max = number_format(max($avg)); $min = number_format(min($avg)); while(true) { //全期間平均をテーブルに出力 $avg[$k] = number_format($avg[$k]); if ($max == $avg[$k]) { echo "$(\"#{$target_name_array[$k][0]}\").html(\"<b id='max'>{$avg[$k]}</b>\");\r\n{$indent}"; } else if ($min == $avg[$k]){ echo "$(\"#{$target_name_array[$k][0]}\").html(\"<b id='min'>{$avg[$k]}</b>\");\r\n{$indent}"; } else { echo "$(\"#{$target_name_array[$k][0]}\").text(\"{$avg[$k]}\");\r\n{$indent}"; } if($k == "8") { echo "\r\n{$indent}"; break; } else { $k++; } } $k = "0"; $max = number_format(max($avg_5days)); $min = number_format(min($avg_5days)); while(true) { //5日間平均をテーブルに出力 $avg_5days[$k] = number_format($avg_5days[$k]); if ($max == $avg_5days[$k]) { echo "$(\"#{$target_name_array[$k][0]}_5days\").html(\"<b id='max'>{$avg_5days[$k]}</b>\");\r\n{$indent}"; } else if ($min == $avg_5days[$k]){ echo "$(\"#{$target_name_array[$k][0]}_5days\").html(\"<b id='min'>{$avg_5days[$k]}</b>\");\r\n{$indent}"; } else { echo "$(\"#{$target_name_array[$k][0]}_5days\").text(\"{$avg_5days[$k]}\");\r\n{$indent}"; } if($k == "8") { echo "\r\n{$indent}"; break; } else { $k++; } } $k = "0"; $max = number_format(max($avg_1day)); $min = number_format(min($avg_1day)); while(true) { //最近増加量をテーブルに出力 $avg_1day[$k] = number_format($avg_1day[$k]); if ($max == $avg_1day[$k]) { echo "$(\"#{$target_name_array[$k][0]}_1day\").html(\"<b id='max'>{$avg_1day[$k]}</b>\");\r\n{$indent}"; } else if ($min == $avg_1day[$k]){ echo "$(\"#{$target_name_array[$k][0]}_1day\").html(\"<b id='min'>{$avg_1day[$k]}</b>\");\r\n{$indent}"; } else { echo "$(\"#{$target_name_array[$k][0]}_1day\").text(\"{$avg_1day[$k]}\");\r\n{$indent}"; } if($k == "8") { echo "\r\n{$indent}"; break; } else { $k++; } } $k = "0"; $max = number_format(max($latest)); $min = number_format(min($latest)); while(true) { //最新データ $latest[$k] = number_format($latest[$k]); if ($max == $latest[$k]) { echo "$(\"#{$target_name_array[$k][0]}_latest\").html(\"<b id='max'>{$latest[$k]}</b>\");\r\n{$indent}"; } else if ($min == $latest[$k]){ echo "$(\"#{$target_name_array[$k][0]}_latest\").html(\"<b id='min'>{$latest[$k]}</b>\");\r\n{$indent}"; } else { echo "$(\"#{$target_name_array[$k][0]}_latest\").text(\"{$latest[$k]}\");\r\n{$indent}"; } if($k == "8") { echo "\r\n{$indent}"; break; } else { $k++; } } ?> }); </script> </body> </html>
これでグラフが表示されます。
めちゃくちゃ長ったらしいソースになってしまい申し訳ないです。
サーバーにアップロードして、ページを開くと以下のようになります。
ダイブいい感じ!
index.phpも配列さえいじれば別の人に入れ替えることが出来るので、ぜひぜひ。
完成形はこちらです。
https://yoshipc.net/aqours_cast_followers/
投稿者プロフィール
最新の投稿
- 2018.09.01AMD動画エンコードでGPUを活用する
- 2018.03.26phpツイートIDからsnowflakeを用いて投稿時刻のミリ秒を算出
- 2018.02.18phpphpMyAdminのインストール方法(Ubuntu)
- 2018.01.07未分類新聞を折らずに郵送する方法
Thank you very much! The “Aqours cast follower count” page is really helpful. Unfortunately, I don’t understand mysql at all. I just wondered that Is it possible to record the followers data before 11/25 by modify your code?
Thanks for your comment!
Unfortunately, maybe not. MySQL can record current data, so it cannot record past data such as yesterday. If we had a time machine, you could record the data before Nov 25 by modifying my code ;(
日本語苦手ですみません。
こちらの例示する図表https://yoshipc.net/blog/wp-content/uploads/2017/12/SnapCrab_No-5860.png が2017年11月25日始まりで、今このページを開いて見れば、11月26日からです。他の方が記録したデータをチェック、2018年6月12日のデータが無くなった。ご修正する方法はありますか?
その日のデータは 253,120 251,020 310,730 305,171 254,088 199,463 255,100 282,801 300,460 (図表の順次同じ。当日日本標準時1時記録。)
Sorry for late reply.
I’ve checked the defect failure.Your report is correct.
I cannot guess the data which is in 12th June, so I handled the data as the average between 11th June and 13th June.
Thank you for your reporting. If you have more questions, please reply.
2018年2月25日・26日・27日のデータも無くなりました。この三日間、ページには全て「0」が表示されました。今日(28日)の夜中の頃も「0」でしたが、午後は正常に戻りました、でも25日・26日・27日のデータがありません。今、25~27日の所では実は22~24日のデータを表示しています。(私は28日0時の頃でツイッターをスクリーンショットしましたが、フォロワーの数字がちょっと違います。このページにの28日のデータは午後(正常に戻った時)で記録したものだと思います。)
Your post is very correct as last time. Thank you always!
The API key had been changed when I made another app on Python. I tried to complete the missing data but I couldn’t. Therefore, I estimated the missing data by the average changes. Now, the graph on the webpage will display the correct data which is before 24th Feb 2019. If there’s anything else, please report to me! Thank you.
2019年11月6日深夜24時も同じことが発生しました。labelの中の「2017年11月25日」が無くなって、「2019年11月7日」のラベルが出現したが、「2019年11月7日」のところでのデータは実際昨日11月6日のデータとなります(小宮有紗さんは294290、ツイッターでは294314)。
また同じトラブルが発生した。2020年12月10日のデータが記録されなかった。
いつもありがとうございます。報告に基づいて、12月10日のデータを補完的に求めました。
近日中にプログラムに改良を加えようと思います。