Instagram に投稿された画像・動画をダウンロードする CLI ツール「igsv」を作った

Twitter から画像・動画をダウンロードする @neos21/twsv という npm パッケージを作ったが、それの Instagram 版を作った。その名も igsv。「InstaGram SaVer」の略のつもり。

目次

先に作ったツールの紹介

igsv は Node.js 製の CLI ツール。npm でインストールできる。パッケージ名としては @neos21/igsv

$ npm install -g @neos21/igsv

グローバルインストールしたら igsv コマンドが使えるようになっているので、以下のように Instagram の URL を引数で指定してやる。

# 指定の投稿に紐付く画像・動画を取得する
$ igsv https://www.instagram.com/p/XXXXXXXXXXX/

デフォルトの保存先は、コマンドを実行した時のカレントディレクトリに igsv-downloads/ ディレクトリを作り、その下にファイルを保存する。

保存先ディレクトリを変更する場合は、環境変数か第2引数で指定できる。両方指定されている場合は第2引数が優先される。

# 環境変数で指定して実行
$ export IGSV_SAVE_DIRECTORY='/home/downloads'
$ igsv https://www.instagram.com/p/XXXXXXXXXXX/

# 第2引数で指定して実行
$ igsv https://www.instagram.com/p/XXXXXXXXXXX/ '/home/downloads'

画像はサイズが一番大きいモノを選んで取得している。動画は IGTV でも通常の動画と同様にダウンロードできる。

以降ツールを作るまでの苦労話

自分が Instagram から画像や動画をダウンロードする時は、以下のウェブアプリを使っていた。

UI がイマイチで、複数枚の画像を DL するのが大変だったので、twsv 同様 CLI ツールとして作ることにした。

Instagram の API は登録が面倒で避けたかったので、スクレイピングでなんとかならないか調べてみた。投稿ページを request-promise で取得し、cheerio で jQuery ライクなオブジェクトに変換し、ページ内を調べてみた。すると、以下のような script 要素が見つかった。

window._sharedData = { 【大量に連想配列…】 };

この window._sharedData という変数に代入されている連想配列 (≒ JSON オブジェクト) を紐解いていくと、投稿ページの全データが含まれていることが分かった。そこで、この script 要素内から連想配列部分だけを抜き出し、JSON.parse() して中を辿っていくことにした。

JSON データの中の、.entry_data.PostPage[0].graphql.shortcode_media 配下に、投稿した画像や動画のデータがある。配下に edge_sidecar_to_children.edges プロパティがあれば複数枚の投稿、なければ単一の画像や動画の投稿だ。

単一の画像や動画の場合は、.shortcode_media.is_video プロパティを見ることで、投稿が画像なのか動画なのかが分かる。is_videotrue なら動画なので、同階層の .video_url を取得すれば良い。

画像の場合は、.display_resources プロパティが配列になっていて、様々な解像度のデータが入っている。.config_width.config_height プロパティがピクセルサイズなので、これらを見て、最大解像度の画像を手に入れるようにした。

複数枚投稿の場合は、.edges 配下が配列になっているだけで、各要素からの画像・動画の抜き出し方は単独の場合と同じ。

JSON の構成が難解だったが、とりあえず拾えたので、あとはダウンロードするのみ。保存先ディレクトリのチェックや保存処理などは、@neos21/twsv とほぼ同じなので割愛。

以上

ページをスクレイピングしているだけなので、非公開アカウントなどは拾えないしユーザのログイン状況などを認識できないが、自分の用途ではコレで十分かな。