Pythonでtwitterでいいねしたツイートにある画像を収集するプログラムを作ってみた

この記事は[Akatsuki Advent Calender 2020](https://adventar.org/calendars/5174)の23日目になります


## はじめに

運用して2~3年経っているのですが記事にしておらず今回いい機会なのですることにしました。

まず事の経緯として
twitterを覗いていると収集したい画像が回ってくることがあります。
そこでいちいち**右クリック->ダウンロード->パス指定**は非常に面倒だしそういうツイートが連続で来たら？となるとやってられません。

そこで**何かしらトリガーがあって自動でダウンロード**してくれないかなと。
それで**閲覧する用のwebページがあれば**完璧ではないかと。
そんな訳で収集欲と技術欲半々のなか作ることにしました。

今回は収集のところだけ。
（それpixivとかで良くない？とか思うかもしれないですが
自分の欲しいやつだけ閲覧できるものが欲しいんです・・・）


## 要件
・RTではなく**いいねのツイートのみ**ダウンロードすることに。
いいねだと**クリック手順が１つ少ない**ので速攻次のツイートに移れる
・収集はレンタルサーバーか何かで行う
自宅に常時つけるPCはないので、収集タイミング時につけてないといけないのは利便性が悪い。
・実装当時はstreaming apiが生きていたのでそれでリアルタイムでいいねツイートを取得
-> なくなったのでrest apiで時間をおいて取得する方にしました。
・ツイート内容やURL、@ IDなどもwebページでの検索用として保存しておく

## 開発環境
レンタルサーバー
・さくらサーバー

言語
・python3.6

使用ライブラリ
・requests_outhlib
・mysql.connector



## Twitter Devへの登録
https://developer.twitter.com/
こちらで登録を行っておき、認証を通せるようにしときます。


## 実装へ
ところどころ省略しています

### 1. セッションの生成

twitter developerにてappを作っておく。
そこでKey And Tokenのタブに認証に必要なKeyとTokenがあるのでコピーしておきます。

![twitter_screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126834/209dd148-ce46-bae2-5d0c-1f97e6684c3e.png)

requests_outhlibにてセッションを作る際は
以下のコードで先程のKeyとTokenを指定します。

```python
twitter_session = OAuth1Session(consumerKey
        , consumerSecret
        , accessToken
        , accessSecret)
```

### 2. APIの結果取得

https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-favorites-list
今回使ういいねAPIについてはこちら

コードでは以下のように使用します

```python
#APIのResources URLと渡すパラメータを指定
#パラメータは上のページに載っていますが今回は以下の２つをメインで使います
#screen_name:@で表記するid 本来はuser_idを指定するのが確実ですが、収集アカウントは変える予定ないのでこれで
#count:一度に取得するツイート数 (max:200)
request = twitter_session.get("https://api.twitter.com/1.1/favorites/list.json", params = {"screen_name":ID, "count":200})

#古いのツイートを取得したい場合 パラメータに以下を追加します
#tweet_idよりも前のツイートを取得するようになります。指定なしで最新のツイートからになります
"max_id":tweet_id
```

結果はjsonで返ってきます。
status_codeでエラーかどうか判別。request.textにjsonのデータが有るためjson.loadsでjsonに変換しておきます。

```python
if request.status_code == 200:
    print("rest connect")
else:
    print("rest Error code%d", request.status_code)
return ""
tweets = json.loads(request.text)
```
またこれを実行する際も以下の制限に気をつける必要があります
・**75リクエスト/15分**
・取得されるツイートの順番は**いいねした順番ではなくいいね先のツイート日時が新しい順**に取得されます
なので古いツイートを取得する場合は工夫する必要があります

### 3. jsonデータを元に画像を取得

先程取得したtweets変数にはツイートが配列が入っているためfor文で１つずつ処理が可能です

```python
for tweet in tweets:
    #ツイートから情報を取得

    #ツイートのID　一番最後のtweet["id"]を上で説明したtwitter_session.getのmax_idに指定することで
    #次のリクエストで取得する結果がかぶることなく処理できます
    tweet["id"]
    #表示する名前 
    tweet["user"]["name"]
    #@id
    tweet["user"]["screen_name"]
    #画像一覧 (URL)
    tweet["extended_entities"]["media"]
    #ツイート文
    tweet["text"]
    #ツイートURLは以下の組み合わせで
    "https://twitter.com/"+tweet["user"]["screen_name"]+"/status/"+tweet["id_str"]
```

今回は画像一覧なので

```python
    #画像一覧 (URL)
    image_list = tweet["extended_entities"]["media"]
```
これを使います。
これも配列としてやってくるのでfor文で処理します
色々と省略はしていますが基本的にこれでダウンロード後保存を繰り返しています。

```python
for image in image_list:
    url = image["media_url"]
    img = urllib.request.urlopen(url, timeout = 5).read()
    f = open(path, 'wb')
    f.write(img)
    f.close()
```

流れとしては以下の通り
・セッション作成
・リミットまでgetリクエスト75回ループ
・取得ツイートの画像を取得
・取得ツイートの最後のツイートIDを保持してリクエスト時に渡す

もし古いツイートを取得する場合は定期的に全いいねを見ていくのが良いかと

### 4.レンタルサーバーでCRON設定
今回はリクエストが15分ごとに制限があるのでそれに合わせてCRONを設定します
![スクリーンショット 2020-12-23 23.28.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126834/392d18b9-ae48-1ed8-5b15-a6301fe57f27.png)

これでいいね自動収集化完了ですが
web上で閲覧・検索をするのであればDBにツイートの情報保存したりする必要があります。

## 最後に
この後、DBやwebページは適宜設定して閲覧はできたのですが、
**正直ほとんど見てません。**収集とプログラムが動いたのでそこができただけで満足しちゃいました。
とはいえ学習するための題材としてはなかなか良かったと思います。スクリプト言語全然触っていなかったのと
自動化への興味が湧いた一番の作品？だったので。

なお、現在収集できた枚数は
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126834/c8575fca-b981-4151-4a7a-ef4c46a1e668.png)
**約 1 7 万 枚**

いいねの回数は
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126834/2254027a-d66a-17bc-2192-a5c7574cde78.png)
**1 5 万 い い ね**
自分でもこの人イカれてますねと思いました。自分だけど・・・

もっと良いシステムを作るとするならば機械学習で収集する画像も自動化が一番いいのですが、一度やろうとしたところ
収集したい画像の判定がめちゃんこ難しくて諦めました。自分の好みを落とし込まないといけない難易度高い・・・
学習のための画像はあるんですけどね・・・・・