GAE/Pでフォロワーの増減確認
前回の記事(フォロワーの増減を確認する - void*)は、shellで動かすことを目的として作ったもので、驚くことに、id:tyru 氏がcronで実行できる(Check Twitter's follower (via http://d.hatena.ne.jp/ykot/20110228/1298879383) · GitHub)ようにしてくれていますので、実際にお使いになる場合は、そちらを使用したほうが効率的かと思います。スクリーンネームでの表示になっていますしね。素敵です:)
今回、少し調子に乗って同じような仕組みでGAEで動かせるようにしてみました。いまさら、GAEの説明は不要だとは思いますので、わからない方は適当にググッてみてください。GAEは、自前マシンを必要としないですし、何よりマシンメンテナンスが必要ない、という点において優れています。この程度のスクリプトなら、無料の範囲なのもすばらしいです。とか、偉そうなことを書いていますが使い始めたばかりで、おもちゃ代わりに遊んでいるだけで、全然解ってないです。最低限動くよって状態ですので、ご指摘などありましたら、ぜひ。
#!/usr/bin/env python # -*- coding: utf-8 -*- from google.appengine.ext import webapp,db from google.appengine.ext.webapp import util from google.appengine.api import urlfetch from google.appengine.api import mail from django.utils import simplejson class Follower(db.Model): uid=db.StringProperty() followers=db.TextProperty() class FollowerHistory(db.Model): uid=db.StringProperty() followers=db.TextProperty() entry_dt=db.DateTimeProperty(auto_now_add=True) class MainHandler(webapp.RequestHandler): def get(self): for follow in Follower.all(): self.response.out.write( u"<a href=./%s>%s<br>" % (follow.uid, follow.uid )) class FollowerHandler(webapp.RequestHandler): def get(self, uid): url = "http://api.twitter.com/1/followers/ids/" + uid + ".json" # retry 10回 for r in range(10): result = urlfetch.fetch(url) if result.status_code != 200: self.response.out.write( u"%s twitter api error(%d)" % (uid, result.status_code) ) else: break if result.status_code != 200: return self.response.out.write( u"%s follower check<br>" % uid) # JSON結果から、list生成 newlist=simplejson.loads(result.content) # datastoreから、JSONデータを取得 follow = Follower.gql('WHERE uid = :1', uid).get() if follow is None: # データストアに存在しない=新規.比較なし Follower(uid=uid,followers=result.content).put() FollowerHistory(uid=uid,followers=result.content).put() return # 比較 oldlist=simplejson.loads(follow.followers) newset=set(newlist) oldset=set(oldlist) follow_list="" for i in newset - oldset: follow_list += "follow:%s\n" % i for i in oldset - newset: follow_list += "remove:%s\n" % i # データ設定 follow.followers = result.content follow.put() b = u"...%s の現在のフォロワーの数:%d" % (uid, len(newlist)) self.response.out.write( u"%s<br>%s" % (follow_list, b) ) if follow_list != "": # 差分あり FollowerHistory(uid=uid,followers=follow.followers).put # 差分があった時、メールを送信 body_text = follow_list + b mail.send_mail(sender = "foo@example.com", to = "bar@example.com", subject = "%s followers check" % uid, body = body_text.encode('utf-8'), ) def main(): application = webapp.WSGIApplication([('/', MainHandler), ('/([-\w]+)', FollowerHandler)], debug=True) util.run_wsgi_app(application) if __name__ == '__main__': main()
response.out.writeとかは、cron使うと必要ないのですが、デバッグとして埋め込んでいます。
http://[appname].appspot.com/[twitter uid]で、差分があった場合、メールで通知する仕組みになっています。一応、http://[appname].appspot.com/ で、一覧が出るようになっています。履歴をとっているのは、後ほど利用するためです。
色々いじっていてわかったのですが、apiは、頻繁にエラーを返すので、retryをするようにしています。
また、下記のメール設定を変更してやれば、メール送信できるようになります。foo@example.com、bar@example.comを適当に変更してご使用ください。
mail.send_mail(sender = "foo@example.com", to = "bar@example.com", subject = "%s followers check" % uid, body = body_text.encode('utf-8'), )
cron.yamlで、cron設定しておけば自動的に実行されます。5分おきとかなら、こんな感じです。差分があった場合に、メールで通知してくれます。
cron: - description: follower chenge check job url: /ykots schedule: every 5 minutes
簡単ですね ;)
ちなみに、既知のバグに、フォロワーの数が多いとエラーになるというのがあります。これは、Datastoreの容量制限に引っかかってしまっているためです。それほど試していないのですが、感覚としては、10000から20000ぐらいのフォロワーがいるとエラーになるみたいです。しばらくしたら、そのあたりも対応していく予定です。
フォロワーの増減を確認する
いまさらながら、Twitterアプリを作るためにいくつかのAPIテストしている最中です。で、副産物としてリムーブ通知ができました。cronとかに設定してメール送信でもすれば、コマンドをたたく必要がないです。スクリプト自体は、idで識別しているので、誰なのかを確認するには、別途処理が必要です。
色々確認している最中だけど、この、followers/idsは、100件とかの制限はなさそうなので、こういった簡易的なリストを作るのには向いているかも。
#!/bin/sh uid=ykots ymd=`date '+%Y%m%d%H%M%S'` # TWITTER API TWITTER_FOLLOWERS_API="http://api.twitter.com/1/followers/ids/$uid.json" # フォローワー一覧リスト取得 status=`curl --silent --connect-timeout 10 -O $TWITTER_FOLLOWERS_API -w "%{http_code}"` rtn=$? if [ $rtn -ne 0 ]; then echo "curl error!!($rtn)" exit 1 fi #HTTPステータスコード if [ $status -ne 200 ]; then echo "twitter API error.($r)" cat $uid.json exit 1 fi # リスト作成 if [ -e new_$uid.list ] ;then rm new_$uid.list fi for id in `cat $uid.json |sed -e "s/\[//" | sed -e "s/\]//" | sed -e "s/,/ /g"`; do echo $id >> new_$uid.list done rm $uid.json # 過去比較 if [ -e $uid.list ]; then d=`diff new_$uid.list $uid.list | grep "^[<|>]" | sed -e "s/ /:/g"` if [ -z $d ]; then echo "変わってないよ" exit 2 fi for id in $d; do f=`echo $id | awk 'BEGIN {FS=":"}{print $1}'` if [ $f = "<" ]; then echo "あたらしくフォローされたみたい。 :D" else echo "ありゃ、リムーブされちゃった。 :(" fi echo $id | awk 'BEGIN {FS=":"}{print $2}' done fi # 移動およびバックアップ cp new_$uid.list $uid.list.$ymd mv new_$uid.list $uid.list
まあ、利用する人はいないかと思いますが、利用上の注意を書いておきます。比較のために、過去リストを保存しています。また、履歴も残していますので、適当なタイミングで消す必要があります。
追記
使う人いないと思っていたので、適当に書いていたんですが、星なんかを貰っちゃっていたので、もうすこし、注意点を。このシェルは、使ってみてもらうとわかりますが、ログインとか必要ないです。API的にOAuthとか必要ないんです。実際に使うときには、3行目のuidを変更することで自分用に変更できます。
uid=ykots <-ここを自分のidに変更する
で、ってことは、全然赤の他人のフォロワー履歴も採取することができます。さらにAPIを変更すれば、フォロー履歴も監視できてしまいます。他人を監視って、ちょっと気持ち悪い気もしますが。API的には問題ないのですが、そんな事やっていいのかわかりません。*1そのあたり、自己責任で使ってください。
*1:実際できるのだから、大丈夫だとは思いますけど...
mod_multicast(XEP-0033)
ejabberd 2.1.6は、XEP-0033を対応した、mod_multicastが同胞されていないようです。モジュールだけ入れればいいようなので、簡単な手続きで、使えるようになるようです。
今回は、old code といわれる手順で入れてみました。環境は、CentOS release 5.5 (Final)で、ejabberdのインストールは、epelのrepoからバイナリで入れています。
- svnを使ってモジュールをダウンロード
- インストールするモジュールのtrunkディレクトリへ移動
- cd ejabberd-modules/mod_multicast/trunk
- README.txtをよんでみる。
- cat README.txt
- コンパイル
- ./build.sh
- ファイルのコピー
- sudo cp ebin/mod_multicast.beam /usr/lib64/ejabberd/ebin/
- README.txt に従いconfiguration fileを変更
- 「{access, multicast, [{allow, all}]}.」を追加
- 「{mod_multicast, []},」を追加
- ejabberdのリスタート
- sudo /etc/init.d/ejabberd restart
これらの手順だけでXEP-0033の対応が出来ます。実際に出来るかどうかは、PsiのXMLコンソールから、試してみました。入力したXMLは、こんな感じです。
<message to='multicast.SERVER'> <addresses xmlns='http://jabber.org/protocol/address'> <address type='to' jid='ykot@SERVER'/> <address type='cc' jid='test@SERVER'/> </addresses> <body>Hello, world!</body> </message>
SERVERの部分は、適当に読み替えてください。ちなみにmod_multicastは、multicastのホスト名のデフォルトが、multicast.SERVERとなっています。これを変更したい場合は、{host, "multicast.example.org"},の部分で対応できるようです。*1
簡単ですね。:D
参考
http://www.ejabberd.im/ejabberd-modules
http://www.ejabberd.im/mod_multicast
http://www.ejabberd.im/node/4485
*1:試してはいないので、定かではないですが...
Pythonで、expect。pexpectがいい感じ。
とあるインストーラの自動化をしたいがために、expectを使いたい状況になったのですが、expectが使えない環境(インストールされていないし、権限もない)だったので、変わりに何かあるかなと探していたところ、expectのPython版があることを知りました。pexpect.py さえあれば動作可能なので、非常に使い勝手がいいです。
ちなみに、pexpect.py以外にも色々あるようで、このあたりを読むとイメージ出来るかと思います。
Pexpect - a Pure Python Expect-like module
うん、これは便利です。;-P
shellで日付比較
shellばかりいじっているから、最近、shellネタばかりです。shell上での日付比較は、秒に置き換えてやると、手っ取り早いです。
# 0 : 同一日時 # 1 : $1 の方が新しい日付 # 2 : $2 の方が新しい日付 function datecheck() { dt1=`date -d "$1" '+%s'` dt2=`date -d "$2" '+%s'` if [ $dt1 -eq $dt2 ]; then return 0 elif [ $dt1 -gt $dt2 ]; then return 1 elif [ $dt1 -lt $dt2 ]; then return 2 fi }
結構、便利に使えます。
kill の「終了しました」のメッセージが邪魔
kill コマンドを発行する時の「終了しました」が非常に邪魔だったので、消す方法がないか調べていたら、これで簡単に消せた。
pid=`sh -c 'hoge & echo $!'`
kill $pid