Instagram のページから投稿 URL を一括取得するブックマークレットを作った

Instagram の検索結果や「保存済み一覧」などのページを Web ブラウザで開いている時に、そのページにある投稿ページへのリンクを一括取得するブックマークレットを作った。収集した URL はクリップボードにコピーする。

javascript:(d=>{e=d.createElement('textarea');e.textContent=Array.from(d.querySelectorAll('a'),a=>a.href.match(/(?!.*liked_by).*(?=\/p\/)/)&&a.href).filter(a=>a).join('\n');d.body.appendChild(e);e.select();d.execCommand('copy');d.body.removeChild(e)})(document);

何件の URL を取得したか alert() するバージョンはコチラ。

javascript:(d=>{e=d.createElement('textarea');l=Array.from(d.querySelectorAll('a'),a=>a.href.match(/(?!.*liked_by).*(?=\/p\/)/)&&a.href).filter(a=>a);e.textContent=l.join('\n');d.body.appendChild(e);e.select();d.execCommand('copy');d.body.removeChild(e);alert(l.length+'件')})(document);

拙作の @neos21/igsv で一括ダウンロードするために取得するのであれば、igtv 【URL】 となるようコピーさせても良いだろう。コピーさせたままターミナルに貼り付ければ igsv でダウンロードができる。

javascript:(d=>{e=d.createElement('textarea');l=Array.from(d.querySelectorAll('a'),a=>a.href.match(/(?!.*liked_by).*(?=\/p\/)/)&&'igsv '+a.href).filter(a=>a);e.textContent=l.join('\n')+'\n';d.body.appendChild(e);e.select();d.execCommand('copy');d.body.removeChild(e);alert(l.length+'件')})(document);

コードの説明

普通のコードに直すとこんな感じ。

const textarea = document.createElement('textarea');

const links = Array.from(document.querySelectorAll('a'), a => a.href.match(/(?!.*liked_by).*(?=\/p\/)/) && a.href).filter(a => a);
textarea.textContent = links.join('\n');

document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);

alert(links.length + '件');

テキストエリアを生成してクリップボードにコピーする部分は、以前紹介したブックマークレットと同じ。

Array.from() を使うと、document.querySelectorAll() を配列化し、ついでに map() 相当のことができる。querySelectorAll() の結果は通常の配列ではないので、forEach() 以外を使う時は何らかの方法で配列化する必要がある。

a.href.match(/(?!.*liked_by).*(?=\/p\/)/) 部分の正規表現がミソ。基本的には、href 属性値に /p/ を含んでいればその値を返すつもりで書いている。コレは Instagram の投稿ページの URL が、

となっているので、間にある /p/ 部分を探るようにした。ただ、投稿一覧などのページだと

といった URL が混じることがあったので、それを除外するために /(?!.*liked_by).*(?=\/p\/)/ こんな正規表現になった。

より正確に取得するなら改良の余地はあるだろうが、ブックマークレットの文字数を削りたいのでコレだけ。

match() しなかった場合は undefined が返り、Array.from() が生成する配列に空 (undefined) の要素が混じってしまう。コレを削るのが .filter(a => a) というイディオムだ。コレだけで、Falsy な値を除外できる。

この方法は undefinednull'' (空文字)・false の他に、数値の 0 も除外されてしまうので、数値を扱う配列の場合は注意。

コレで、投稿ページの URL の配列ができたので、あとはテキストエリアに突っ込んでコピーしたりとかすれば終わり。

注意点

このブックマークレットで投稿 URL を一括取得や〜、といきたいところだったが、一つ大きな注意点が。

Instagram には Virtual Scroll という技術が導入されている。スクロールバーは一見長くなっているのだが、DOM 要素的には画面上に表示されている要素しか配置されていない、という状態になっているのだ。

つまり、数十件、数百件分の投稿が画面に表示されているかのように、ページ最下部までのスクロールを何度も繰り返した後にこのブックマークレットを使っても、先頭の方の投稿の DOM 要素はなくなっており、2・30件分くらいの URL しか取得できないのだ。

一括でゴッソリ取れるかと思ったが、なかなか上手く行かず残念。諦めよう〜