【Python】Twitterで捨て垢からリプが来たらブロックするツールを作る【ChatGPT】

最近Twitterをしていると捨て垢で嫌がらせをしてくる知的障害者の方がいるため、その対策と、プログラミングの勉強も兼ねてタイトル通りのツールを作ってみることにしました。

やりたいこと

  1. 自分宛てリプを取得
  2. そのアカウントのIDと登録日を取得
  3. 直近3日内に作成されたアカウントの場合ブロックする

上記3ステップ1分ごとにスケジューラ実行でしょうかね。
今はTwitterAPIの制限が激しくなったらしいので無料でできる範囲だと1時間に1回かもしれません。知らんけど。
Twitterの仕様を知らんので、ブロック済みかどうかを管理する必要があるかも知りません。

知らんけど作ってみましょう。たぶん大丈夫でしょう。

Pythonインストール

https://www.python.org/ftp/python/3.10.10/python-3.10.10-amd64.exe

3.10.10をインストールします。ちょっとだけ古いやつ。

ChatGPT4に聞く

ここからは、引用符で括っているのが私がChatGPT4に投げた命令(質問)です。

ツイッターでリプライを送ってきているアカウントの一覧を取得し、そのアカウント作成日が最近3日の場合はブロックをするpythonプログラムを書いてください。

次の返事が来ました。

ご要望のプログラムを作成することができます。ただし、Twitter APIキーが必要です。お持ちですか?

import tweepy
from datetime import datetime, timedelta

# あなたのTwitter APIキーを入力してください
consumer_key = 'YOUR_CONSUMER_KEY'
consumer_secret = 'YOUR_CONSUMER_SECRET'
access_token = 'YOUR_ACCESS_TOKEN'
access_token_secret = 'YOUR_ACCESS_TOKEN_SECRET'

# Tweepy APIの認証
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

# リプライを送ってきているアカウントの一覧を取得
mentions = api.mentions_timeline()
for mention in mentions:
    user = mention.user
    created_at = user.created_at
    # アカウント作成日が最近3日の場合はブロック
    if created_at > datetime.now() - timedelta(days=3):
        api.create_block(user.id)

当然ですが、APIキーは自分で用意します。
あとtweepyもインストールしておきます。

少し修正指示をする

このプログラムは動きません。

タイムゾーンの考慮ができていなかったり、tweepyのブロックの書き方が間違っています。
こういう修正指示も、エラー内容をコピペしてどうやって直せばいいかChatGPT4にやらせます。

ちなみにこの修正指示をする前にログ出力機能を追加命令しているので、次のコードで突然ログ機能が入ってます。勝手に入ったものではありません。

このプログラムは、「if created_at > datetime.now() – timedelta(days=3):」の行にて、「TypeError: can’t compare offset-naive and offset-aware datetimes」のエラーが発生します。修正方法はありますか

はい、そのエラーは、created_atがタイムゾーン情報を持つ一方で、datetime.now()がタイムゾーン情報を持たないために発生します。この問題を解決するには、datetime.now()をdatetime.utcnow()に変更するか、pytzライブラリを使用して、datetime.now()にタイムゾーン情報を追加することができます。

以下は、datetime.utcnow()を使用して修正したプログラムです。

import tweepy
from datetime import datetime, timedelta

# あなたのTwitter APIキーを入力してください
consumer_key = 'YOUR_CONSUMER_KEY'
consumer_secret = 'YOUR_CONSUMER_SECRET'
access_token = 'YOUR_ACCESS_TOKEN'
access_token_secret = 'YOUR_ACCESS_TOKEN_SECRET'

# Tweepy APIの認証
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

# ログファイルのパス
log_file_path = 'C:/log.txt'

# リプライを送ってきているアカウントの一覧を取得
mentions = api.mentions_timeline()
for mention in mentions:
    user = mention.user
    created_at = user.created_at
    # アカウント作成日が最近3日の場合はブロック
    if created_at > datetime.utcnow() - timedelta(days=3):
        api.create_block(user.id)
        # ログを出力
        with open(log_file_path, 'a') as f:
            f.write(f'{datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")} Blocked user: {user.id}, created at: {created_at}\n')

先ほどと同じエラーが発生します

ごめんなさい、私のミスです。created_atがタイムゾーン情報を持つため、datetime.utcnow()を使用しても同じエラーが発生します。この問題を解決するには、pytzライブラリを使用して、datetime.now()にタイムゾーン情報を追加する必要があります。

以下は、pytzライブラリを使用して修正したプログラムです。

import tweepy
from datetime import datetime, timedelta
import pytz

# あなたのTwitter APIキーを入力してください
consumer_key = 'YOUR_CONSUMER_KEY'
consumer_secret = 'YOUR_CONSUMER_SECRET'
access_token = 'YOUR_ACCESS_TOKEN'
access_token_secret = 'YOUR_ACCESS_TOKEN_SECRET'

# Tweepy APIの認証
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

# ログファイルのパス
log_file_path = 'C:/log.txt'

# リプライを送ってきているアカウントの一覧を取得
mentions = api.mentions_timeline()
for mention in mentions:
    user = mention.user
    created_at = user.created_at
    # アカウント作成日が最近3日の場合はブロック
    now = datetime.now(pytz.utc)
    if created_at > now - timedelta(days=3):
        api.create_block(user.id)
        # ログを出力
        with open(log_file_path, 'a') as f:
            f.write(f'{now.strftime("%Y-%m-%d %H:%M:%S")} Blocked user: {user.id}, created at: {created_at}\n')

pytzもインストールします。

ここまでは私は手元で「api.create_block(user.id)」だけコメントアウトしてテストしていました。
これでエラーが出なくなったので、あとはブロック対象かそうでないかをログで判断できるようにし、それからブロック命令を実行するようにします。

ログを出力するタイミングと内容を変えてください。 具体的には、ブロックした、ブロックしていない、両方を出力してください。

ご要望の通り、ログを出力するタイミングと内容を変更しました。以下が修正後のプログラムです。

import tweepy
from datetime import datetime, timedelta
import pytz

# あなたのTwitter APIキーを入力してください
consumer_key = 'YOUR_CONSUMER_KEY'
consumer_secret = 'YOUR_CONSUMER_SECRET'
access_token = 'YOUR_ACCESS_TOKEN'
access_token_secret = 'YOUR_ACCESS_TOKEN_SECRET'

# Tweepy APIの認証
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

# ログファイルのパス
log_file_path = 'C:/log.txt'

# リプライを送ってきているアカウントの一覧を取得
mentions = api.mentions_timeline()
for mention in mentions:
    user = mention.user
    created_at = user.created_at
    # アカウント作成日が最近3日の場合はブロック
    now = datetime.now(pytz.utc)
    if created_at > now - timedelta(days=3):
        api.create_block(user.id)
        # ブロックした場合のログを出力
        with open(log_file_path, 'a') as f:
            f.write(f'{now.strftime("%Y-%m-%d %H:%M:%S")} Blocked user: {user.id}, created at: {created_at}\n')
    else:
        # ブロックしなかった場合のログを出力
        with open(log_file_path, 'a') as f:
            f.write(f'{now.strftime("%Y-%m-%d %H:%M:%S")} Not blocked user: {user.id}, created at: {created_at}\n')

これでいい感じにログが出てきたので、手元でコメント合うとしていたブロック命令を実行します。するとエラーになりました。

API.create_block() takes 1 positional argument but 2 were given このエラーが発生しました。

ごめんなさい、私のミスです。api.create_block()メソッドは、user_id引数をキーワード引数として受け取ります。以下が修正後のプログラムです。

import tweepy
from datetime import datetime, timedelta
import pytz

# あなたのTwitter APIキーを入力してください
consumer_key = 'YOUR_CONSUMER_KEY'
consumer_secret = 'YOUR_CONSUMER_SECRET'
access_token = 'YOUR_ACCESS_TOKEN'
access_token_secret = 'YOUR_ACCESS_TOKEN_SECRET'

# Tweepy APIの認証
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

# ログファイルのパス
log_file_path = 'C:/log.txt'

# リプライを送ってきているアカウントの一覧を取得
mentions = api.mentions_timeline()
for mention in mentions:
    user = mention.user
    created_at = user.created_at
    # アカウント作成日が最近3日の場合はブロック
    now = datetime.now(pytz.utc)
    if created_at > now - timedelta(days=3):
        api.create_block(user_id=user.id)
        # ブロックした場合のログを出力
        with open(log_file_path, 'a') as f:
            f.write(f'{now.strftime("%Y-%m-%d %H:%M:%S")} Blocked user: {user.id}, created at: {created_at}\n')
    else:
        # ブロックしなかった場合のログを出力
        with open(log_file_path, 'a') as f:
            f.write(f'{now.strftime("%Y-%m-%d %H:%M:%S")} Not blocked user: {user.id}, created at: {created_at}\n')

これで完成しました。
これを作ろうとTwitterで語っていたらストーカーが来なくなったので最後のブロックテストに困りました。
なのでしばらく待ってたところ「口先だけで自動ではしてないんだな」みたいなことを言いにまた来たので、このアカウントを使って試しました。ツール実行してブロックされていること確認し、手動でブロック外して再確認したり。問題なさそうです。

Windowsスケジューラ実行

問題なく動きそうなのであとは1時間に1回くらい走らせておきます。TwitterAPIの制限を知らないので、1分に1回とかだと怖いです。1時間に1回なら大丈夫でしょう。

と思ったのですがこのプログラムは直近20件しか取得しないので、1時間に1回だと私のTwitterアカウント規模だと取りこぼしが発生します。制限知りませんが3分に1回とかの方がいいでしょうね。TwitterAPI的には直近200件までなら引数で渡せばサッと落ちてくるそうですので、そのように修正もありでしょう。

ついでに引用リプライも対象にする

リプライだけでなく、引用リプライもブロック対象にするようにしてください。

ご要望の通り、引用リプライもブロック対象にするようにプログラムを修正しました。以下が修正後のプログラムです。

import tweepy
from datetime import datetime, timedelta
import pytz

# あなたのTwitter APIキーを入力してください
consumer_key = 'YOUR_CONSUMER_KEY'
consumer_secret = 'YOUR_CONSUMER_SECRET'
access_token = 'YOUR_ACCESS_TOKEN'
access_token_secret = 'YOUR_ACCESS_TOKEN_SECRET'

# Tweepy APIの認証
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)

# ログファイルのパス
log_file_path = 'C:/log.txt'

# リプライと引用リプライを送ってきているアカウントの一覧を取得
mentions = api.mentions_timeline(include_entities=True, tweet_mode='extended')
for mention in mentions:
    user = mention.user
    created_at = user.created_at
    # アカウント作成日が最近3日の場合はブロック
    now = datetime.now(pytz.utc)
    if created_at > now - timedelta(days=3):
        api.create_block(user_id=user.id)
        # ブロックした場合のログを出力
        with open(log_file_path, 'a') as f:
            f.write(f'{now.strftime("%Y-%m-%d %H:%M:%S")} Blocked user: {user.id}, created at: {created_at}\n')
    else:
        # ブロックしなかった場合のログを出力
        with open(log_file_path, 'a') as f:
            f.write(f'{now.strftime("%Y-%m-%d %H:%M:%S")} Not blocked user: {user.id}, created at: {created_at}\n')
    
    # 引用リプライの場合は、引用元ツイートのユーザーもブロック対象にする
    if mention.is_quote_status:
        quoted_status = mention.quoted_status
        quoted_user = quoted_status.user
        quoted_created_at = quoted_user.created_at
        if quoted_created_at > now - timedelta(days=3):
            api.create_block(user_id=quoted_user.id)
            # ブロックした場合のログを出力
            with open(log_file_path, 'a') as f:
                f.write(f'{now.strftime("%Y-%m-%d %H:%M:%S")} Blocked user: {quoted_user.id}, created at: {quoted_created_at}\n')
        else:
            # ブロックしなかった場合のログを出力
            with open(log_file_path, 'a') as f:
                f.write(f'{now.strftime("%Y-%m-%d %H:%M:%S")} Not blocked user: {quoted_user.id}, created at: {quoted_created_at}\n')

今のところストーカーは引用リプライでは来ていないのでこれは動作確認していませんが、来たら確認の上で追加します。またストーカーが捨て垢をしばらく寝かせて運用するようにすれば、しきい値を変えればいいだけですね。

ChatGPTプログラミング、驚くほど楽ですね。

コメント コメントは承認制です。

タイトルとURLをコピーしました