院試勉強しながらついTwitterをしてしまうあなたに「院試まで残り何秒bot」作ってみた


お勉強の合間に邪悪なbotを作成。ちょっぴり内輪向けです。

こちらです → @inshi_sister

最近徐々に身の回りで院試勉強をしている人が増えてきています。
お勉強というのは人によっていろいろなスタイルがあります。私は図書館くらいの空気がちょうどいいのですが、人が大勢いる環境で捗る人も意外と多いようです。

そういう方々が集中するために使っているのか、よく見る(煽り合っている?)のが「院試カウントダウンタイマー」やそれに類するカウントダウン系焦らせグッズです。

私がこんなの使いながら勉強したら発狂するんじゃないかと思いますが、まあいろいろな人がいるものです。

一方で図書館などでもよく見るのがTwitterを見ながらのお勉強です。なるほどTwitterというのはひとりで勉強中でも連帯感みたいなものを提供してくれます。一方でこいつはかなりの時間泥棒で、どうやったらTwitterから離れられるか四苦八苦している人も多いようです。

今回はその2つを単純に足して、Twitter上で院試までの残り時間を主張するbotを作ってみました。


watch1

Taken by robstephaustralia, Flickr.

このbot(@inshi_sister)は、定期的に院試までの残り時間をつぶやいてくれます。

ただし、ただひとりでつぶやくだけでなく、フォロワーがツイートしているのを見かけるやいなや「院試! 院試! 」と精一杯暴言を励ましてくれる機能があります。

お勉強したいけどTwitterに引き寄せられる、カウントダウンでも使おうか…という人は試しにフォローしてみてはどうでしょう。フォローは自動で返します。またフォロー解除すればこちらからも自動で解除します。

ただし時刻が機械工学専攻の試験に合わせてあるので、ずれている人もいるかと思います。


ソースコードのお時間。長いし、興味のある人向け。
今回はPythonです。久しぶりに書いたのでPythonとしてかなり変なところがあるかと思います。

まずは前半のもろもろの定義とTwitterとの連携。今回はライブラリにpython-oauth2を使っています。ちょっと関数たちが冗長ですが。
hogehogeは実際にはアクセストークンやら何やらの文字列が入っています。

#! /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):
	client.request('https://api.twitter.com/1.1/friendships/create.json', 'POST',
			urlencode({'user_id': user_id, 'follow': 'true'}))

def post_unfollow(client, user_id):
	client.request('https://api.twitter.com/1.1/friendships/destroy.json', 'POST',
			urlencode({'user_id': user_id}))

def post_to_twitter(client, text):
	client.request('https://api.twitter.com/1.1/statuses/update.json', 'POST',
			urlencode({'status': text.encode('utf-8')}))

def reply_to_twitter(client, text, reply_id):
	client.request('https://api.twitter.com/1.1/statuses/update.json', 'POST',
			urlencode({'status': text.encode('utf-8'), 'in_reply_to_status_id': reply_id}))

後半が全体の処理を行う関数です。

ループの中で順にフォロワーの処理、みんなのツイートの取得、個別向けツイート、みんなへのツイート、保存、の順で処理しています。
途中で予期せず終了したときのために、処理に使うデータを適当に保存しています。

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()

あとはこれを起動すれば、デーモンとして作業をしてくれます。


院試勉強しながらついTwitterをしてしまうあなたに「院試まで残り何秒bot」作ってみた」への1件のフィードバック

  1. ピンバック: 最近のブログ記事まとめ | ぞうさんの何でもノート

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です