Twitterでいいねを押したツイートに含まれる画像と動画をダウンロードしてGoogle Driveにアップロードする

#はじめに

初心者ながら2度目の投稿です。温かい目で見守っていただければとおもいます。
[GitHub](https://github.com/kotaromz/SavePicsAndVideosYouLiked)にあげてます。

好きなアーティストや芸能人、スポーツ選手等のツイートに添付されている画像や動画を保存したいってことありますよね。それをプログラムでどうにかできないかなぁと思って作ってみました。

#概要

TwitterのユーザIDを指定してその人がいいねしたツイートに含まれる画像・動画を一度ローカルのフォルダにダウンロードして、その後Google Driveの指定フォルダにアップロードします。cmdからpythonコマンドを叩いて動くものになっています。一定間隔で動くとか常時起動とかその辺りは対応できていません。いずれは対応したいのですが、[質問](#質問)にある問題が残っているので、、、

TwitterのAPIとGoogleDriveのAPIは使えるようになっているものとしてすすめます。詳しくは [参考](#参考)にあるサイトを参照してください。非常にわかりやすくまとめられています。

#ソースコード
↓設定をまとめています。上はTwitterのAPIキーやユーザ名、下は保存するGoogleDriveのディレクトリのIDです。ご自身で取得された値を入れてください。

```python:config.py

CONSUMER_KEY = "********************************"
CONSUMER_SECRET = "********************************"
ACCESS_TOKEN = "********************************"
ACCESS_TOKEN_SECRET = "********************************"
USER_ID = "***********"

GOOGLEDRIVE_PICS_DIRECTORY_ID = "********************************"
GOOGLEDRIVE_VIDEOS_DIRECTORY_ID = "********************************"

```

↓メインとして動く部分。cmdでデバッグ出力するためにエンコードしています。画像・動画が含まれるかは自動で判断しています。動画については.mp4でないもの、サイズが小さいものがあるので最もサイズが大きいものを取得するようにしています。


```python:get_data.py
import json, config
from requests_oauthlib import OAuth1Session
import re
import download
import upload

CONSUMER_KEY = config.CONSUMER_KEY
CONSUMER_SECRET = config.CONSUMER_SECRET
ACCESS_TOKEN = config.ACCESS_TOKEN
ACCESS_TOKEN_SECRET = config.ACCESS_TOKEN_SECRET

USER_ID = config.USER_ID

twitter = OAuth1Session(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)

url = "https://api.twitter.com/1.1/favorites/list.json"

params ={'screen_name' : USER_ID, 'count' : 200}
res = twitter.get(url, params = params)

def main():
    if res.status_code == 200:
        for line in json.loads(res.text):
            if('extended_entities' not in line):
                return
            for i in line['extended_entities']['media']:
                if('video_info' in i): #if the tweet contains a video.
                    dic = {}
                    for v in i['video_info']['variants']:
                        if ('.mp4' in v['url']): #only .mp4 file.
                            dic[v['url']] = find_max_size(v['url'])
                    print(max(dic, key=dic.get).encode('cp932', 'ignore').decode('cp932'))
                    download.download_videos(max(dic, key=dic.get))
                else:
                    print((i['media_url_https']).encode('cp932', 'ignore').decode('cp932'))
                    download.download_pics(i['media_url_https'])
    else:
        print("Failed: %d" % res.status_code)

def find_max_size(url): #Find the max size video.
    s = re.findall(r'/\d+x\d+/', url) #e.g. /720x1280/
    t = re.findall(r'/\d+x', str(s[0])) #e.g. /720x
    u = re.findall(r'x\d+/', str(s[0])) #e.g. x1280/
    x = int(t[0].replace('x', '').replace('/', '')) #e.g. 720
    y = int(u[0].replace('x', '').replace('/', '')) #e.g. 1280
    return x * y

main()
upload.upload_pics_videos()
```

↓ローカルのフォルダに画像・動画をダウンロードする部分です。/pics, /videosというフォルダを作ってそこに保存しています。ファイル名は日時で一意にしています。

```python:download.py
import requests
import datetime
import os

def download_pics(url):
  os.makedirs('pics/', exist_ok=True)
  file_name = "pics/" + datetime.datetime.now().strftime("%Y%m%d%H%M%S%f") + ".jpg"

  response = requests.get(url)
  image = response.content

  with open(file_name, "wb") as stream:
      stream.write(image)

def download_videos(url):
  os.makedirs('videos/', exist_ok=True)
  file_name = "videos/" + datetime.datetime.now().strftime("%Y%m%d%H%M%S%f") + ".mp4"

  response = requests.get(url)
  video = response.content

  with open(file_name, "wb") as stream:
      stream.write(video)

```

↓最後にGoogle Driveにアップロードする部分です。あらかじめドライブ上に作成しておいたフォルダにアップロードする動きになっています。

```python:upload.py
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from pathlib import Path
import config

def upload_pics_videos():
  gauth = GoogleAuth()
  gauth.CommandLineAuth()
  drive = GoogleDrive(gauth)

  for p in Path("pics").glob("*"):
    q = str(p)
    f = drive.CreateFile({
      "parents": [{
        "id": config.GOOGLEDRIVE_PICS_DIRECTORY_ID
        }]
      })
    f.SetContentFile(q)
    f.Upload()
    print(f['title'], f['id'])

  for p in Path("videos").glob("*"):
    q = str(p)
    f = drive.CreateFile({
      "parents": [{
        "id": config.GOOGLEDRIVE_VIDEOS_DIRECTORY_ID
        }]
      })
    f.SetContentFile(q)
    f.Upload()
    print(f['title'], f['id'])
```

#さいごに
もっときれいにソースを書くべきですね。Python初心者とはいえ、反省です。変数名とか動画の最大サイズ求めるところとか。。。ですが成果物としていつもお世話になっているQiitaさんに記事を投稿してみたい気持ちが強かった&動くものができたので勇気を出して公開してみました。

#質問
TwitterのAPIにお詳しい方にお聞きしたいのですが、今回使っている GET favorites/list の制限について。実際にこのアプリケーションというかプログラムを動かしてみても、

1. 指定件数分取得できない
2. 1件も取得できないときがある。
3. 時間間隔をおいて1日1回などの起動でもうまく動かない。


ネットで色々調べてみると

* Rate Limit：15分で15回まで
* count：200以下
* 一回の実行で 200x15=3,000fav が取得できる

というような制限はあるようなのですが、それは満たしているのになんでだろうっていう感じです。これはAPIの使い方が悪いからなのか、それともサーバーが重い等の問題なのか。当方初心者ですのでよくわかっておりません。コメント等で教えていただけたら幸いです。

#参考
[Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ　※2019年8月時点の情報 ](https://qiita.com/kngsym2018/items/2524d21455aac111cdee)

[PythonでGoogleドライブに画像をアップロード](https://qiita.com/akabei/items/f25e4f79dd7c2f754f0e)