Twitterのタイムラインから人気のあるツイートを取得、一覧表示してツイ廃を卒業しよう

# 背景
自分は多分ツイ廃でスクリーンタイム見たら一日平均約3時間近くツイッターをやってます。
一日の8分の一近くツイッターやってることになる…
まあ、自分よりもっとやばい人はいるので...
あと、気が向いたらフォローよろしくお願いします→[@y_a_m_a_y_a](https://twitter.com/y_a_m_a_y_a)
(Qiitaの連携するアカウント変更しました）

やっている内容のほとんどが人のツイートを見たり、トレンドをチェックしたり(流行には敏感なので)するタイムラインにツイートを並べるだけなので、そこの時間を減らすプログラムを作りたいなと思いました。

作成した[デモ(Twitterに動画で投稿)](https://twitter.com/y_a_m_a_y_a/status/1261218576918130688?s=20)はこちらです。

# やりたい事
1. 自分のタイムラインを取得する
2. ファボ、RTの多い順にソートする
3. 上位のツイートをHTMLで書き出す

# 環境
Google Colab(環境構築がめんどくさかった)
コードは[GitHub](https://github.com/kurikinton105/TwitterTimeLine)と[googleドライブ](https://drive.google.com/open?id=1ArdP2iEufGYFLv3VrUMR9-PS7_1Wk6SC)に載せています。

# 1. 自分のタイムラインを取得する
基本的にこの部分の説明が多くなります。

### developer登録
ツイッターのapiを使うには、developer登録する必要があります。この部分はいろんな人が書いてくれてるので、そちらを参照。
[Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ　※2019年8月時点の情報](https://qiita.com/kngsym2018/items/2524d21455aac111cdee)
学生の勉強のためのアカデミック目的なので一日ぐらいですぐ認証がおりました。

### タイムラインを取得
twitterライブラリを使うと簡単にツイッターのツイート、フォローなど色々出来ます。(Colabで使うときにはインストールしてくださいね)

はじめに認証が必要です.以下のコードでtwitterの認証を行います。


```python:AOuth.py
import twitter
# 取得したキーとアクセストークンを設定する(各自のキーを入力)
auth = twitter.OAuth(consumer_key="-------------------",
                     consumer_secret="-------------------",
                     token="-------------------",
                     token_secret="-------------------")

t = twitter.Twitter(auth=auth)
```

### ツイートを取得
次にツイートの取得です。ツイートの取得は以下のコードで実行できます。


```python:
t.statuses.home_timeline(count = 取得ツイート数)
```

で行うことができます。
jsonファイルで帰ってきます。返答例は[このページ](https://syncer.jp/Web/API/Twitter/REST_API/GET/statuses/user_timeline/)がすごく分かりやすいです。
jsonライブラリをインポートすると、jsonがリストみたいに使えます

```python:例
import json
last_id = get_data[len(get_data)-1]["id"]
```
上のコードはツイートのIDを取得しています。

Twitterのapiの制限は厳しいので、一度に取得できるツイートの数はだいたい200と決まっています。[公式リファレンス](https://developer.twitter.com/en/docs)
そこで、while文でこのコードを繰り返し読み込むことで、取得することができます。

### max_idでツイートを遡る
max_idを使うことで、指定されたツイートID以前のツイートを取得することができます。

```python:
t.statuses.home_timeline(count = 取得ツイート数 ,max_id = ツイートのid)
```

ここで注意するのは、指定したidのツイートを重複して含んでしまうことです。if文で、除外します。

これでツイートを取得できます!!!

しかしAPIの仕様で、遡れるツイートは約800ツイートと決まっているそうです…(なんてことだ...)
[Tweepyを使うと3200ツイート取得できる記事](https://www.pytry3g.com/entry/python-twitter-timeline#Cursor%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%A4%A7%E9%87%8F%E3%81%AE%E3%83%84%E3%82%A4%E3%83%BC%E3%83%88%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B)もありましたが、試したらすぐ15分のツイッターapiの制限に引っかかって使えなかったので800ツイートで諦めました…


### 時間の取得
元の考えでは、24時間ツイートを遡りたいと思ってたので、datetimeライブラリを使って時間を調べます。ツイートの時刻はdatetimeの形式ではないので、文字列操作で、無理やり変換します。それが以下の部分です。

```python:
import datetime

date_create = get_data[int(len(get_data)-1)]["created_at"] #ツイートから作成日時の取得
date_create_at = datetime.datetime(year=int(date_create[26:30]), month=int(date.month), 
　　　　　　　　　　day=int(date_create[8:10]), hour=int(date_create[11:13]),minute=int(date_create[14:16]))#ツイートの投稿時間の変換
```

時間の比較（24時間以上前になったら終了）をやりたかったので、引き算して値の比較がしやすいように秒単位に変換しています。まあ使わなかったのですが...

```python:
diff = date - date_create_at
...
if diff.seconds >= 86400 or count >15: #24時間かループの制限に引っかかる時
    break
```
ここら辺を組み合わせると現在時刻から800ツイート取得することができます!(やったね）


# ファボ、RTの多い順にソートする
次にソートをします。
ライブラリのsortを使うとアルゴリズムの効率性とか考えなくてもソートできます。
多次元のリストのソートなので、lamdaを使ってソートします。

```python:
data.sort(key=lambda data: data[5]) #ラムダ式を使ってソートする(ファボ)
```

また今回はファボ数とRT数それぞれでソートするので、data配列をコピーします。(書き出しの時にそっちの方が楽そうなので)
コピーはcopyライブラリを使います。

```python:
import copy
data_RT = copy.copy(data)
```

# 上位のツイートをHTMLで書き出す
最後に書き出しをします。
[Twitterが公式で出しているHTMLのジェネレーター](https://publish.twitter.com)を参考に作ります。urlをちゃんと指定すれば大体でもちゃんと正しく表示されることがわかったので、値を代入するだけで大丈夫です。
関数で定義します。


```python:
# ツイートからHTMLを作成（関数）
def create_html(text ,username ,userid, tweetid):
  html =  '<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">' + text + '</p>&mdash;' + username +'(@' + userid  +') <a href="https://twitter.com/' + userid + '/status/' +tweetid + '?ref_src=twsrc%5Etfw"></a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>'
  return html
```

For文で最後の10個を書き出して完成です！！

# 感想
TwitterAPIの制限が厳しくて最初の想定の24時間遡るのではなく、結果的に3時間ほどしか遡れなかったので残念。（フォロー数によってここら辺は結果が変わってくると思う）
あと、developer登録しないと各個人環境でできないのと、colabでやっているので、ファイルの生成がローカルと比べてうまく行かなかったり、改善点多めな気がします...

ツイ廃卒業はもう少し時間がかかりそうです。。。
・実行結果

<img width="802" alt="スクリーンショット 2020-05-16 15.13.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548598/d8391296-10b3-9a68-38d2-7642d803e86f.png">


# 最後にコード
レガシーコード感が...

```python:
import twitter
import json
import datetime
import copy

# ツイートからHTMLを作成（関数）
def create_html(text ,username ,userid, tweetid):
  html =  '<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">' + text + '</p>&mdash;' + username +'(@' + userid  +') <a href="https://twitter.com/' + userid + '/status/' +tweetid + '?ref_src=twsrc%5Etfw"></a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>'
  return html

# 取得したキーとアクセストークンを設定する(各自のキーを入力)
auth = twitter.OAuth(consumer_key="-------------------",
                     consumer_secret="-------------------",
                     token="-------------------",
                     token_secret="-------------------")

t = twitter.Twitter(auth=auth)

#タイムラインを取得(while文で出来るだけさかのぼる)
date = datetime.datetime.now() # 今の時間の取得
date = datetime.datetime(year=date.year, month=date.month, day=date.day, hour=date.hour,minute=date.minute)
count = 0 # 取得ツイートを数えるため
data =[] # 取得したデータを保存
#data_swap =[]
diff = date - date
print("開始時刻",date)

while(1): # データ取得の開始
  if diff.seconds >= 86400 or count >15: #24時間かループの制限に引っかかる時
    print("探索終了")
    print(count)
    break
  elif count ==0: # 一番初めの時
    get_data = t.statuses.home_timeline(count = 200)
    for i in range(len(get_data)):
      # create,"id",name,userid,text,"favorite_count","retweet_count"
      data_swap = [str(get_data[i]["created_at"]),str(get_data[i]["id"]),str(get_data[i]["user"]["name"]),str(get_data[i]["user"]["screen_name"]),str(get_data[i]["text"]),int(get_data[i]["favorite_count"]),int(get_data[i]["retweet_count"])]
      data.append(data_swap)
    last_id = get_data[len(get_data)-3]["id"] # 最後のツイートのidからそれ以前のツイートを取得するようにする
    date_create = get_data[int(len(get_data)-1)]["created_at"]
    date_create_at = datetime.datetime(year=int(date_create[26:30]), month=int(date.month), day=int(date_create[8:10]), hour=int(date_create[11:13]),minute=int(date_create[14:16]))#ツイートの投稿時間の取得
    count = count +1
  else: #それ以外の時
    get_data = t.statuses.home_timeline(count = 800, max_id = last_id)
    if len(get_data) == 0: # 制限にひかかって取得ツイートが0になった時
      print("探索終了")
      break
    for i in range(len(get_data)):
      if i >0: # max_idで指定したツイート以降を取得
        data_swap = [str(get_data[i]["created_at"]),str(get_data[i]["id"]),str(get_data[i]["user"]["name"]),str(get_data[i]["user"]["screen_name"]),str(get_data[i]["text"]),int(get_data[i]["favorite_count"]),int(get_data[i]["retweet_count"])]
        data.append(data_swap)
    last_id = get_data[len(get_data)-1]["id"] # 最後のツイートのidからそれ以前のツイートを取得するようにする
    date_create = get_data[int(len(get_data)-1)]["created_at"]
    date_create_at = datetime.datetime(year=int(date_create[26:30]), month=int(date.month), day=int(date_create[8:10]), hour=int(date_create[11:13]),minute=int(date_create[14:16]))#ツイートの投稿時間の取得
    diff = date -date_create_at
    count = count +1

print("終了時刻",date_create_at)
print("データ総数:",len(data))

# ソートする
size = len(data)
data.sort(key=lambda data: data[5]) #ラムダ式を使ってソートする(ファボ)
data_RT = copy.copy(data)
data_RT.sort(key=lambda data: data[6]) #ラムダ式を使ってソートする(RT)

# 結果の表示(HTML)
path = '/content/drive/My Drive/Colab Notebooks/TwitterAPI/' + 'data/TimeLine' +str(date.month) +'月' +str(date.day) + '日' +'.html'
with open(path, mode='w') as f:
    f.write("<H1>ファボ数が多かったツイートベスト１０！ <H1>")
    f.write("<H1>"+str(date + datetime.timedelta(hours =9)) + "~" +str(date_create_at + datetime.timedelta(hours =9)) +"<H1>")
    for i in range(10):
        f.write("<H2>第"+str(i+1)+"位!!　"+ str(data[size-1-i][5]) + "ファボ <H2>")
        f.write(create_html(data[size-1-i][4],data[size-1-i][2],data[size-1-i][3],data[size-1-i][1]))
        
    # RTの時
    f.write("<H1>RT数が多かったツイートベスト１０！ <H1>")
    for i in range(10):
        f.write("<H2>第"+str(i+1)+"位!!　"+ str(data[size-1-i][6]) + "RT <H2>")
        f.write(create_html(data_RT[size-1-i][4],data_RT[size-1-i][2],data_RT[size-1-i][3],data_RT[size-1-i][1]))
print("書き込み終了")

```