むきりょくbotを復活させた。【Python: ツイート編】
高校生の頃に作って、TwitterのAPI仕様が変わり止まっていたむきりょくbotを5年ぶりに再稼働させました。
前回の記事はこちら。
セリフの登録
むきりょくbotはむきりょくかん。さんの作品に登場するキャラクターのセリフや文章を呟くbotです。そのためにはセリフがないと始まりません。 セリフしかもつ必要はないので、今回は単純にテキストファイルで保持するようにしました。以下のように、1行につき1つのセリフが書かれているイメージです。
吾輩は猫である。名前はまだない。(吾輩は猫である/夏目漱石) クラムボンは笑ったよ。(やまなし/宮沢賢治) ある日の暮方の事である。一人の下人げにんが、羅生門らしょうもんの下で雨やみを待っていた。(羅生門/芥川龍之介)
本当はむきりょくbotを作った当時のPCにテキストファイルが残っていればよかったんですが、消失していました。仕方ないので再読を兼ねてひたすらゲームをプレイしたり、過去のツイートを遡って追加していきました。ちなみに、ツイートを遡る時はクエリで日付を指定すると便利です。
from:mukiryokuBOT until:2013-06-20 (2013年6月20日以前のむきりょくbotのツイートを取得)
セリフのランダム取得
セリフを登録したら、今度はそのセリフの中から呟くセリフを取得する必要があります。
ファイルを一度に開いてランダムに抽出すると今後セリフが膨大な数になった時とか嫌なので、いい感じのアルゴリズムをないかと探しました。するとstackoverflowにいい感じのものがあったので参考にさせていただきました(記事中の(Waterman's "Reservoir Algorithm") from Knuth's "The Art of Computer Programming"
)。
How do I read a random line from one file in python? - Stack Overflow
ツイート
さて、これでセリフは取得できたのであとはツイートするだけです。Tweepyではupdate_status()
メソッドたったひとつでツイートできます。
import oauth # oauth認証編で作成したもの import tweepy def post_speech(): api = oauth. create_twitter_api() speech = get_speech() api.update_status(speech) def get_speech(): ~ Reservoir Algorithmでランダムにセリフを取得 ~
このプログラムをtweet.py
として保存し、シェルから実行すれば呟くことができます。
$ python tweet.py
次はどうせなので、何かしらエラーが起きてツイートできなくなった時にslackへ通知が来るようにします。
むきりょくbotを復活させた。【Python: OAuth認証編】
高校生の頃に作って、TwitterのAPIの仕様が変わって止まっていたむきりょくbotを5年ぶりに再稼働させました。
このbotを作った当時はCを授業で少し書き始めたくらいでプログラミングがほぼできず、かつAPIとか何それという状態だったので、「Twitter bot ツール」とかで出てきたツールを使って作ったような記憶があります(たしかPHPだった)。それを@pagesかなんかでバッチ処理してたんじゃなかったかなぁ。
その後TwitterのAPIが変わったか@pagesのサービスが終わったかでずっと止まってました。 直さなきゃ直さなきゃと思いつつもなかなか直せずにいて、先日知人から「あれ最近見ないね」と言われてやっと直すことを決意しました。
完全に0から作ることになりましたが、ただセリフを呟いていくだけなのでだいたい1日で完成しました。諸々の管理上リポジトリは公開できませんが、どんな感じの処理をしているかは書いて行こうと思います。
botの構成
言語:Python
ライブラリ:Tweepy
デプロイ環境:Heroku
トークン取得
TwitterのAPIを使うための申請方法やトークンの取得は色々記事があるので、そちらを参考にしてください。 僕はこれらを参考にしました。
TwitterのAPIについて
Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ ※2018年9月時点の情報 - Qiita
【第1回】Twitter APIを使うためにdeveloper accountの申請をしよう! – cmblog
OAuth認証
今回の言語はPythonで、ライブラリはTweepyを使用しました。
TweepyはTwitterのAPIをよしなに扱えるようにしてくれるライブラリで、非常にメジャーです。これを使ってOAuth認証し、APIオブジェクトを作成します(※トークン等はそれぞれ環境変数として設定している前提です)。
このcreate_twitter_api
関数を呼び出してAPIオブジェクトを取得することで、各メソッドが使えるようになります。
実際に使用するのはまた別の記事で。
続き
GoでSlackのIncoming Webhooksを使う
Slack Incoming Webhooks
Slackにある機能の1つで、これを使うと外部サービスからSlackにメッセージを送信することができます。
詳しい使い方はこちらにあるので、参考にして見てください。
GoでHTTPリクエストを送る
Incoming Webhooksといっていますが、実際にはHTTPリクエストを送信するだけです。
payload
パラメータにJSON形式でいくつかのフィールドを設定することで、自由に装飾したメッセージを送信することができます。
今回は単純なテキストメッセージを送信するだけに留めています。というのも、もともと僕が運用しているTwitter botでエラーが起きた時に通知するためのものなので、そこまで凝ってないというだけです。
抜粋しただけなのでmain関数にはなっていませんが、このSendSlack関数にstring型のmessageを渡せば、環境変数で設定したチャネルへメッセージを送信できます。
Dockerのno Space Left on Deviceエラーでビルドできなくなった。
先日Docker buildを実行したところ、エラーが出てbuildできなくなりました。
色々調べてみたところ、no Space Left on Device
というエラー文を発見。
どうやらVMの容量を食いつぶしてしまっていたみたい。
原因
ぼくが使っていた環境だと、docker-compose up
するとPCのファンがガンガン回ってうるさかったので、ずっと docker-compose run
でコマンドを実行していました。
それが今回わかったんですが、docker-compose run
ってコンテナを新たに立ち上げちゃうみたいですね。完全に勉強不足(というかそもそも勉強していなかった)。
docker ps
してみるとここ半年で立ち上げられた山のようなDockerコンテナが。
同じようにdocker images
も悲惨なものでした。
対処
ぼくはDockerでは一つの環境しか使っていなかったので、コンテナとイメージを全部削除することにしました。
削除するコマンドはそれぞれ
docker rm <コンテナID>
docker rmi <イメージID>
ですが、山のようなコンテナをひとつずつ削除していくのは骨が折れるので、以下のコマンドで全部消しました(使っているのはbashです)。
docker rm $(docker ps -a -q)
docker rmi $(docker images -q)
これで無事ストレージが解放されてbuildできるようになりました。
runの対処
友達に聞いたところ、--rm
オプションをつければプロセス終了と同時にコンテナも消えてくれるとのこと。
今度からこれを使っていこうと思います。
参考
Pythonでtry-exceptする引数付きデコレータを単体テスト
先日Pythonの引数付きデコレータをテストしたいということがありました。
結構調べるのが大変だったので、メモっておきます。
引数付きデコレータ
今回テストしたかったのはこんな感じのデコレータです。
何も起きなければデコレートした関数をそのまま実行し、例外が起きた時に引数で指定した値を返します。
これほんとネスト深くなって嫌ですねー。
何はともあれ、このデコレータを使えばこんな感じで、例外処理を簡単に使えるようになります。
この @try_except
をテストします。
テスト
デコレータは引数に関数を持つので、その関数をモックとして作ってあげなきゃいけません。
こういう時はunittestパッケージのMagicMockを使ってあげると楽に書けます。
また、戻り値や例外なんかも設定できます。
今回は、次の二つをテストします。
- 例外が起きなかった場合にデコレートされた関数の戻り値が返ること
- 例外が起きた時にデコレータに渡した引数が返ること
ここで注意なのですが、デコレータそのものをテストする際は、デコレータを直接関数として呼び出す必要があります。
引数付きデコレータの場合は関数が3つネストされているので、3回の関数呼び出しが必要です。
以上をまとめると、実際のテストコードはこんな感じになります。
無事テストできました。
とにかく大事なのはこの二つですね。
- デコレートする関数をMagicMockを使ってモック化する
- デコレータ自身を関数として呼び出す
参考
pythonのデコレータを使ってお手軽ベンチマーク - BlankTar
[Python] Exceptionをraiseするモック関数の作り方
歪んだ自分と向き合う話
ここ数日某社のインターンに行っていて、人と議論することが多い。
その場で自分がやっていることは今までしてきたこととだいたい近い気がする。
自分から新しく発言することはあまりなくて、人の発言を聞いて、自分なりに解釈して、ところどころでまとめようとする。
高専の頃は実行委員長として最初からまとめたり新しい発言をしていたけど、その前段階。
そのことをメンターに話した時、「本当に自分から発言しないことが最善なの?」とか「その役割がチームにとって最善なの?」と聞かれた。
たぶん今のあり方を否定するわけではなくて、「それが本当に正しいのか」「ほかの手段はないのか」ということを考えて欲しいんだと思う。
今日幡野広志さんの「ぼくが子どものころ、ほしかった親になる。」を読んで、人の在り方について感化された上、チームメンバーの日報を読んで「まずいことをしたな」とはっとさせられることがあったから、自分のことについて考えてみる。
- 「なぜ、新しい発言をしようとしないのか」
- 「自分が正しい」
- 「自分が一番だ」
- 「劣っているはずがない」
- 「それが性格だから」で終わらせない
- 2018年9月11日追記「完璧主義者」