Twitter をいろいろ遊んでみて「やはり携帯電話から更新できないと」と思えてきた。
携帯電話からメールを送る事で Twitter にアップデートをかけてくれるゲートウェイを設置できれば一番いいのだけれど、そのようなメールアドレスを作る場所が今はない(さすがに会社のサーバはまずい)。
ということでiモードから更新をかけられるように短い CGI プログラムを書くことにした。 CPAN には Net::Twitter という Perl モジュールがあるのだが、JSON::Any (と JSON::XS / JSON / JSON::DWIW / JSON::Syck のどれか)が必要で、ちょっと大げさなので今回は使用は見送り。 普通に CGI.pm と LWP::UserAgent で書いた。
#!/usr/bin/perl -w use 5.005_03; use strict; use CGI qw(-no_xhtml); use Jcode; use LWP::UserAgent; my $query = CGI->new; my $user_name = $query->param('u'); my $password = $query->param('p'); my $status = $query->param('s'); $user_name = '' unless defined $user_name; $password = '' unless defined $password; $status = '' unless defined $status; my $message = ''; if ($user_name ne '' && $password ne '' && $status ne '') { my $ua = LWP::UserAgent->new; Jcode::convert(\$status, 'utf8', 'sjis'); $ua->credentials('twitter.com:80', 'Twitter API', $user_name, $password); my $request = $ua->post('http://twitter.com/statuses/update.json', {status => $status . ' '}); if ($request->is_success) { $message = '<p>OK</p>'; } } print $query->header(-type => 'text/html', -charset => ''); print '<html><head><title>Twitter update</title></title><body>'; print '<form method="post" action="twitter">'; print 'ユーザ名:', $query->textfield('u'), '<br>'; print 'パスワード:', $query->password_field('p'), '<br>'; print 'ステータス:', $query->textfield('s'), '<br>'; print '<input type="submit">'; print '</form>'; print $message; print '</body></html>';
とりあえずこれで、iモードから送信できることを確認。 パスワードの入力が面倒だけれども、サーバ側に書いておくのも嫌なので毎回送ることにした。FOMA 端末側には定型文として保存しておく以外にいい手はないのかな。
最初うまく送れなくてなんだろうと思ったが、あきやん氏の「Twitterで日本語を入力する方法 (akiyan.com)」の記事にある
といった日本語を入力する際の注意点がらみだったようである。 とりあえず CGI プログラムの方で最後に必ずいわゆる半角空白を追加するようにしておいた。
文字数チェックとか Twitter API の返り値チェックとか、改善すべきところはいろいろあるけれど、自分用にはまずこれでいいかな。
気が向いた時に外出先から更新かけます。
Twitter の replies (mentions) をフィードリーダや Plagger で読めるようにするために、Basic 認証で Twitter にアクセスしてフィードをとってきてそのまま出力する Perl CGI スクリプトを書いて使っていたのだが、やはり Basic 認証が嫌なので OAuth 認証に書き換えた。
Net::Twitter モジュールだと取ってきたフィードが Perl のデータ構造になってしまいそのまま再度出力するのが面倒なので、Net::OAuth モジュールでリクエストを作って投げるようにした。
以下エラー処理等を省略したコード。
Web サイトに設置すれば(CGI スクリプト側で認証を済ませて)認証無しで replies のフィードが取れるようになるので簡単にフィードリーダで読めるようになる。
#!/usr/bin/perl -w use strict; use warnings; use CGI; use LWP::UserAgent; use Net::OAuth; use Data::Random qw(rand_chars); $Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0A; my $consumer_key = 'YOUR CONSUMER KEY'; my $consumer_secret = 'YOUR CONSUMER SECRET'; my $access_token = 'YOUR ACCESS TOKEN'; my $access_token_secret = 'YOUR ACCESS TOKEN SECRET'; my $url = 'http://twitter.com/statuses/replies.atom'; my $method = 'GET'; my $query = CGI->new; my $request = Net::OAuth->request('protected resource')->new( consumer_key => $consumer_key, consumer_secret => $consumer_secret, request_url => $url, request_method => $method, signature_method => 'HMAC-SHA1', timestamp => time, nonce => join('', rand_chars(ssize => 16, set => 'alphanumeric')), token => $access_token, token_secret => $access_token_secret, extra_params => {count => '200'}); $request->sign; my $ua = LWP::UserAgent->new; my $response; if ($method eq 'GET') { $response = $ua->get($request->to_url); } else { $response = $ua->post($request->to_url); } print $query->header('application/atom+xml; charset=utf-8'); print $response->content;
my $response = URI::Fetch->fetch( "http://api.twitter.com/1/statuses/user_timeline.rss?user_id=$id&count=200" ) or die URI::Fetch->errstr;
とかレガシーなコードが動いているの(2007年11月に書いた*1)で、Twitter API 1.1 に対応せねば。
Net::Twitter::Lite を使うか。Net::Twitter::Lite を cpanm で home の下にインストール。
curl -LO http://xrl.us/cpanm chomod 755 cpanm cpanm -l /home/naney/local/libperl-twitter Net::Twitter::Lite
で自分の Tweet を取ってくるのはだいたいこんな感じ。
#!/usr/bin/perl use warnings; use strict; use HTTP::Date; use Net::Twitter::Lite; use lib qw(/home/naney/local/libperl-twitter/lib/perl5 /home/naney/local/libperl-twitter/lib/perl5/i386-freebsd-64int); my $consumer_key = 'aaa'; my $consumer_secret = 'bbb'; my $access_token = 'ccc'; my $access_token_secret = 'ddd'; my $id = 自分の Twitter アカウントの ID(数字); my $twitter = Net::Twitter::Lite->new( apiurl => 'http://api.twitter.com/1.1', legacy_lists_api => 0, consumer_key => $consumer_key, consumer_secret => $consumer_secret ); $twitter->access_token($access_token); $twitter->access_token_secret($access_token_secret); my $timeline = $twitter->user_timeline( { count => 200, user_id => $id, include_rts => 'true' } ); foreach my $tweet (@$timeline) { my $time = $tweet->{created_at}; $time =~ s/\+0000/UTC/; $tweet->{_created_at} = HTTP::Date::str2time($time); # use $tweet here. }
[ Perl ]
Twitter API v1.1 に対応していないスクリプトがあって、たしか OAuth 対応はしてあるけど RSS 形式を使っていたので JSON で取得して処理するようにしなければなーと思ってたんだけれど、そもそも OAuth 対応すらしてなかった。
なので Net::Twitter::Lite を使うように書き換え。
あと、いままで1つのスクリプトで「Twitter API を呼び出してタイムライン取得」「シリアライズしてファイルに保存」「Wiki 形式に整形して書き出し」をしていたんだけれど、UNIX 哲学に従って小スクリプトに分割してパイプで受け渡すように変更するなど。
スクリプト間のやりとりは構造化テキストデータなので JSON にしたんだけれど、若干これでいいのかなぁ感はある。テキスト形式だし最近の主流フォーマットではあるんだけれど、それでもシェルから見ると複雑な形式な気がするんだよね。でもあと軽量な構造化テキストフォーマットだと YAML ぐらいかなぁ。
Naney (なにい)です。株式会社ミクシィで SNS 事業の部長をしています。
※本サイトの内容は個人的見解であり所属組織とは関係ありません。