Help us understand the problem. What is going on with this article?

.NETの力でTwitterの黒歴史を葬り去りたいっ!!!

Twitterの黒歴史を葬り去りたいっ!!!

と、思ったことありますよね? 僕もそう思いました。そう思ってしまったので、プログラミングの力を使ってTwitterの黒歴史を葬り去ってしまいましょう!!!

用意するもの

自分がC#くらいしかマトモに使える言語がないのと、さくっとつくってしまいたかったので下記のデータとライブラリを使ってます。

  • Twitter データ(これが無いと本格的♂には消せない)
  • とりあえず何かしらのアプリを作っておく (https://developer.twitter.com/ で)
  • Json.NET (C#でJSON扱うならこれでしょ!!!)
  • CoreTweet (C#でTwitterするならこれでしょ!!!)

Twitter データの必要性

Twitterのツイートを削除する方法としてとりあえずポチポチ消していくのもアリかなーと思い、Androidの自動タップアプリを使って消そうと考えました。

が、どうやらTwitter公式クライアントでは最新のツイート数千件ほどしか取得できないらしく、これでは残しておきたいツイートも消さないと黒歴史ゾーンまでたどり着けません。Twitter 検索の機能であるuntilキーワードもあるけれど、よくよく考えてみたら1万ツイートある量を自動タップアプリでやらせても遅いことに気がついたので、他の方法を模索することになりました。

最終的に、Twitter データを使い過去に投稿されたIDと日時を取得することで、黒歴史を葬り去ることができることを確認できました。事前にTwitter データをリクエストし、ダウンロードしておきます。ダウンロードしたファイルを解凍したらtweet.jsがあると思います。それがツイートのデータです。これを使います。

tweet.jsの中身は、ツイートやリツイート、ツイートのやそれのID、画像に関してはサムネイルの位置まで、「Twitter データ」の名に相応しい情報が詰め込まれています。今までcsv形式でしたが、最近(Web版がリニューアルしてから?)ではjsonフォーマットとして保存されています。よりプログラムで扱いやすい形式になって良いですね☆。

プログラムの流れ

OAuth認証 → 消す範囲の取得 → tweet.jsの読み込み → 消すツイートの抽出 → 削除APIを叩く → 叩く → 叩く → ...

実際に組んでみる!!

1回しか使わないと考えてたので汚いのは許してください。例外処理なんて知ったこっちゃないです。コメントにいろいろ書いてます。

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using CoreTweet;
using Newtonsoft.Json.Linq;

namespace ByeByeTweet
{
    class Program
    {
        static void Main(string[] args)
        {
            // カレントカルチャを英語にする(Twitter データの曜日が英語なので)
            CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US");

            // なぜか残ってる
            Console.WriteLine("Hello World!");
            // Twitter アプリのコンシューマーキーとシークレット
            var session = OAuth.Authorize("hogehoge", "piyopiyo");
            // アプリ認証用URLを表示させる
            Console.WriteLine("Access to {0}, and get PIN code.", session.AuthorizeUri.AbsoluteUri);
            Console.Write("PIN code:");
            var pin = Console.ReadLine();

            // 認証させる
            var token = OAuth.GetTokens(session, pin);

            Console.WriteLine("ツイートをどこまでけすか入力。例:Fri May 12 12:00:00 +0000 2018");
            var date = Console.ReadLine();

            // どこまで消すかのDateTime構造体を取得しておく
            var dateTime = GetDate(date);

            Console.WriteLine("ここまで消します:{0}", dateTime.ToString());

            Console.Write("tweet.jsのパス:");

            var path = Console.ReadLine();

            var file = System.IO.File.ReadAllText(path);

            // tweet.jsの冒頭にある文字を消してプレーンなjsonにするために、最初にくる[までなかったことにする。
            file = file.Substring(file.IndexOf("[") - 1);

            // パースしてあげる。
            var json = JArray.Parse(file);

            // すべてのツイートを必要な情報だけList<Tweet>にいれておく
            var list = new List<Tweet>();

            for (int i = 0; i < json.Count; i++)
            {
                var tweet = new Tweet();
                tweet.ID = (string)json[i]["id"];
                tweet.Date = (string)json[i]["created_at"];
                tweet.Text = (string)json[i]["full_text"];
                list.Add(tweet);
            }

            // 削除対象のList<Tweet>。処理の簡単のために別のListに。
            var deleteList = new List<Tweet>();

            foreach (var item in list)
            {
                // ツイートの時刻からDateTime構造体を取得して、先ほど指定した時刻より小さかったら?古かったら削除対象リストに入れる。
                var thisDate = GetDate(item.Date);
                if (thisDate < dateTime)
                {
                    deleteList.Add(item);
                }
            }

            // わざわざ言ってくれるの親切。
            Console.WriteLine("実際に消していきます。");

            foreach (var item in deleteList)
            {
                // キタ!ついに例外処理を始めたぞ!!!
                try
                {
                    // 削除APIを叩く。long型なので変換してやってね
                    token.Statuses.Destroy(Convert.ToInt64(item.ID));
                    // 削除できたっぽいので教えてあげる。
                    Console.WriteLine("削除しました: {0} / {1} / {2}", item.ID, item.Date, item.Text);
                }
                catch (CoreTweet.TwitterException)
                {
                    // よくわかんないけど、ツイートがすでに存在しなかったらこの例外が投げられるのでcatch。
                    // ざんねん!見つからなかったと教えてあげよう。
                    Console.WriteLine("見つかりませんでした: {0} / {1} / {2}", item.ID, item.Date, item.Text);
                }
                // 1秒間に何度も叩かれるとTwitterさんが困っちゃうと思うので、1000ミリ秒お休みしてもらう
                Thread.Sleep(1000);
            }

            // 入力待ちでポーズ。
            Console.ReadLine();

        }

        private static DateTime GetDate(string date)
        {
            // Twitter データのフォーマットがこれなので、これでDateTime構造体に変換してあげる。
            var format = "ddd MMM dd HH:mm:ss K yyyy";
            // 普通のDateTime.Parseじゃあ多分例外吐く。
            var dateTime = DateTime.ParseExact(date, format, null);
            return dateTime;
        }

        // IDと時間を保持しておくクラス。内容は表示用のおまけ。
        public class Tweet
        {
            public string ID;
            public string Date;
            public string Text;
        }
    }
}

苦労した……ポイント

  • DateTime.Parseじゃ変換できない(多分) → 自前でフォーマットを用意して、DateTime.ParseExactで変換させる。
  • ちなみにdddが省略形の曜日でMMMが省略形の月で、Kが時差を表してます。あとは普通の日付フォーマット。

……あれ?そのくらいかも?

こういうところが改善できる!

  • ~まで ではなく、 ~から~までと範囲選択できるようにする
  • TweetDeckの検索機能のように、リツイート・いいねがn件以上されていたら消さない(n:自然数)
  • 特定のクライアントからツイートされたものを削除する (TweetDeck, Twitter for Android, とか……)

これらすべてはtweet.jsから取得できる内容なので、簡単に応用が利くと思います!

まだいろいろ改善できそうですね!これらを実装してだれでも使えるようにGUIアプリ化しても面白いと思います!知らんけど!!

さいごに

Screenshot_20190917-021915_Twitter.jpg
Screenshot_20190917-132000_Twitter.jpg

過去の黒歴史に……さよならバイバイ!(めざせ!ツイッタラー)

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away