A Day In The Boy's Life -72ページ目

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

4月で計画停電終了か、というニュースが流れていますので「Twitterで計画停電のグループ検索BOT作りました 」で作ったbotが今後活躍することはないような気がしていますが、せっかくなのでリプライに反応して情報を返すようなTwitter botの作り方を書いてみます。

基本的な作りは、今までにこのブログの中でまとめたPHPプログラムを使いまわしているのが大部分なんですが。

似たような動きをするのに@recipetter とかがありますね。(実際の動作はどうなっているかわかりませんが・・・)



botを動かすプログラム群


@teiden_kensaku のbotは4つのプログラムから成り立っています。

図にするとこんな感じ。


A Day In The Boy's Life-Twitter-BOT


それぞれ役割を分担させ、1つの処理が他の処理のボトルネックにならないようにしています。

東京電力のHPで公開されている計画停電のグループの情報を取得するプログラム(group_get.php)、Twitterユーザーが@teiden_kensaku宛に飛ばしたリプライの情報を取得するプログラム(twitter_get.php)、取得したリプライから住所を読み取り該当のグループ情報をユーザーに返すプログラム(twitter_post.php)、そしてこれらのプログラムが正常に動作しているかを監視するプログラム(check_deamon.php)です。


以下、各プログラムの詳細。



計画停電のグループ情報を取得するプログラム


東京電力のHP上に、計画停電のグループ情報が掲載されたExcelファイルが公開されています。

このプログラムでは、このExcelファイルからデータを読み取ってデータベースに情報を格納するという処理をしています。


Excelファイルの取り込み処理は、下記のような感じ。


- Excelファイルを取り込み保存する処理


$prefecture = array(array('prefix' => 'tochigi',   'name' => '栃木県'),
                    array('prefix' => 'ibaraki',   'name' => '茨城県'),
                    array('prefix' => 'gunma',     'name' => '群馬県'),
                    array('prefix' => 'chiba',     'name' => '千葉県'),
                    array('prefix' => 'kanagawa',  'name' => '神奈川県'),
                    array('prefix' => 'tokyo',     'name' => '東京都'),
                    array('prefix' => 'saitama',   'name' => '埼玉県'),
                    array('prefix' => 'yamanashi', 'name' => '山梨県'),
                    array('prefix' => 'numazu',    'name' => '静岡県'));
$pre_cnt = count($prefecture);

for ($i = 0; $i < $pre_cnt; $i++) {

    $hp = NULL;

    $file_name = $prefecture[$i]['prefix'] . ".xls";

    $url = "http://www.tepco.co.jp/images/$file_name";
    $hp = file_get_contents($url);

    $fp = fopen("./tmp/$file_name", "w");
    fwrite($fp, $hp);
    fclose($fp);

    sleep(10);
}


以前は、HPトップから各県のグループ情報のExcelがリンクされていたんですが、4月8日現在でなくなってしまっています。(検索システムが公開されているので、そっち使えって事かもしれませんけど)

ただし、まだ上記のリンクは活きていてExcelファイルは定期的に更新されているようです。


ファイルの取得は、file_get_contents 関数を使っていますが、エラーチェックを厳密にしていませんので、したければ$http_response_header とか使って確認した方がよいでしょう。

cURL関数 使っても出来ると思いますが)

このプログラム自体は、Cronにセットしており6時間に1度実行するようにしています。

Excelファイルが1日に1度ぐらいしか更新されていませんし、あまり頻度を高めるとHPへ負荷をかけてしまって問題にもなるので。


PHPでExcelファイルからデータを抜き取る方法ですが、PHPExcel を使いました。


- PHPでExcelファイルからデータを読み取る処理
$objReader = PHPExcel_IOFactory::createReader('Excel5');
$objPHPExcel->setActiveSheetIndex(0);
$worksheet = $objPHPExcel->getActiveSheet();

$list = array();

// Excel内の全行でループ
foreach ($worksheet->getRowIterator() as $row) {
// 最初の3行はグループデータじゃない
    if (($rnum = $row->getRowIndex()) < 4) {
// 一行目にデータの更新日時があるので、そのデータを取得
        if ($rnum === 1) {
            $data = array();
            foreach ($row->getCellIterator() as $cell) {
                if (!is_null($cell)) {
                    $data[] = $cell->getValue();
                }
            }

            for ($j = 0; $j < count($data); $j++) {
                if (!is_null($cell)) {
// Excel内にある更新日時のデータを取得
                       if (preg_match("/^平成[0-9]{2}年[0-9]{1,2}月[0-9]{1,2}日/", $update) === 1) {
                        // ここで更新日時のデータをDBにセット 
                            break;
                    }
                }
            }
        }
        continue;
    }
    $data = array();

// 各列のデータを取得
    foreach ($row->getCellIterator() as $cell) {
        if (!is_null($cell)) {
            $data[] = $cell->getValue();
        }
    }
    // ここで各列の住所、グループ情報をDBにセット
}


少し端折って書いてますが、大体上記のようにExcel内の各データを一行ずつ読み込んでDB内に取り込んでいくという処理をしています。

DBは、PostgreSQLを使っていますがグループ情報を格納しているテーブル構造は下記のようにしています。


- グループ情報を格納しているテーブル構造
 Column |     Type     | Modifiers
--------+--------------+-----------
 pid    | integer      |
 city   | text         |
 town   | text         |
 bgroup | integer      |
 sgroup | character(1) |


まぁ、Excelデータの構造を基本的にそのままDBとして持たせた感じです。



Twitterからリプライを取得するプログラム


こちらは、以前書いた「OAuthを通してPHPからタイムラインの情報を取得する 」のプログラムがベースになっています。

メンションを取得するには、下記のAPIのURLから情報が取得できます。


$api_url = http://api.twitter.com/1/statuses/mentions.xml;

since_idオプションをつけて、TwitterのIDを指定すればそのID以降のメンションを取得することができます。

なので、定期的にメンションを取得するのもそのID以降の情報を取得するようにすれば、重複した情報を処理しないようにすることが出来ます。


取得したメンションのデータは、こちらもDBへ取り込んでいます。

TwitterのIDや送られてきたメンションのデータそのものを取り込み、その日時や処理をしたかどうかをあらわすためのフラグを持たせたりしています。


- リプライの情報を格納しているテーブル構造

    Column     |            Type             | Modifiers
---------------+-----------------------------+-----------
 tid           | text                        |
 screen_name   | text                        |
 twitter_text  | text                        |
 response_text | text                        |
 request_time  | timestamp without time zone |
 post_time     | timestamp without time zone |
 post_flg      | boolean                     |

このプログラム自体は、PHPをデーモン化して動かしています。

PHPをデーモンとして動かすのは「[PHP] デーモンとして動かせるTwitter botの作り方 」を参考にしてみてください。

1分に1度、TwitterのAPIを通してリプライが無いかをチェックして、あればDBに溜め込むという処理だけをさせています。



リプライに反応してPOSTするプログラム


今度は、リプライに反応するプログラムです。

こちらのプログラムも以前に書いた「OAuthを使ってPHPからTwitterへ投稿する 」をベースにしています。


まずは、ユーザーからのリプライはDBに溜め込まれているので、そのDB内で未処理になっている情報を降順に取得していきます。

そのリプライの情報から住所データを抜き出していき、予め取り込んでいる住所とグループ情報のテーブルと突合せを行っていき、該当のものがあればそのグループ情報をPOSTしていきます。

住所のデータではないもの(都道府県から始まってないもの)やリプライではないと思われるツイート(@teiden_kensakuから始まらないもの)に関しては、基本無視させています。


処理が終わったものは順次、処理をしたフラグを更新して行き次回以降に処理をしないようにさせています。

こちらのプログラムもデーモン化させ、1分に1度処理を繰り返すということをしています。



デーモンの稼動状況をチェックするプログラム


リプライを取得するプログラム、リプライに反応するプログラムはそれぞれPEAR::System_Daemon でデーモン化させて稼動させていますが、長時間稼動させていると落ちることがたびたびあったため、その稼動状況をチェックして、デーモンが落ちてたら再起動させるプログラムとして作っています。


落ちる理由は、PEAR::System_Daemonが不安定というより、Twitterからのレスポンスが不安定だったりして、例外処理が発生し、その例外処理を全て処理し切れなかったというものが多かったです。

また、常に私自身がこのbotを監視できる状況ではなかったため、とりあえず落ちたら再起動させる、というようなことを自動化しておきたかったというのもあります。


System_Deamonで動かすプログラムは、起動時に任意の場所に動かすプロセスのIDが書かれたファイルを保存する仕様になっています。

また、自動起動スクリプトを簡単に作ることができるので、このプロセスIDのファイルを読み取りそのプロセスが稼動しているかをチェックし、落ちているようであれば自動起動スクリプトから再起動させてやるという処理をさせています。


- プロセスが落ちてたら再起動する処理
if (!file_exists($get_app_pid)) {
    `/etc/init.d/twitter_get start > /dev/null`;
} else {
    $pid = trim(file_get_contents($get_app_pid));
    if (!(file_exists("/proc/$pid"))) {
        `/etc/init.d/twitter_get restart > /dev/null`;
    }
}

if (!file_exists($post_app_pid)) {
    `/etc/init.d/twitter_post start > /dev/null`;
} else {
    $pid = trim(file_get_contents($post_app_pid));
    if (!(file_exists("/proc/$pid"))) {
        `/etc/init.d/twitter_post start > /dev/null`;
    }
}


プロセスが落ちたと判断しているのは、デーモンを起動させた際に作られるプロセスIDが書かれたファイルが存在しなかった場合、/proc/プロセスIDのディレクトリが存在しなかった場合、ということで判断させています。



まぁまぁ大掛かりにはなってしまったんですが、簡単なTwitter botであれば処理を統合してしまってもっと少ないプログラムで動かすことが出来ると思います。

Twitter上で何かbotを動かしてみたい、って言う場合の参考になれば幸いです。





電力不足によりあちこちで計画停電が実施されています。

仕事だけでなく生活さえも計画停電の影響により、普段とは異なる行動を余儀なくされていますが、自分が住んでいる地区や仕事場が計画停電の対象になるかどうかをTwitter上で検索できるBOT(@teiden_kensaku )を作ってみました。


まぁ、東京電力のHP 上からも検索できるんですがね。。

もちろんこれは、非公式なので正式な情報は東京電力のHPをご参照ください



@teiden_kensakuの仕様


現在は、東京電力のHP上で公開されている9都道府県(栃木県、茨城県、群馬県、千葉県、神奈川県、東京都、埼玉県、山梨県、静岡県)のデータから、指定の地域の計画停電の対象グループを答えてくれます。

@teiden_kensakuに住所を送ると、対象地域のグループをリプライします。


例) 埼玉県入間市高倉1丁目で検索
A Day In The Boy&#39;s Life-計画停電検索-1


結果は、こんな感じ


A Day In The Boy&#39;s Life-計画停電検索-2

複数のグループに登録されている地域もあるらしく、指定した住所の全てのグループが返ってきます。

詳細は、東京電力の方に問い合わせないと不明との事ですが。

返答があるまで早ければ2,3分だと思います。(サーバーの負荷やリクエスト数によってその限りではないですが・・・)


指定する住所は、必ず都道府県から始める必要があります。


@teiden_kensaku {都道府県}{市区町村}{地域名}


また、住所は漢字で指定する必要があります。(埼玉県さいたま市とかひらがなが正式名のところは除きます)
住所は、最後まで指定する必要はありません。

公開されているデータが地区名(町名や○丁目とか)までしかないため、それより詳細な住所(番地やマンション名とか)を指定しても正しい結果が得られません。

個人情報の観点からも詳細な住所は入力しない方が良いかと思います。


もちろん東京都や神奈川県川崎市など大きな範囲でも検索できます。(その場合はその地区に含まれる複数のグループが返ってくる確率が高くなります)
とりあえずその市内や町内が計画停電の対象に含まれてるか調べたいって事もできます。


A Day In The Boy&#39;s Life-計画停電検索-3


括弧内の日時は東京電力のHP上で公開されているデータの中に含まれている公開時間です。

(BOTが返答した、システム解析上の時刻ではありません)

最後のURLは、東京電力のHPへのURLです。


該当の9都道府県以外の都市を指定した場合は無視されます。

また、上記のフォーマット以外でリプライを送った場合も無視されます。

基本的に、BOTの動きをするので要望や疑問を@teiden_kensakuへ送られても返信できません。

要望や質問は、中の人である@it_boy かitboy.orgアットマークgmail.comの方へお願いいたします。



@teiden_kensakuを作った経緯


私の住んでるところ、職場は計画停電の対象には含まれていないのですが、今後東京23区も計画停電の対象に含まれる可能性があると示唆されていますし、毎日東京電力から公開されているデータを逐次チェックするのもかなり面倒なので、こういったBOTを通してすぐに対象地域がグループに属しているかどうかを確認したいと思い、作ってみました。

生活上でも、行く先々が計画停電の対象になっているかが気になったりもしますからね。


今後は、計画停電の情報発信なども出来ればと思っていますが、今のところ未定です。

最後に、作っといて何なんですが早くこういったBOTが活躍しないように復興が進んでいくことを心から願います。





まずは、まだまだ余談を許さない状況ではありますが、一刻も早く被災地が復興し被災された方々が日常を取り戻せることを願います。


私自身は、渋谷の方にある会社で地震を体感したんですが、その直後は案の定電話は普通となり、ネットだけが唯一の情報源となりました。

Twitterでは、多くの被災の情報が飛び交い事の大きさをそこからすぐに読み取ることも出来ました。

実は、社会人になるまでは関西に住んでたため、あの阪神淡路大震災も体験している(実際は当日はたまたま関西にいなかったので直接的にあの地震の大きさを体感したわけではないですが)のですが、当時は高校生でしかも今のように携帯もネットも普及してはいませんでした。

TVの情報が大きなウェイトを占めていましたし、人づてに聞く噂話は今思えばかなり偏っていたような気がします。



情報の怖さ


ただ、情報化社会となった今、ネットを通して簡単に情報を手に入れることが出来ます。

それはとても便利な側面もある一方、風評被害も加速化させる特性を持ちます。

数多くのデマも流れるため、どれが真実かということさえもわからなくなり、かなり疑心暗鬼になってしまいました。


それを象徴するかのような出来事として、自分の周りで一緒に働いていた海外からの労働者が一気に姿を消すというような事態もおきました。

そういった人たちの情報源は自国で(またはその言語)で発せられる情報で、日本国内でもこれだけ情報が錯綜しているので、他国の情報が正しく伝達されているなど到底思えないわけで、それが起こるのは致し方ないことのように思えます。

実際、海外のメディアの伝え方はかなり偏りがあるようで、早く日本を離れた方が良いというような一方的な情報が多いようです。


真実を伝える情報はもちろん正しいものですが、これだけ大きな震災で皆がパニックに陥った現状を見ると、本当にそれが正しいかさえもよくわからなくなったりもします。

嘘で塗り固められたとしても安心とされる情報を発せれば一定の安堵を得ることは出来ます。

ただし、情報が嘘とわかったときの反感も大きくなりますし、それを発したものは大きな報いを得ることにもなりますので、かなりリスクの大きい情報の発信とはなりますが。


それは、政府が国民に対して発信する情報だけでなく、会社においての上司・部下の関係における情報伝達であっても同様です。

このような状況下で部下を落ち着かせるためとはいえ、間違った情報だけを伝えて安堵させても、それが最悪な事態となったときに、その人を守ることなんてこの非常時においては難しくもあります。

結局は、自分自身で情報を得てそれが正しいのか誤っているのかを取捨選択していく能力が試されたりもするんだなと痛感したりもします。


TVでは専門家と名乗る人が数多く出てきましたが、その人たちでさえ良い・悪いの意見が分かれてたりもしますし、Twitter上でもこの非常時における行動のあり方の良し悪しを議論する声が多く見られました。

そのどちら側にいるのか、自分の判断は正しいのか悪いのか、数多くの情報の中で最終決定するのは、結局自分です。

どんなに情報化社会が進んだとしても、その事実に変わりは無いでしょう。

情報の多数決で決めていくやり方もありますが、それが過ちだったとした場合に納得できるはずなど無いでしょうから。



情報の暖かさ


日本中がどんよりする中でも、その数多くの情報から希望となる暖かさを感じることも出来ます。


計画停電が発表されて以降、ヤシマ作戦 といった自ら節電を呼びかける行動もネット上を大いに賑わしましたし、買いだめを禁止するための自作のポスターなども見られました。

Twitter上で、被災地から発信された情報が何度もRTされるのをみましたし、日本中でも自分たちに出来ることは何かとこの状況を少しでも打破するために考えた行動を見て取れます。

不謹慎といわれようが、こんな状況だからこそ皆が温かい心になれるようにと今その場で日常を送ることの大切さや、時には笑える情報というものが飛び交っています。

義援金や協力要請を見るとその動きは世界中に広がっていますから、それも情報伝達スピードに比例して即時に呼応しあう人々の温かさや大きさを表している気がします。


自分自身は大きな被害にはあっていませんが、計画停電や通勤の不自由さなど少しの変化はある中で、そういったことへの不満さえも、繋がっていることへの安堵感から何度も緩和されたりしました。

ネットを通じ、距離は遠く離れていようとも肩を寄せ合い励まし合うということが、今回の件を通して何よりも存在価値を高めたと感じます。

Web系のエンジニアをしているのでその技術に着目しがちなんですが、その上でのユーザー体験というものが本当に大切なんだなと感じたりもします。

技術を通して、それを使う人のライフスタイルの変遷や、それを使うことでその人たちの間で生まれるものが何なのかっていうところ。

単に情報を伝え合う、というものではなし得ないものがあるんだなと。


この幾つもの温かい情報に触れたから自分自身の恐怖というものも和らぎましたし、小さくとも自分に出来ることをやっていこうという勇気も沸いてきます。

情報を操るのも人であれば、その情報に宿る温かさも人のそれそのものではあります。

感情だけでは何も変わらないのも事実です。

ただ、考えより良い一歩を踏み出すためのエネルギーとなるには、そういったものが必要だと思うんですよね。

だから、こういうときこそ温かくなる情報を伝えていきたいと思ったりするわけです。