お勉強の合間に邪悪なbotを作成。ちょっぴり内輪向けです。
こちらです → @inshi_sister
東大工学系院試まであと85日と42319秒だよ。
— Inshi_Counter (@inshi_sister) June 1, 2013
最近徐々に身の回りで院試勉強をしている人が増えてきています。
お勉強というのは人によっていろいろなスタイルがあります。私は図書館くらいの空気がちょうどいいのですが、人が大勢いる環境で捗る人も意外と多いようです。
そういう方々が集中するために使っているのか、よく見る(煽り合っている?)のが「院試カウントダウンタイマー」やそれに類するカウントダウン系焦らせグッズです。
私がこんなの使いながら勉強したら発狂するんじゃないかと思いますが、まあいろいろな人がいるものです。
一方で図書館などでもよく見るのがTwitterを見ながらのお勉強です。なるほどTwitterというのはひとりで勉強中でも連帯感みたいなものを提供してくれます。一方でこいつはかなりの時間泥棒で、どうやったらTwitterから離れられるか四苦八苦している人も多いようです。
今回はその2つを単純に足して、Twitter上で院試までの残り時間を主張するbotを作ってみました。
このbot(@inshi_sister)は、定期的に院試までの残り時間をつぶやいてくれます。
ただし、ただひとりでつぶやくだけでなく、フォロワーがツイートしているのを見かけるやいなや「院試! 院試! 」と精一杯暴言を励ましてくれる機能があります。
お勉強したいけどTwitterに引き寄せられる、カウントダウンでも使おうか…という人は試しにフォローしてみてはどうでしょう。フォローは自動で返します。またフォロー解除すればこちらからも自動で解除します。
ただし時刻が機械工学専攻の試験に合わせてあるので、ずれている人もいるかと思います。
ソースコードのお時間。長いし、興味のある人向け。
今回はPythonです。久しぶりに書いたのでPythonとしてかなり変なところがあるかと思います。
まずは前半のもろもろの定義とTwitterとの連携。今回はライブラリにpython-oauth2を使っています。ちょっと関数たちが冗長ですが。
hogehogeは実際にはアクセストークンやら何やらの文字列が入っています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #! /usr/bin/python # -*- coding:utf-8 -*- import oauth2 as oauth from urllib import urlencode import json import datetime import copy import random import time import sys from daemon import DaemonContext i_consumer_key = "hogehoge" i_consumer_secret = "hogehoge" i_access_key = "hogehoge" i_access_secret = "hogehoge" my_screen_name = 'inshi_sister' file_dest = 'hogehoge' target_datetime = datetime.datetime( 2013 , 8 , 26 , 9 ) post_dsec = 5400 reply_threshold = 5 def get_text_from_twitter(client, presentID): get_request = urlencode({ 'count' : 200 , 'since_id' : presentID}) resp, content = client.request( 'https://api.twitter.com/1.1/statuses/home_timeline.json?' + get_request, 'GET' ) texts = [] if (resp[ 'status' ] = = '200' ): texts = json.loads(content) return texts def get_followers(client): get_request = urlencode({ 'screen_name' : my_screen_name}) resp, content = client.request( 'https://api.twitter.com/1.1/followers/ids.json?' + get_request, 'GET' ) texts = [] if (resp[ 'status' ] = = '200' ): texts = json.loads(content) return texts[u 'ids' ] def post_follow(client, user_id): urlencode({ 'user_id' : user_id, 'follow' : 'true' })) def post_unfollow(client, user_id): urlencode({ 'user_id' : user_id})) def post_to_twitter(client, text): urlencode({ 'status' : text.encode( 'utf-8' )})) def reply_to_twitter(client, text, reply_id): urlencode({ 'status' : text.encode( 'utf-8' ), 'in_reply_to_status_id' : reply_id})) |
後半が全体の処理を行う関数です。
ループの中で順にフォロワーの処理、みんなのツイートの取得、個別向けツイート、みんなへのツイート、保存、の順で処理しています。
途中で予期せず終了したときのために、処理に使うデータを適当に保存しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | def main(): f = open (file_dest + 'bot2_ID' , 'rU' ) presentID = int (f.readline()) user_twdict = json.loads(f.readline()) user_screendict = json.loads(f.readline()) user_friendlist = json.loads(f.readline()) user_lastpostdict = json.loads(f.readline()) f.close() client = oauth.Client(oauth.Consumer(key = i_consumer_key, secret = i_consumer_secret), oauth.Token(i_access_key, i_access_secret)) error_count = 0 post_last = time.time() while True : time_start = time.time() try : followers = get_followers(client) tmp_friend = copy.copy(user_friendlist) for follower in followers: if follower in tmp_friend: tmp_friend.remove(follower) else : post_follow(client, follower) for removed_friend in tmp_friend: post_unfollow(client, removed_friend) user_friendlist = followers texts = get_text_from_twitter(client, presentID) texts.sort(key = lambda x:x[u 'id' ]) for text in texts: presentID = text[u 'id' ] user_id = str (text[u 'user' ][u 'id' ]).decode() user_screen = text[u 'user' ][u 'screen_name' ] user_lastpost = text[u 'id' ] if user_screen = = my_screen_name.decode(): continue elif user_id not in user_twdict: user_twdict[user_id] = 1 user_screendict[user_id] = user_screen user_lastpostdict[user_id] = user_lastpost else : user_twdict[user_id] + = 1 user_lastpostdict[user_id] = user_lastpost for user_id in user_twdict: threshold_over = user_twdict[user_id] - reply_threshold if threshold_over > = 0 : dtime = target_datetime - datetime.datetime.now() main_text = u '残り' + str (dtime.days) + u '日!! ' post_text = u '@' + user_screendict[user_id] + u '院試まであと' + main_text for i in range (threshold_over / 2 ): post_text = post_text + main_text if len (post_text) > 131 : post_text = post_text[: 130 ] reply_to_twitter(client, post_text, int (user_id)) user_twdict[user_id] = 0 time.sleep( 2 ) if ((time.time() - post_last) > post_dsec): post_last = time.time() dtime = target_datetime - datetime.datetime.now() post_text = u '東大工学系院試まであと' + str (dtime.days) + u '日と' + str (dtime.seconds) + u '秒だよ。' post_to_twitter(client, post_text) f = open (file_dest + 'bot2_ID' , 'w' ) f.write( str (presentID) + '\r' ) f.write(json.dumps(user_twdict) + '\r' ) f.write(json.dumps(user_screendict) + '\r' ) f.write(json.dumps(user_friendlist) + '\r' ) f.write(json.dumps(user_lastpostdict) + '\r' ) f.close() sleep_time = time_start + 300 - time.time() + random.randint( 0 , 20 ) if (sleep_time > 0 ): time.sleep(sleep_time) except : error_count + = 1 if (error_count > 20 ): sys.exit() pass #if __name__=="__main__": # main() dc = DaemonContext(stdout = open (file_dest + 'stdout.txt' , 'w+' ), stderr = open (file_dest + 'stderr.txt' , 'w+' )) with dc: main() |
あとはこれを起動すれば、デーモンとして作業をしてくれます。
ピンバック: 最近のブログ記事まとめ | ぞうさんの何でもノート