PythonのTwitter制御ライブラリTweepy〜同じ内容を連続してツイートできないバグの修正〜

目次

Tweepy

前回、PythonでTwitterを制御するためのライブラリTweepyを使って特定の期間内のツイートをリツイートしてくれたユーザーに感謝ツイートをするプログラムをダブルクリックで実行できる形式に変更しました。

ただ何回も試していると、どうやら同じ内容を連続してツイートしようとしてしまい、それがTwitterの仕様上できないことで、エラーが出てしまうということが分かりました。

ということで今回はこのバグを修正していきましょう。

まずは前回のおさらいから。

<セル1>

import tweepy
import datetime

account = "@Nori_3PySci"
check_days = 1

time_now = datetime.datetime.now()

consumer_key = 'API keyを入力'
consumer_secret = 'API key secretを入力'
access_token = 'Access tokenを入力'
access_token_secret = 'Access token secretを入力'

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)

api = tweepy.API(auth)
<セル2>

def tweet_check(account, check_days, time_now):
    
    tweets = tweepy.Cursor(api.user_timeline, id=account).items(100)

    rt_ids = []

    for tw in tweets:
        if time_now - (tw.created_at + datetime.timedelta(hours=9)) <= datetime.timedelta(days=check_days):
            if (tw.text.startswith('RT')) or (tw.text.startswith('@')):
                pass
            else:
                if tw.retweet_count >= 1:
                    rt_ids.append(tw.id)

    return rt_ids
<セル3>

def rtuser_check(rt_ids):
    
    rt_users = []

    for ids in rt_ids:
        retweets = api.retweets(id=ids)
        for rt in retweets:
            rt_users.append("@" + rt.user.screen_name)

    return rt_users
<セル4>

def rtuser_tweet(rt_users):

    if len(rt_users) != 0:
        tweet_content = '\n'.join(rt_users[:10])
        api.update_status("(APIテスト中)\n今日もみなさんのリツイート、ありがとうございます!\n\n" +  tweet_content + "\n\n#RT感謝砲") 
    elif len(rt_users) == 0:
        api.update_status("(APIテスト中)\n今日は残念ながら、リツイートありませんでした...\n\n#RT感謝砲")
<セル5>

def main(account, check_days, time_now):
    rt_ids = tweet_check(account, check_days, time_now)
    rt_users = rtuser_check(rt_ids)
    rtuser_tweet(rt_users)
<セル6>

if __name__ == '__main__':
    main(account, check_days, time_now)

問題のエラー

今回の問題は同じ内容をツイートしようとするとエラーが返ってきてツイートできないという問題です。

これは先ほどにも少しお話ししましたが、Twitterの仕様上できないことになっています。

多分、昔、botや詐欺アカウントなんかで同じ内容を何度も繰り返してツイートされていたことから、規制されたのだと考えられます。

まずは出てきたエラーを見てみましょう。

---------------------------------------------------------------------------
TweepError                                Traceback (most recent call last)
<ipython-input-29-d8c9015c0404> in <module>
      1 if __name__ == '__main__':
----> 2     main(account, check_days)

<ipython-input-26-1a05e6f0f343> in main(account, check_days)
      4     rt_users = rtuser_check(rt_ids)
      5 #     print(rt_users)
----> 6     rtuser_tweet(rt_users)

<ipython-input-25-38c825b59c44> in rtuser_tweet(rt_users)
      5         api.update_status("(APIテスト中)\n今日もみなさんのリツイート、ありがとうございます!\n\n" +  tweet_content + "\n\n#RT感謝砲")
      6     elif len(rt_users) == 0:
----> 7         api.update_status("(APIテスト中)\n今日は残念ながら、リツイートありませんでした...\n\n#RT感謝砲")

/opt/anaconda3/lib/python3.7/site-packages/tweepy/api.py in update_status(self, *args, **kwargs)
    216                            'card_uri'],
    217             require_auth=True
--> 218         )(*args, **kwargs)
    219 
    220     def media_upload(self, filename, *args, **kwargs):

/opt/anaconda3/lib/python3.7/site-packages/tweepy/binder.py in _call(*args, **kwargs)
    251                 return method
    252             else:
--> 253                 return method.execute()
    254         finally:
    255             method.session.close()

/opt/anaconda3/lib/python3.7/site-packages/tweepy/binder.py in execute(self)
    232                     raise RateLimitError(error_msg, resp)
    233                 else:
--> 234                     raise TweepError(error_msg, resp, api_code=api_error_code)
    235 
    236             # Parse the response payload

TweepError: [{'code': 187, 'message': 'Status is a duplicate.'}]

「TweepError: [{‘code’: 187, ‘message’: ‘Status is a duplicate.’}]」とあることから、同じ内容が2度続けて投稿されたものによるエラーだと分かります。

ではこれを修正するにはどうしたらいいでしょうか?

ツイートの日時を入力

問題点は「同じ内容の投稿」になってしまったことにあります。

ということは2つ目のツイートが「違う内容の投稿」になればいいわけです。

その一番簡単な方法としては、ツイートに日時を入れることでしょう。

日にちを入れれば次の日になれば「違う内容の投稿」になりますし、何時何分まで入れれば1分経てば「違う内容の投稿」になります。

それでもまだ被る可能性を考えると秒まで入れてしまうのが現実的にいいところかなと思います。

もっと細かくマイクロ秒まで入れてしまうとちょっと見た目がごちゃごちゃしますし、そんなに連続投稿はしないだろうと考えられます。

ということで修正をしていきましょう。

修正するのは<セル4><セル5>です。

<セル4>では現在時間(time_now)を入力するようにし、その時間を含めたツイートをするように変更します。

<セル4 修正>

def rtuser_tweet(rt_users, time_now):

    if len(rt_users) != 0:
        tweet_content = '\n'.join(rt_users[:10])
        api.update_status("(APIテスト中)\n今日もみなさんのリツイート、ありがとうございます!\n\n" +  tweet_content + "\n\n" + time_now.strftime("%Y/%m/%d %H:%M:%S") + "\n\n#RT感謝砲") 
    elif len(rt_users) == 0:
        api.update_status("(APIテスト中)\n今日は残念ながら、リツイートありませんでした..." + "\n\n" + time_now.strftime("%Y/%m/%d %H:%M:%S") + "\n\n#RT感謝砲")

ちなみに変数time_nowにはdatetime形式の数字が格納されているので、str型に変更し、なおかつ表示するフォーマットを整える必要があります。

そこで追加する時間を「time_now.strftime(“%Y/%m/%d %H:%M:%S”)」としています。

<セル5>ではrtuser_tweetの関数にtime_nowを入力するように変更します。

<セル5 修正>

def main(account, check_days, time_now):
    rt_ids = tweet_check(account, check_days, time_now)
#     print(rt_ids)
    rt_users = rtuser_check(rt_ids)
#     print(rt_users)
    rtuser_tweet(rt_users, time_now)

これで確かに問題なくツイートできました。

ただJupyter notebookを使っている場合の注意点として、<セル6>だけを2回連続して実行した場合、<セル1>が実行されておらず現在時間を取得していないので、同じ内容を連続してツイートしてしまうことになりエラーとなります。

実際、運用する場合は全体のプログラムが実行される形で運用しますので、問題ないと考えられます。

これでプログラミングは完了したので、プログラムを保存しておくのですが、普通の保存だけではなく、Pythonの実行形式(.py)でも保存しておきましょう。

そのためには File > Download as > Python (.py) をクリックして、プログラムを保存します。

それでは次回はMacを使って定期的にこのプログラムを実行するように設定していきましょう。

ではでは今回はこんな感じで。

よかったらシェアしてね!

コメント

コメントする

目次
閉じる