日記とか、工作記録とか

自分に書けることを何でも書いてゆきます。作った物、買ったもの、コンピュータ系の話題が多くなるかもしれません。

Raspberry pi 3でTwitter [RaspiParrot]

#おそるべしPokemon Go…… ってのはさておきまして。

安普請だったのでもう少し堅牢に修正

昨日動かしたままにしておいたRaspiParrotなのですが、謎のエラーで停止していました。

2016-07-21 18:40:40,130 INFO ----- OneCycle開始 -----
2016-07-21 18:40:40,131 INFO Twitter APIの使用を開始します。
2016-07-21 18:40:40,146 INFO Starting new HTTPS connection (1): api.twitter.com
2016-07-21 18:40:40,842 INFO 返答済みのMention:[2016-07-21 17:52:19] WindVoice_en
2016-07-21 18:40:40,843 INFO 返答済みのMention:[2016-07-21 16:21:50] WindVoice_en
2016-07-21 18:40:40,843 INFO 返答済みのMention:[2016-07-21 15:06:49] WindVoice_jp
2016-07-21 18:40:40,844 INFO 返答済みのMention:[2016-07-21 10:32:28] WindVoice_jp
2016-07-21 18:40:40,845 INFO 返答済みのMention:[2016-07-21 09:19:22] WindVoice_jp
2016-07-21 18:40:40,845 INFO ----- OneCycle終了 -----
2016-07-21 18:43:40,945 INFO ----- OneCycle開始 -----
2016-07-21 18:43:40,946 INFO Twitter APIの使用を開始します。
2016-07-21 18:43:40,962 INFO Starting new HTTPS connection (1): api.twitter.com
pi@pi3:~/twitter$

なぜ謎のエラーなのかといいますと、記録が残っていないためです。上のとおり、ログは突然途切れています。サドンデスですね。これでは原因が突き止められないので、まずは情報採取をしっかりやりましょうということで改造します。

例外を処理

Pythonには「例外」という機能があります。何かまずいことが発生したときに、本来のプログラムの段取りとは別に、「突然ですがここで緊急ニュースです」とでもいった調子で始まる処理のことです。どんな「例外」が発生しうるのかはそのときやっている処理によるのですが、Python-Twitterの場合は、"TwitterError"という名称の「例外」が定義されており、これが発生(raise)します。下のリンクはソースコードです。ところどころにraiseという命令が置いてあります。

python-twitter/api.py at master · bear/python-twitter · GitHub

さて、例えばtwitter.api()を呼び出してkeyからアクセス権を取得するとき「アクセスしすぎでしょエラー」が発生することがあります。15分で15回以上アクセスすると、Twitter側でそれ以上の処理を拒否するようです。この場合、しばらく待ってリトライするのが正しい処理ということになりますね。

下のようにtry~catchを使用しました。しばらく待ってリトライするので、ログに残すだけでよいはずです。なお、発生した例外に対応する処理が作られていない場合、プログラムは強制的に終了させられます。RaspiParrotのような常駐プログラムでは、これは致命的ですので注意する必要があります。

def GetAPI():
    '''
    Twitter APIを準備する部分
    '''
    global inifile
    logger.info("Twitter APIの使用を要求")
    consumer_key    = inifile.get("keys", "TWEETUSERNAME")
    consumer_secret = inifile.get("keys", "TWEETPASSWORD")
    access_key      = inifile.get("keys", "TWEETACCESSKEY")
    access_secret   = inifile.get("keys", "TWEETACCESSSECRET")
    encoding        = 'utf-8'
    try:
        api = twitter.Api(consumer_key=consumer_key,
                       consumer_secret=consumer_secret,
                       access_token_key=access_key,
                       access_token_secret=access_secret,
                       input_encoding=encoding)
    except TwitterError as e:
        logging.warning(u"twitter.Api error: %s" % ( e.message ))
    except Exception as e:
        logging.warning(u"不明なエラー")

GitHub更新しました

更新したソースコードGitHubに上げておきました。
github.com