情報系音ゲーマーの手記

Splatoon2とかDDRとか

【Python】tweepyを用いてbot的な何かを作成した話

ハセ学を通したエイプリルフールネタを書こうかと思ってたんですが、いつのまにかエイプリルフールが終了してたので、趣味で書いたPythonbot的なやつの話になります。"若干の"不適切な表現があるので閲覧には少しご注意を...
 



~~ことの発端~~
Twitterで「致すか」ってツイートしてから「致した」ってツイートするまでめっちゃ早いやつおるな。」

「せや!何秒かかってるのか自動で計測できるようにしたろ!」

てな感じでこういう頭悪い感じのbotを作成することに。
f:id:eiki1253:20170412000947p:plain


TwitterAPI(consumer_keyとか)に関してはこちらを
webnaut.jp


プログラムの基本的な部分はこちらを参考にさせていただきました。
net.univ-q.com


それでは早速プログラムの全文なんですが、プログラムが横に広いのに気を付けてください。(あとシングルクオテーションとダブルクオテーションがところどころごっちゃになってますが、気にしないでください。)
プログラムの解説は後ろに書いてあります。

# -*- coding:utf-8 -*-

import tweepy
import datetime

consumer_key = "自分のconsumer_key"
consumer_secret = "自分のconsumer_secret"
access_key = "自分のaccess_key"
access_secret = "自分のaccess_secret"

CK=consumer_key
CS=consumer_secret
AT=access_key
AS=access_secret

itasiname="hoge"
status1="hoge"
d1=datetime.datetime.today()

# Twitterオブジェクトの生成
auth = tweepy.OAuthHandler(CK, CS)
auth.set_access_token(AT, AS)
api = tweepy.API(auth)

class Listener(tweepy.StreamListener):
	def on_status(self, status):
		status.created_at += datetime.timedelta(hours=9)
		# 致すか
		if  u'致すか' in status.text:
			global d1
			global status1
			global itasiname
			itasiname=str(status.author.screen_name)
			d1 = datetime.datetime.today()
			micro1='%s' % d1.microsecond
			microsecond1 = micro1.rjust(6,'0')
			s1=u'%s時%s分%s秒%s\n' % (d1.hour, d1.minute, d1.second, microsecond1)
			itasuka=u"致しはじめ\n"
			status1=itasuka+s1
			print status1
		# 致した
		if (str(status.author.screen_name)==itasiname) and (u'致した' in status.text):
			tweetid=status.id
			d2 = datetime.datetime.today()
			micro2='%s' % d2.microsecond
			microsecond2 = micro2.rjust(6,'0')
			s2=u'%s時%s分%s秒%s\n' % (d2.hour, d2.minute, d2.second, microsecond2)
			itasita=u"致し終わり\n"
			status2=itasita+s2
			print status2
			itasi_microsecond=d2.microsecond-d1.microsecond
			itasi_second=d2.second-d1.second
			if itasi_microsecond<0:
				itasi_microsecond=itasi_microsecond+1000000
				itasi_second=itasi_second-1
			if itasi_second<0:
				itasi_second=itasi_second+60
			if itasi_second==0:
				tweet=u'.@'+itasiname+u' の射精早すぎィ!!!!!自分、不正認定いいすか?'+ \
				      u'淫夢知ってそうだから淫夢のリストにぶち込んでやるぜー!'+ \
				      u'いきなりツイートしてすみません!許してください!なんでもしますから!'+ \
				      u'(なんでもするとは言ってない)'
				print u'早すぎィ!\n'
			else :
				itasi_microsecond_final = str(itasi_microsecond).rjust(6,'0')
				status3=u'致しスピード %s秒%s\n' % (itasi_second,itasi_microsecond_final)
				print status3
				tweet=u'.@'+itasiname+u" の記録\n"+status1+status2+status3
			api.update_status(status=tweet, in_reply_to_status_id=tweetid)
			itasiname="hoge"
		return True

	def on_error(self, status_code):
		print('Got an error with status code: ' + str(status_code))
		return True

	def on_timeout(self):
		print('Timeout...')
		return True

# Twitterオブジェクトの生成
auth = tweepy.OAuthHandler(CK, CS)
auth.set_access_token(AT, AS)

listener = Listener()
stream = tweepy.Stream(auth, listener)
stream.userstream()


自分で書き換えた部分は主に16~18行目と、28~71行目の処理なので、そちらについて解説をおこなっていきます。

まずは16~18行目について、次のようになっています。

16:
itasiname="hoge"
status1="hoge"
d1=datetime.datetime.today()

簡単に言えば、プログラムのどこからでもアクセスできるグローバル変数のようなものを作っています。なぜグローバル変数を用いているのかは後述とします。


次に、28~40行目です。

28:
# 致すか
if  u'致すか' in status.text:
	global d1
	global status1
	global itasiname
	itasiname=str(status.author.screen_name)
	d1 = datetime.datetime.today()
	micro1='%s' % d1.microsecond
	microsecond1 = micro1.rjust(6,'0')
	s1=u'%s時%s分%s秒%s\n' % (d1.hour, d1.minute, d1.second, microsecond1)
	itasuka=u"致しはじめ\n"
	status1=itasuka+s1
	print status1

status.text(ツイートの本文)に"致すか"という文字列が含まれていればここの処理に入ります。
変数の前にglobalをつけることにより、d1などの変数がグローバル変数であることを示しています。これがないと、次の処理でこのツイートが行われた時刻などを得ることができません。(前述のグローバル変数が必要な理由となります。)

33行目では変数itasinameにstatus.author.screenname(ツイートした人のスクリーンネーム、@の後ろに続いてる文字列)を格納しています。後にこれを使うことにより、異なったアカウントの致し時間を計測してしまうことを防ぎます。

34行目ではツイートされた時刻をtoday関数を用いて取得しています。もちろん、時間の差をとるために使いますが、そのまま用いると、1秒004000と表示したいところを1秒4000と表示されてしまいます。なので、rjust関数を用いて0パディング(0埋め)を36行目でおこなっています。

あとは文字列の結合をおこなって、コマンドライン上に確認用に出力するだけです。



後半部分(41~71行目)の処理も似たようなものです。

41:
# 致した
if (str(status.author.screen_name)==itasiname) and (u'致した' in status.text):
	tweetid=status.id
	d2 = datetime.datetime.today()
	micro2='%s' % d2.microsecond
	microsecond2 = micro2.rjust(6,'0')
	s2=u'%s時%s分%s秒%s\n' % (d2.hour, d2.minute, d2.second, microsecond2)
	itasita=u"致し終わり\n"
	status2=itasita+s2
	print status2
	itasi_microsecond=d2.microsecond-d1.microsecond
	itasi_second=d2.second-d1.second
	if itasi_microsecond<0:
		itasi_microsecond=itasi_microsecond+1000000
		itasi_second=itasi_second-1
	if itasi_second<0:
		itasi_second=itasi_second+60
	if itasi_second==0:
		tweet=u'.@'+itasiname+u' の射精早すぎィ!!!!!自分、不正認定いいすか?'+ \
		      u'淫夢知ってそうだから淫夢のリストにぶち込んでやるぜー!'+ \
		      u'いきなりツイートしてすみません!許してください!なんでもしますから!'+ \
		      u'(なんでもするとは言ってない)'
		print u'早すぎィ!\n'
	else :
		itasi_microsecond_final = str(itasi_microsecond).rjust(6,'0')
		status3=u'致しスピード %s秒%s\n' % (itasi_second,itasi_microsecond_final)
		print status3
		tweet=u'.@'+itasiname+u" の記録\n"+status1+status2+status3
	api.update_status(status=tweet, in_reply_to_status_id=tweetid)
	itasiname="hoge"
return True

まずは42行目、先ほどと似ていますが少し条件が違います。"致した"の文字列が含まれてる、かつ、先ほどツイートしたアカウントと同じならこの処理に入ります。ここで変数itasinameを用いています。
43~50行目について、リプライ用にtweer.idをとっていますが、それ以外は先ほどの33~40行目の処理とほぼ同じです。

51~57行目では、"致すか"とツイートしてから"致した"とツイートするまでの時間の差分をとっています。繰り下がりに少し注意です。

58~63行目の処理は、複数クライアントや、プログラムなどを用いた不正の防止用の分岐となります。2つのツイートの時間差が1秒未満であればこの処理に入ります。処理とはいってもクソリプ送るだけですが。

そんで最後、64~71行目ですが、文章や計測結果をのせてツイートするだけです。
少し解説を挟むと、68行目までにツイートの本文を作成してます。69行目のstatusには作成した本文を突っ込み、in_reply_to_status_idという「どのツイートに対して返信するか」という変数には変数tweetid("致した"と書かれたツイートのid)を突っ込んでます。
70行目でitasiname="hoge"としたのは、「致すか」→「致した」→「致した」の順でツイートすると、始めの致すかから、最後の致したまでの差分をとってツイートしてしまうからです。

これで2つのツイートの時間差をとって、勝手にリプライしてくれるbotの完成となります。
お疲れさまでした。

最後に実行結果を次の図に示しておきます。
f:id:eiki1253:20170412013458p:plain


以下、Q&Aコーナー

Q,何の役に立つんですか

  • 何の役にも立ちません。


Q,もっと詳しく説明して

  • コメント等でどこの説明してほしいか言ってくだされば。


Q,変数の命名センスなさすぎ

  • うっせぇ!!!!!!!!