LoginSignup
1
1

More than 5 years have passed since last update.

Pythonで黒歴史クリーナーを作ってみた。

Posted at

Twitterやってる人なら一度は耳にした事があるであろう「黒歴史クリーナー
僕も黒歴史ツイートとか消し去りたいので作ってみました。

向き合わなきゃいけないのは分かってても、
消したい過去もある。

手順

プログラム実行する前にやる事があるので、まずは準備から。
前提として、Python3の実行環境が整っているものとします。
それ以外に、やらなきゃいけないのは以下です。

  • 各種キー情報の取得(参考記事)
    • Consumer Key (API Key)
    • Consumer Secret (API Secret)
    • Access Token
    • Access Token Secret
  • データ取得(参考記事)
    • 過去全てのツイートデータ
  • Pythonの外部ライブラリ取得
    • pip install pandas
    • pip install requests
    • pip install requests-oauthlib

実際のコード

deleteTweets.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
# 実行コマンド
> python deleteTweets.py {%Y} {%m} {%account_id}

#パラメータ説明
%Y: 処理終了年(未設定の場合は最初から最後までが対象)
%m: 処理終了月(未設定の場合は最初から最後までが対象)
%account_id: 対象アカウントID(特定の相手とのやりとりを消去したい場合に設定)
"""

import sys
import pandas as pd
from requests_oauthlib import OAuth1Session
from time import sleep

# 取得してきた各種キー情報を設定 ※※キー情報は他の人に教えちゃダメだよ!悪用されるよ!※※
twitter = OAuth1Session(
    client_key="XXXXXXXXXX",
    client_secret="XXXXXXXXXX",
    resource_owner_key="XXXXXXXXXX",
    resource_owner_secret="XXXXXXXXXX"
)

# ファイル食って、列['timestamp']をdatetime型にしておく
df = pd.read_csv("twieeted/tweets.csv")
df['timestamp'] = pd.to_datetime(df['timestamp'])

# 削除済みIDを読んで、DataFrameから消しておく
f = open("deleted_ids.txt")
deleted_ids = str(f.read()).split(",")
f.close()
print("started len(deleted_ids): {}".format(len(deleted_ids)))
for deleted_id in deleted_ids:
    if "" != deleted_id:
        df = df[df["tweet_id"] != int(deleted_id)]
deleted_ids = []

# 処理開始年月〜処理終了年月まで処理する
# - 処理終了年月が設定されてない場合は最後まで
start_y = int(min(df['timestamp']).strftime("%Y"))
start_m = int(min(df['timestamp']).strftime("%m"))
max_y   = int(sys.argv[1]) if 2 <= len(sys.argv) else 0
max_m   = int(sys.argv[2]) if 3 <= len(sys.argv) else 0
try:
    while True:
        # 処理対象年月のツイートのみに絞る(元オブジェクトに影響が及ばないように別オブジェクトに作成)
        tweets = df[df["timestamp"].dt.year == start_y]
        tweets = tweets[tweets["timestamp"].dt.month == start_m]
        if len(tweets) <= 0:
            print("bye:)")
            break
        print("processing... {}/{}".format(start_y, start_m))


        """
        XXX ここは毎回変えないといけない。正規表現部分だけ外出しすればいいんだろうけど、面倒臭い。ごめん。
        設定例:
          先頭が"RT"で始まるツイート(=RT):
            "^RT.*"
          先頭が"RT"で始まらないツイート(=RT以外)
            "^(?!RT).*"
          先頭が"@"で始まるツイート(=リプライ)
            "^@.*"
          先頭が"@"で始まらないツイート(=リプライ以外)
            "^(?!@).*"
        """
        # 指定された正規表現に従って、ツイートを絞り込み
        tweets = tweets[tweets["text"].str.contains("^(?!RT @).*$")]  # 中の正規表現を変えて使ってね。ごめんね。
        if 3 <= len(sys.argv):
            tweets = tweets[tweets["text"].str.contains(sys.argv[3])]


        # 1秒ごとにTwitterAPIを呼び出して削除する
        # - 削除に失敗(!=200)の場合は、削除済みリストに入れないよう留意
        # - すぐに削除せず、どういうツイートが取れるのか見たい時は、sleep以降をコメントアウトすると良い
        if 0 < len(tweets):
            for index, row in tweets.iterrows():
                print("{} - {} : {}".format(row["timestamp"], row["tweet_id"], row["text"]))
                sleep(1)
                res = twitter.post("https://api.twitter.com/1.1/statuses/destroy/{}.json".format(int(row["tweet_id"])))
                if res.status_code == 200 or res.status_code == 404:
                    deleted_ids.append(row["tweet_id"])
                if res.status_code != 200:
                    print("       - [{}]: {}".format(res.status_code, res.json()))

        # 処理終了年月になった場合はbye
        if start_m == 12:
            start_y += 1
            start_m = 1
        else:
            start_m += 1
        if start_y == max_y and start_m == max_m:
            print("bye:)")
            break

finally:
    # 削除対象IDをファイルに書いて終了
    # (元CSVをpandas.to_csv()で書き込んだら、データ型が変わってしまって再利用できなかったので苦肉の策。ごめん。)
    print("finished len(deleted_ids): {}".format(len(deleted_ids)))
    if 0 < len(deleted_ids):
        f = open("deleted_ids.txt", "a")
        f.write("{}".format(deleted_ids)
                .replace("[", "")
                .replace("]", "")
                .replace("'", "")
                .replace(" ", ""))
        f.write(",")
        f.close()

ソースコードコメント多くてすみません。
あれこれ手探りで、やっつけで作ったので、「何でこうしたの?」って部分が多くなったので、書いといた方が親切かなと思って書いてます。。。


というか、過去ツイートの黒歴史がうじゃうじゃ出てきて気持ち悪い...
いや、ツイートしたのは自分なんだけど。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1