見出し画像

Twitterでいいねした画像を自動保存する

あ~Twitter API有料になりましたね。(←2023-04-15記)

Twitterでいいねした画像を自動で保存し続けたい記事です。

ぼくにとってTwitterの楽しみの1つは好きなアイドルやコスプレイヤの画像なんですよね。タイムラインを見ると撮影会の写真や自撮りした画像が流れてきて、毎日癒やされます。気に入ったものを手で保存したりしていたのですが、手間がかかるため、いいねした画像を自動で保存したいと考えました。

調べてみると、特定アカウントの画像やいいねした画像をダウンロードするtimgというサービスが見つかりましたが、複数回ダウンロードすると前回保存したものもまたダウンロードしてしまうことや、画像サイズが最大じゃないことなど気になる点がありました。他にもいろいろな方法でやってる例が見つかりますが、自分で作ってみたほうが好きなようにカスタマイズできていいですし、勉強になりますし、単純にTwitter APIを試してみたいというのもあり、Pythonでやってみることにしました。

具体的にやりたいのは、いいねしたツイートの画像を自動でローカルに保存することです。Twitter APIを使えばなんでもできるんじゃないかと思ってやり始めましたが実際は制限もあり、試しているうちにわかったことがいろいろあるので、それについて書いてみたいと思います。すでに使ってる人にとっては簡単な内容だと思います。

Twitter API実行時に認証のため4つのトークンが必要なので、まずは開発者アカウントを申請して審査を通過し、承認される必要があります。

Your Twitter developer account application has been approved!

では早速使ってみます。いいねをリクエストするURLはこれですね。GETすると自分がいいねしたツイートの情報がJSON形式で、投稿日時が新しい順に20個取れます。https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-favorites-list

GET https://api.twitter.com/1.1/favorites/list.json

しかし20個では足りません。全部取るにはどうすればいいでしょうか?countというパラメータに200まで設定できるので、1回の呼び出しで200個まで取れます。しかし200個でも足りません。もっと古いツイートを取るにはどうすればいいでしょうか?max_idというパラメータを指定すると、指定したIDと同じか、それより古いツイートを返してくれます。なので、

APIを呼び出す
一番小さいIDを確認する
max_idに一番小さいIDを設定してAPIを再度呼び出す
また一番小さいIDを確認する
...

と繰り返せば、どんどん古いツイートの情報を得ることができそうです。

APIの呼び出し頻度には制限があり、15分あたり75回です。ということは15分で75回実行すれば200x75=15000個取れて、次の15分でまた15000個取れて、と繰り返していけば全部取れるんじゃないかと思いました。しかしそうはいきません。どうやら遡れるツイート数自体に制限があるらしく、3000くらいが限界でした。Webクライアントで自分の古いいいねを見ようと思っても全部見れないのと同じようです。なお、古いいいねを全部見る方法は存在しないわけではなく、Twitterの全ツイート履歴ダウンロードを利用すると、画像はついてきませんが一覧を取得できます。

というわけで、日々新しくいいねしていくと、3000個よりも古いいいねがどんどん見れなくなってしまうことがわかりました(T_T)。なので、見れなくなってしまう前に、たとえば週1とかの頻度で定期的に実行しないといけないのです!

また、TwitterのWebクライアントだといいねした順で表示されますが、APIでは投稿日時順に取れました。なので、すごく古いツイートを新たにいいねしても、それが3000個より古いツイートだった場合は残念ながらこのAPIでは取れないことになります。

画像URLはJSONのextended_entities内のmedia配列内のオブジェクトのmedia_urlに書かれています。2014年まではTwitterの画像が1枚だったため、entitiesだけでしたが、現在は4枚まで投稿できるのでextended_entitiesを見る必要があります。https://developer.twitter.com/en/docs/twitter-api/v1/data-dictionary/overview/extended-entities-object

画像取得の実験をしていて、たまにJSONに画像URLが取れていないことがありました。調べたところ、ツイートの"text"がURLを含んでいたりと長いときに、末尾が「…」となって省略されてしまい、情報がすべて取れていないことがわかりました。省略されたことは、そのツイートオブジェクトに"truncated": trueというフラグが付いていることで確認できます。このような場合に省略せずに全文取得するには、API呼び出し時にtweet_mode=extendedというパラメータを与える必要があります。tweet_mode=extendedを使用すると、ツイートの文字列は"text"ではなく"full_text"に省略なしで格納されるようになり、extended_entitiesもちゃんと取れ、フラグは"truncated": falseに変わります。

まとめるとAPIの呼び出しはこんな感じになります。

GET https://api.twitter.com/1.1/favorites/list.json?count=200&max_id=1303429696810618883&tweet_mode=extended

これで画像のURLは取れますが、もう1つ注意点があります。media_urlにそのままアクセスすると画像のサイズがオリジナルより小さくなってしまうことがあります。大きなサイズの画像にアクセスするには(media_url):largeとする必要があります。

自分で実際使っている感想として、ここまでの議論で大事な点はおさえられてるのではないかと思います。漏れているとか、画像が小さい!といった問題が起きていないので。以上をふまえて書いたget_fav_image.pyは有料記事ですが、どのような動作をするか述べます。実行するには適当なフォルダfolder_hogeにget_fav_image.pyを置きます。

folder_hoge
  + get_fav_image.py

folder_hogeにカレントフォルダを移動し、get_fav_image.pyを1回実行すると次のように画像とログのフォルダが自動で作られます。

folder_hoge
  + get_fav_image.py
  + logs
        + session.txt (実行したセッション数が書かれるログ)
        + 00001_idlist.txt (セッション1で取得したツイートIDのリスト)
        + idlist_all.txt (全てのセッションで取得したツイートIDのリスト)
  + images
        + 00001 (セッション1で取得した画像のフォルダ)
              + 画像1
              + 画像2
              + 画像3
              ...

実行のたびにセッションIDが増えていきます。つまり、もう1回実行すると、00002_idlist.txt(セッション2で取得したツイートIDのリスト)と00002(セッション2で取得した画像のフォルダ)が作られます。

画像の名前は{user_screen_name}_{tweet_id}_{numbering}.{jpg or png}としています。numberingというのは1つのツイートに複数の画像があった場合に1、2、3と採番するためのものです。ファイル名からアカウント名とツイートIDがわかれば便利かなと思ってぼくはこうしてますが、好きなようにカスタマイズすれば良いと思います。

idlist_all.txtというログを出しているのは、これまでに画像を保存したツイートID一覧を覚えておき、同じ画像を何度も保存するのを避けるためです。つまり2回目以降のセッションでは、すでに保存した画像を保存しません。

1回の実行ではAPIを15回呼び出すようにしています。これは1回で取れるツイートが200個で、いいねを遡れる数の限界が3000程度であることをふまえた回数です。20回呼んでも意味がないのです。

上に述べたように、実行するためにはTwitterの開発者アカウントを取得し、Access Tokenを発行し、合計4つのトークンを、コード中に記載する必要があります。Twitter APIに興味なかったらこれだけで敷居高いですが^^;

API_KEY = "***"
API_KEY_SECRET = "***"
ACCESS_TOKEN = "***"
ACCESS_TOKEN_SECRET = "***"

また、requests_oauthlibなどのライブラリを使っていますので、必要なライブラリはpipで事前にインストールする必要があります。

動作確認環境はWindows10、Python 3.8.5で、継続的に問題なく便利に使っています。いいねした画像を1箇所に保存できて、まとめて見れるというのは楽しいです。たとえば特定のアカウントの画像が欲しいとか動画も欲しいとかやり方を変えたいとかあると思いますが、好きなようにカスタマイズして使っていただければと思います。バグや、使用したことによる損害については念のため免責でお願いします^^;

なんとなく自分で書いたこの記事に立ち寄った今日は2021年9月12日。偶然にも投稿してからぴったり1年です。その間このスクリプトはずっと使い続けており、ダウンロードした画像は、11万ファイル、35GBにもなっています。数が増えても大丈夫かというのは1つ気になっていたことですが、今のところ正常に動いています。数が問題で動かなくなったらまあ、別フォルダで再開すれば済みますが。

ここから先は

3,172字

¥ 300

.