メンヘラすぎて無視されたツイートは消したい
これは私ではないが、こういうツイートを消したい
自分がモテないのも、もしかして瀧さんのせいですか?
— ねっとのひと (@_tanosikuikouze) April 6, 2020
- 無視されるよりは無視したほうが良いという、被害者より加害者よりの思考へシフトし、陽キャよりのコミュニケーションにコミットを行う
- これはセキュリティ・オートメーションに対してのコミュニティ・オートメーションであり、ある意味革命である
- もちろん例にあげた公式垢にクソリプを送るのは対象外で、日常のTwitterコミュニケーションにおける無視されたツイートが対象である
削除対象はこれ
- 無視されたツイート
- リプライをしたが、リプライが返ってこないか、ふぁぼられていないツイート
- 具体的にはこんなのの下のほうにある、ふぁぼられてないしリプライもされてないツイート
簡単な解説
-
Tweet1がTweet2にリプライした場合、図の通りTweet2にはリプライされたというフラグが存在しない為、下記手順で抽出する必要がある
- user_timelineからふぁぼ・RTされていないツイートを抽出
- mentions_timelineから直近のリプライを取得し、in_reply_to_status_id(リプライされたツイート)の一覧を取得する
- 2つを突合してリプライされていない、かわいそうなツイートを抽出する
- かわいそうだが、それらを消す
-
API取得上限の問題
- user_timelineは一度の取得上限が3200件
- mentions_timelineは一度の取得上限が800件
- そのままぶつけるとuser_timelineが圧倒的に多く、問題がある
- user_timeline =< mentions_timelineにしたい
-
できるなら毎日ジョブで消したいが、面倒なのでサーバーは立てたくない
- そこでAWS Lambdaなら簡単だし、無料
前提条件
- TwitterのAPIキーを発行済み
- 英作文はググればいくらでも出てくるから頑張る
- AWSのアカウントを作成済み
- AWS CLIを使えるようにしておく
インフラの構築
フォルダ構造
DeleteNoReactionTweet
| lambda.yml
| README.md
|
\---code
DeleteNoReactionReply.py
パラメーターは外だしして再利用できるようにする
-
NoEcho
をつけるとセキュアだが、Lambdaのコンソールで環境変数は見えてしまうので、あまり意味がない - SSMパラメータストアやKMSを使うとよりにセキュアにできるみたいだが、今回はそこまでしない
AWSTemplateFormatVersion: '2010-09-09'
# Twitter API Key
Parameters:
ConsumerKey:
Type: String
NoEcho: true
ConsumerSecret:
Type: String
NoEcho: true
AccessKey:
Type: String
NoEcho: true
AccessSecret:
Type: String
NoEcho: true
Lambda,IAM Role,Rule,Permissionの設定
Resources:
# Lambda
Lambda:
Type: 'AWS::Lambda::Function'
Properties:
Code: code # カレントディレクトリ下のcodeフォルダを読み込む
Environment: # Lambda環境変数
Variables:
ConsumerKeyVar: !Ref ConsumerKey
ConsumerSecretVar: !Ref ConsumerSecret
AccessKeyVar: !Ref AccessKey
AccessSecretVar: !Ref AccessSecret
Description: DeleteNoReactionReply
FunctionName: DeleteNoReactionReply
Handler: DeleteNoReactionReply.lambda_handler
MemorySize: 128
Role: !Sub
- arn:aws:iam::${AWS::AccountId}:role/${roleName}
- { roleName: !Ref LambdaRole }
Runtime: python3.8
Timeout: 180
# CloudWatchEvents Rule
Rule:
Type: 'AWS::Events::Rule'
Properties:
Description: DeleteNoReactionReplyRule
Name: DeleteNoReactionReplyRule
ScheduleExpression: 'cron(0 18 * * ? *)' # 夜中三時に消す
State: ENABLED
Targets:
- Arn: !GetAtt Lambda.Arn
Id: lambda
# Lambda IAM Role
LambdaRole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: DeleteNoReactionReplyRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# CloudWatchEvents Lambda excute enable
LambdaEvent:
Type: 'AWS::Lambda::Permission'
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: !Ref Lambda
Principal: 'events.amazonaws.com'
SourceArn: !GetAtt Rule.Arn
Pythonで削除スクリプトを書く
import tweepy
import os
# API Key デプロイ時にCLIで指定する
consumer_key = os.environ['ConsumerKeyVar']
consumer_secret = os.environ['ConsumerSecretVar']
access_key = os.environ['AccessKeyVar']
access_secret = os.environ['AccessSecretVar']
# Tweepy Auth
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_key, access_secret)
api = tweepy.API(auth)
myReplyTweet = []
mentionInReplyTweet = []
noDeleteTweet = []
deleteTweet = []
# Get My Reply
print("==========Get My Reply==========")
for tweet in tweepy.Cursor(api.user_timeline,exclude_replies = False,include_rts = False).items(200): # あふれない程度に
if "@" in tweet.text and tweet.favorite_count == 0 and tweet.retweet_count == 0:
print(tweet.id,tweet.created_at,tweet.text.replace('\n',''),tweet.favorite_count,tweet.retweet_count)
myReplyTweet.append(tweet.id)
# Get in_reply_to_status_id in mentions
print("==========Reply Tweet==========")
for mentions in tweepy.Cursor(api.mentions_timeline).items(400): # 800まで
print(mentions.id,mentions.created_at,mentions.text.replace('\n',''))
mentionInReplyTweet.append(mentions.in_reply_to_status_id)
# Extraction Delete Tweet
print("==========Extraction Delete tweet==========")
for mntnrptw in mentionInReplyTweet:
for myrptw in myReplyTweet:
if mntnrptw == myrptw:
deleteTweet.append(myrptw)
preparateDeleteTweet = set(myReplyTweet) ^ set(deleteTweet)
print(list(preparateDeleteTweet))
# Delete Tweet
print("==========delete tweet==========")
for deltw in preparateDeleteTweet:
print(api.get_status(deltw).id,api.get_status(deltw).created_at,api.get_status(deltw).text)
api.destroy_status(deltw)
AWSへのデプロイ
- Tweepyは外部モジュールなので同梱する
pip install tweepy --target ./code
- パッケージにしてS3に転送
aws cloudformation package --s3-bucket $YourBucketName `
--template-file lambda.yml `
--output-template-file lambda-packaged.yml
- インフラ構築とデプロイ
- ここでTwitterのAPI KEYをLambdaの環境変数に指定する
aws cloudformation deploy `
--template-file lambda-packaged.yml `
--stack-name $YourStackName `
--parameter-overrides AccessSecret=$YourAccessSecret `
ConsumerKey=$YourConsumerKey `
ConsumerSecret=$YourConsumerSecret `
AccessKey=$YourAccessKey `
--capabilities CAPABILITY_NAMED_IAM
- マネコンから確認する
GitHubにあげた完全版
張っておきます。
https://github.com/natsukawadaisuki/DeleteNoReactionReply
そもそも
- フォロワーが無視しなければいい