PerlでTwitterのキーワード検索&リツイート(oAuth編)

先日、twitter API の仕様が変更になって、基本認証が使えなくなった。

そのため、以下の記事のスクリプトが動かなくなった。

そこで、oAuthに対応したものをご紹介。

目的

Twitterの検索メモに登録されたキーワードのリストを取得して、タイムラインを検索し、マッチしたものを公式リツイートする。

  • 自分自身の投稿はリツイートしない。
  • RTや@が含まれる投稿はリツイートしない。
  • すでにリツイートした投稿はリツイートしない。
  • ログに保存されたIDより古い投稿はリツイートしない。

アプリケーション登録申請

oAuth認証を行うには以下の情報が必要なので、アプリケーション登録申請を行う。

  • Consumer key
  • Consumer secret
  • Access Token
  • Access Token Secret

登録申請の手順は以下のサイトが分かりやすかった。

実用! PerlでコマンドラインからTwitter投稿(OAuth対応) – perl-mongers.org

ソース

以下のような感じ。
13行目〜17行目を書き換えること。

あとは、Cron等に登録して使用する。

#!/opt/local/bin/perl -wT

#binmode(STDOUT, ":utf8");

use strict;
use Encode;
use Net::Twitter;
use URI::Escape;
use LWP::Simple;
use XML::DOM;

# Config
my $user    = ''; # Twitter のユーザー名
my $key     = ''; # Consumer key
my $secret  = ''; # Consumer secret
my $token   = ''; # Access Token
my $tsecret = ''; # Access Token Secret

my $lang         = 'ja';
my $api          = 'http://search.twitter.com/search.atom';

# do not need to edit
my $max_length      = 140;
my $home;
if (-d $ENV{'HOME'} && $ENV{'HOME'} =~ /^(\/.+)$/) {
    $home = $1;
}
my $log = $home.'/.twitbot.txt'; # 最新のIDを保存して次回以降はこのID以下は無視
if (!-e $log) {
    open (OUT, ">", $log);
    close(OUT);
}

my $max_id = 0;
open (IN, "<", $log);
my $n = <IN>;
if ($n) {
    chomp $n;
    $max_id = $n;
}
close(IN);

# connect to twitter
my $twt = Net::Twitter->new(
    traits => [qw/API::REST OAuth WrapError/],
    consumer_key    => $key,
    consumer_secret => $secret
);

$twt->access_token       ($token);
$twt->access_token_secret($tsecret);

my $sch = $twt->saved_searches();
my %posted;
my $since = $max_id;
foreach (@$sch) {
    my $k = uri_escape_utf8($_->{query});
    my $url = $api.'?show_user=true&q='.$k.'&lang='.$lang;
    my $atom = get($url);
    my $parser = new XML::DOM::Parser;
    my $doc = $parser->parse ($atom);
    my $nodes = $doc->getElementsByTagName ("entry");
    for (my $i=0; $i<$nodes->getLength; $i++) {
        my $node = $nodes->item($i);
        my $txt = getvalue($node, 'title');
        my $id = getvalue($node, 'id');
        if ($id =~ /([0-9]+)$/) {
            $id = $1;
        } else {
            die ('can not get id');
        }
        if ($max_id < $id) {
            $max_id = $id;
        }
        # 以下に該当するものはRTしない
        # 自分の投稿
        # RT(スペース)が含まれる投稿
        # @が含まれる投稿
        # すでにRTした投稿
        # ログに保存されたIDより古い投稿
        if ($txt !~ /^$twitter_user/ && $txt !~ /RT\s/ && $txt !~ /\@/ && !$posted{$id} && $since < $id) {
            $posted{$id} = 1; # 重複投稿しないためのフラグ
            eval {$twt->retweet($id)};
            if ($@) {
                warn "update failed because: ".$@."\n";
            }
        }
    }
}

open (OUT, ">", $log);
print OUT $max_id;
close(OUT);

exit;

sub getvalue {
    my $node = shift @_;
    my $tag = shift @_;
    my $n = $node->getElementsByTagName($tag)->item(0);
    return $n->getFirstChild->getNodeValue;
}

参考

livedoor の天気予報 API 用クラスつくった。

いまさらって感じもあるかもしれませんが、livedoor の「お天気 Web サービス」用の XML をパースして、JSON とか PHP の配列で取得するためのクラスを作った。

PHPのlivedoor Weather Hacks API用クラス

でも、いざ使おうと思ったら、「お天気 Web サービス」そのものが当初予定していた用途にマッチしないことに気がついて、あららと思いながらも、せっかくなので完成(?)させた。

ところで

こういうことって、気象庁あたりがやるべきではないんだろうか?と、おもって調べたら、ここでアメダスのデータをほぼリアルタイムに掲載していた。

で、クローラーつくって取り込んでしまえと思ったら、HTML内に重複したIDが指定されているらしくパーサーがエラー。。。

「自動巡回ソフトは原則としてお断り」みたいなことが書いてあったが、新手のクローラー対策だろうか?(笑)

bit.lyにセキュリティホール?

追記: 8/10 09:00頃だと思いますが、解消されたようですね。

追記:8/10 07:00ごろにbit.lyからまもなく問題を解消するよとメールがあったので、以下の問題は近日中に解消されると思います。

書こうか迷ったのですが、bit.lyにセキュリティホールがあるようです。
いろいろと検索した結果、すでにいくつかのソースが公開されているようなので、あえてここでもご紹介します。

こういうことが可能である旨は私からもbit.lyのサポートに報告済みです。

現象

crossdomain.xmlが非常にゆるい制限になっているため、Flashを使用した悪意のあるページに、bit.lyにログインしたままアクセスすると、メールアドレスやAPIキーを取得されます。

原因

Flashには、crossdomain.xmlというファイルで許可されているコンテンツは別のドメインからでも取得可能にするという、独自の仕組みがあります。

bit.lyは、このcrossdomain.xmlが非常にゆるい制約になっているため、別のサーバーにあるHTMLコンテンツから、bit.lyのコンテンツを取得可能になっています。

サンプル

bit.lyにログインしたまま、以下のURLにアクセスするとメールアドレスが取得されているのが、おわかりかと思います。

http://firegoby.jp/labo/bitly/

実際には、どこにも保存しておりませんので、ご安心下さい。

対策

bit.lyはログインしたままにしないで、こまめにログアウトするよう心がけることを、強くご推奨します。

Perlでキーワード検索&公式リツイートを行うbot

ご注意!

ここでご紹介しているスクリプトは、Twitter API の仕様変更により現在は動作しません!(2010/09/06)

以前に書いた記事「キーワード検索したつぶやきをRTするTwitter用bot」で、特定のキーワードにマッチする記事をRTするスクリプトを紹介したが、その後、みなさん御存知の通りTwitterには公式リツイートという仕組みが導入された。

Twitterブログ: リツイート機能を公開しました

というわけで、以前の記事のスクリプトを以下のように修正することで、公式なリツイートに対応できる。

#!/opt/local/bin/perl -wT

#binmode(STDOUT, ":utf8");

use strict;
use Encode;
use Net::Twitter;
use URI::Escape;
use LWP::Simple;
use XML::DOM;

# Config
my $twitter_user = ''; # twitterユーザー名
my $twitter_pass = ''; # twitterパスワード
my $lang         = 'ja';
my $api          = 'http://search.twitter.com/search.atom';

# do not need to edit
my $twt_clientname  = 'twitbot';
my $twt_clientver   = '0.1';
my $twt_clienturl   = 'http://www.theta.ne.jp/';
my $max_length      = 140;
my $home;
if (-d $ENV{'HOME'} && $ENV{'HOME'} =~ /^(\/.+)$/) {
    $home = $1;
}
my $log = $home.'/.twitbot.txt'; # 最新のIDを保存して次回以降はこのID以下は無視
if (!-e $log) {
    open (OUT, ">", $log);
    close(OUT);
}

my $max_id = 0;
open (IN, "<", $log);
my $n = <IN>;
if ($n) {
    chomp $n;
    $max_id = $n;
}
close(IN);

# connect to twitter
my $twt = Net::Twitter->new(
    username    => $twitter_user,
    password    => $twitter_pass,
    clientname  => $twt_clientname,
    clienturl   => $twt_clienturl,
    useragent   => $twt_clientname,
    source   => $twt_clientname,
    clientver   => $twt_clientver,
);

my $sch = $twt->saved_searches();
my %posted;
my $since = $max_id;
foreach (@$sch) {
    my $k = uri_escape_utf8($_->{query});
    my $url = $api.'?show_user=true&q='.$k.'&lang='.$lang;
    my $atom = get($url);
    my $parser = new XML::DOM::Parser;
    my $doc = $parser->parse ($atom);
    my $nodes = $doc->getElementsByTagName ("entry");
    for (my $i=0; $i<$nodes->getLength; $i++) {
        my $node = $nodes->item($i);
        my $txt = getvalue($node, 'title');
        my $id = getvalue($node, 'id');
        if ($id =~ /([0-9]+)$/) {
            $id = $1;
        } else {
            die ('can not get id');
        }
        if ($max_id < $id) {
            $max_id = $id;
        }
        # 以下に該当するものはRTしない
        # 自分の投稿
        # RT(スペース)が含まれる投稿
        # @が含まれる投稿
        # すでにRTした投稿
        # ログに保存されたIDより古い投稿
        if ($txt !~ /^$twitter_user/ && $txt !~ /RT\s/ && $txt !~ /\@/ && !$posted{$id} && $since < $id) {
            $posted{$id} = 1; # 重複投稿しないためのフラグ
#            my $post = 'RT @'.$txt;
#            $post = decode_utf8($post);
#            if (length($post) > $max_length) {
#                $post = substr($post, 0, 137)."...";
#            }
#            print $post."\n";
#            print "----\n";
            eval {$twt->retweet($id)};
            if ($@) {
                warn "update failed because: ".$@."\n";
            }
        }
    }
}

open (OUT, ">", $log);
print OUT $max_id;
close(OUT);

exit;

sub getvalue {
    my $node = shift @_;
    my $tag = shift @_;
    my $n = $node->getElementsByTagName($tag)->item(0);
    return $n->getFirstChild->getNodeValue;
}

MacOSでGitHub – ファイルの更新からコミット

前回及び前々回に続いてGitHubについて。

今回はいよいよファイルを更新して、レポジトリに反映するところまでを行う。

GitのcloneとSubversionのチェックアウト

ローカルやテストサーバーなどにファイルをダウンロードして、更新作業を行うには、Subversionでは、チェックアウトという操作を行い作業ディレクトリを作成する。

そして、Gitではこれとよく似た操作でcloneという操作を行う。

では、このcloneとsubversionのチェックアウトは何が違うのか?

両者の最も大きな違いは、cloneの結果得られたローカルの作業ディレクトリ内には、レポジトリの全ての修正履歴が含まれている点にある。

したがって、サーバーへのアクセスができないときでも、履歴が参照できたりする!これはエライ!

実際にcloneを行って作業ディレクトリを作成する

ターミナルでデスクトップ上等に任意のディレクトリを作成する。

mkdir ~/Desktop/WorkDir
cd ~/Desctop/WorkDir

この後、cloneを行うためのコマンドを入力するのだが、そのためのリポジトリのパスをあらかじめ調べておく。

リポジトリのパスは、前回の記事で作成したforkの画面上に記載されている。

forkをしたリポジトリは、”Read+Write Access”となっていることに注目。

では、実際にこのパスをコマンドにコピペして使用する。

git clone git@github.com:user/path/to/repos.git

以上を実行すると、カレントディレクトリ内に作業ディレクトリが作成される。

commitしてpush

作業ディレクトリ内に作成された、ファイルを修正したらリポジトリに修正内容を反映する。

それには、以下の操作を行う。

1)追加したファイルや修正したファイルをGitの索引に追加する。

git add file.txt

file.txtというのが修正したファイル。
これに該当するコマンドは、Subversionにはない。

2)コミットする

git commit -m “hogeをhugaした”

これは、コマンドのフォーマットは、Subversionとにているが、この時点ではサーバーのリポジ鳥に反映されていないことが、大きく違う。

なので、以下のコマンドを実行して、”なかった事にする”ことができる。これもエライ!

git reset --soft HEAD^

3)サーバーに反映する

コミットした結果をリポジトリに反映するには、以下のコマンドを実行する。

git push

以上で修正した結果が、forkに反映される。

もし、forkに反映されたものをマスターに反映してもらいたいなら、メール等でマスターのオーナーにお願いすると、反映してもらえるかもしれない。

というわけで、gitについてはここまで。

ちなみに、Gitコマンドについては以下のサイトがわかりやすくまとまっていた。

Gitを使いこなすための20のコマンド – SourceForge.JP Magazine : オープンソースの話題満載

MacOSでGitHub – 既存のプロジェクトをForkする

前の記事に続けて、GitHubについて。

タイトルでは、「MacOSで」とあるが、今回はOSはどれでも同じ。

GitHubについてさらに詳しく

GitHubとは、分散リポジトリのクラウドサービスで、簡単に言うとSubversionが高機能になったシステム(git)のWebサービスである。

では、gitとは何かと言うと、Linuxを開発したリーナス・トーバルズさんが開発したバージョン管理システムで、彼に言わせるとCVSやSubversionは最悪らしい。(笑)

何が最悪なのかは、私の技術レベルではよくわからないが、要はSubversionみたいなバージョン管理システムがGitで、そのレポジトリをオンラインで共有出来るようにしたサービスがGitHubだと考えるとわかりやすい。

今回やりたい事

今回は、WordPressの某テーマファイルを日本語化するに当たり、私以外の方がすでにGitHubでリポジトリを作成しており、そこでメンテナンスをしていた。(感謝!)

ところが、現在の最新バージョンのテーマファイルに対応していなかったので、それを引き継いで修正したいと考えた。

既存のリポジトリをForkする

既存のリポジトリを引き継ぐには、Forkという機能を使用する。

これは、Subversionで言うところのブランチと似ているが、もとのリポジトリにアクセス権が無くても出来ることとか、あとでメインのリポジトリ(マスターと呼ぶ)にマージすることもできる(これはマスターにアクセス権が必要)など、ややブランチとはニュアンスが違う。

実際にForkするには?

引き継ぎたいリポジトリの画面を開いて(例えばこれ)、右上にある「Fork」をクリックする。

これだけの操作で、既存のリポジトリのForkが完了して、コミットができるようになる。

もちろん、Forkしたものは削除もできる。
削除するには、さきほどのForkボタンの左側にある「Admin」ボタンをクリックして、「Delete this repository」をクリックする。

Subversionでブランチを作る手間を考えると、ここまでは簡単。

というわけで、今回はここまで。

MacOSでGitHub – アカウントの作成から初期設定まで

今日、GitHubというサービスを始めて使った。

Githubとは、分散リポジトリのクラウドサービスで、まあ、簡単に言うとオープンなSubversionって感じ?

ちょうど「株式会社はてなの開発戦略」というプレゼンテーションで紹介されていたので、以下のとおりご紹介。

[slideshare id=1023281&doc=deb2009-1234499749924070-2]

アカウントを作成する

GitHubには0.3GBまで保存できる無料アカウントが用意されており、他にもディスク容量等によって、いくつかのプランがある。(フリーミアムなのだ!)

無料アカウントを作成するには、以下のページで登録する。

アカウントの詳細を登録する

ここまでの作業でとりあえずログインはできるようになるが、以下のページでURLや名前などの公開情報や、ファイルをコミットするための公開鍵を設定できる。

公開鍵は後述するので、とりあえず、それ以外の情報を登録しておく。

ちなみに、このページで「Email」を登録すると公開されてしまうので要注意!

Your Account – GitHub

公開鍵の作成

以降はMacOSXのターミナルでの作業が中心。

まず、ターミナルで以下のコマンドを入力して公開鍵を作成する。
パスフレーズの入力を求められるので、任意のパスフレーズを入力するか、パスフレーズが不要な場合は、そのままEnter。

ssh-keygen

上記のコマンドを入力すると、.sshというディレクトリが作成され、その中にid_rsaというファイル名の秘密鍵と、id_rsa.pubというファイル名の公開鍵が作成される。

この公開鍵をGitHubに登録するには、以下のコマンドを実行して出力された文字列をコピペして、「SSH Public Keys」のページで登録する。

cat .ssh/id_rsa.pub

gitコマンドのインストールと設定

GitHubは分散リポジトリのウェブサービスなので、ファイルをコミットしたりチェックアウトするためのコマンドが用意されている。

MacOSXでは、MacPortsで提供されているのでそれを利用してインストールする。

MacPortsがまだインストールされていない場合はこの記事をご参照。

sudo port install git-core +gitweb +svn

とっても優しい github の使い方 – ¬¬日常日記 によると、以下のコマンドも実行しておいたほうがいいらしい。

git config --global user.name "Your Name"
git config --global user.email you@example.com

以上、とりあえず、今回はここまで。

Amazonより「お支払い遅延のお詫び」

あのAmazonより以下のようなメールが突然届いた。

xxxx(xxxx)様

拝啓

平素は格別のお引き立てにあずかり、

ありがたく厚くお礼申しあげます。

この度は 1月度ご請求の代金を本来であれば3月末日迄にお支払いすべきところ、入金が遅れてしまい誠に申し訳ございません。当社システム不具合のためこのような結果となりましたが、現在緊急でこのシステム不具合の解消を行っております。現時点で明確なお支払日をご案内差し上げる事ができないのですが、不具合解消でき次第大至急お支払処理をさせて頂きますので、何卒お待ちくださいますようお願い申しあげます。

略儀ではございますが、取り急ぎ書面 にてお詫び申し上げます。

敬具

Amazonアソシエイト・プログラム

別にたいした金額ではないので、どうでもいいのだが、ちょっと面白かった。

ちなみに、和歌山県の串本町に引っ越しました。
さりげなく、ご報告。

ソーシャルメディアポリシー

ブログやtwitter、SNSなど、オンラインのソーシャルサービスがますます増加する中で、ある企業の一員としてこれらのソーシャルサービスに参加する機会が増えてきた。

そこで、そのためのガイドラインのようなものがないか調べてみた。

マイクロソフト

実際のソースを見つけられなかったが「Web屋のネタ帳」で紹介されたいたのは以下のような内容。

  • 雇用の契約内容に守秘義務があることを忘れない。
  • ニュースを発さない。守秘情報は公開しない。
  • 読者からの情報などは、著作権・特許などの絡みもあるので取り扱いに注意。
  • 前にいた会社に敬意を払い、その情報を書く際には気をつける。
  • 自分自身が誰で、マイクロソフトで働いていることを公開する。
  • 企業責任の問題もあるので、サポートやアドバイスをする時には注意が必要。
  • 個人の意見として公開。
  • 「Post」のボタンを押す前に、どのような反響があるかを考える。

IBM

こちらは、IBMの方がご自身のブログ「再び、Blogging @ IBM:永井孝尚のMM21:ITmedia オルタナティブ・ブログ」で公開している社内のガイドライン。

  • IBMのビジネス・コンダクト・ガイドラインの遵守してください
  • IBM社員は自分が掲載した内容に個人的に責任を持ちます。書いたものが長期間公開されることに留意し、自身のプライバシー保護に努めてください
  • IBM関連のことを書く際、名前とIBMの業務を明確にし、一人称で書くこと。自分の個人的見解でありIBMの意見を代弁するものではないことを明確にすること
  • IBM関連の書き込みをする場合、免責文を入れること。(訳注:私のサンプルはこちらです)
  • 著作権や財務情報公開に関する法律を遵守すること
  • IBMおよび他者の機密情報を提供しないこと
    承認を得ずにお客様、パートナー、サプライヤーを引き合いに出したり、言及しないこと
  • 読者に敬意を払い、中傷や侮辱、猥褻な内容は書かないこと
  • 他の誰がその話題についてブログを行っているか調べ、引用すること
  • 喧嘩を仕掛けないこと。自分の間違いがあれば訂正すること。過去の掲載内容を断りなく変更しないこと
  • 価値を付加するよう心がけること。値打ちのある情報と見識を提供しましょう

英国政府のTwitterガイドライン

これは、本当に素晴らしいの一言。
翻訳は「シロクマ日報」様、ありがとうございます!
政府機関のための Twitter 戦略テンプレート/Template Twitter strategy for Government Departments

perlでbit.lyのapiを使ってurlを短縮

GoogleがURLの短縮を始めたとのことで、もしかしたら窮地に陥っているかもしれませんが、個人的にはURLの短縮なんてGoogleさんがやらんでも!って感じでbit.lyさんを応援したい今日この頃。

というわけで、perlを使ったbit.ly APIによるURL短縮。
別のシステムに組み込んだものを、この記事用に書き換えたので、もし動かなかったらごめんなさい!

#!/usr/bin/perl -wT

use strict;
use warnings;
use JSON::XS;
use LWP::Simple;
use URI::Escape;

my $baseurl = shift @ARGV; # 短縮したいURL

my $bituser = ''; # bit.lyのユーザー名
my $bitkey = ''; # bit.lyのapiキー
my $apiurl = 'http://api.bit.ly/shorten?version=2.0.1&login=%s&apiKey=%s&longUrl=%s';
my $bitly = sprintf($apiurl,$bituser, $bitkey, $baseurl);

my $res = decode_json(get(uri_escape($bitly)));
my $shortURL = $res->{results}->{$baseurl}->{shortUrl};

print $shortURL;
exit;