Instagramのリールを週に1度スプレットシートにまとめたいです。
AIに時間を委ねた私がこれから解説します
私は先日、Playwrightというツールを使って、
Instagramのリールを自動で調査する仕組みを作ろうとしました。
VSCodeを開いて、コードを貼り付ければ動くだろう
その結果、やってしまいました。
npxコマンドが「command not found」と出続け、
原因を調べたらNode.jsのインストールからやり直しに。
ようやく動いたと思ったら、
今度は「フォロー中」のボタンをクリックできず、
タイムアウトエラーの連続でした。
Instagramの画面構成は頻繁に変わるため、
コードを何度も調整する必要がありました。
試行錯誤の末、
ようやく「フォロー中のアカウントを自動で巡回し、
条件に合うリールだけを抽出してスプレッドシートに出力する」
仕組みが完成しました。
この記事では、私が実際につまずいた点を交えながら、
初心者の方でも同じ失敗をしないように、
手順を丁寧に解説します。
この記事で分かること
- Playwrightを使ったブラウザ自動操作の始め方
- Instagramのフォロー中アカウントを自動で巡回する方法
- 再生数・投稿日・動画の長さで自動フィルタリングする方法
- 結果をGoogleスプレッドシートに出力する方法
- 毎週決まった曜日に自動実行する設定方法
ClaudeCodeを利用してInstagramの自動化をする際に注意するべきこと
結論から言うと、この方法はInstagramの利用規約に触れる可能性があるので、あくまで個人の学習・研究目的の範囲で試すことをおすすめします。
なぜなら、短時間に大量アクセスするとアカウント制限のリスクがあるからです。
気をつけたいポイントは、大きく2つあります。
- 利用規約について
- 著作権について
Instagramの利用規約について
- 短時間に大量のページへアクセスしない
- 自分のアカウントで、個人の学習目的の範囲で試す
- 待機時間を適度に入れて、自然な操作間隔を保つ
Instagramの著作権について
見つけたリールの動画そのものや、
音声の全文を保存・
複製することは著作権上の問題になり得ます。
この記事で紹介する方法は、
あくまで再生数・投稿日・動画の長さといった数値データと、
動画のURLを集めるところまでにとどめています。
内容を参考にしたい場合は、
全文を書き起こすのではなく
「構成の型」を自分の言葉で
メモすることをおすすめします。
ClaudeCodeでInstagram自動化するために必要なツール
以下のソフトが必要です。
まだ入れていない場合は、
先にインストールしてください。
- VSCode:コードを書くためのエディタ
- Node.js:プログラムを動かすための実行環境
- Playwright:ブラウザを自動操作するためのツール
私はここでつまずきました。
「node -v」を打っても反応がなく、
Node.js自体が入っていなかったんです。
VSCodeのターミナルで、
以下を実行して確認してみてください。
node -v
バージョン番号(例:v24.20.0)が表示されればOKです。
「command not found」と出た場合は
、Node.js公式サイトからインストールしてください。

ClaudeCodeでInstagramの自動化プロジェクトを作る
作業用のフォルダをVSCodeで開いた状態で
ターミナルに以下を入力します。
npm init playwright@latest
途中でいくつか質問が出ますが、
基本的にEnterキーを押して
デフォルトのまま進めて問題ありません。

⚠️ つまずきポイント
フォルダ名に日本語(全角文字)が含まれていると
「Invalid name」というエラーが出ることがあります。
その場合は、先に以下のコマンドで
package.json を英数字の名前で作ってから、
もう一度実行してください。
cat > package.json << 'EOF'
{
"name": "ai-workspace",
"version": "1.0.0"
}
EOF
ClaudeCodeでInstagramのログイン状態を保存する
毎回ログインし直さなくて済むように、
最初に1回だけログインして、
その状態を保存しておきます。
「test.ts」というファイルを作り、
以下のコードを貼り付けます。
import { chromium } from '@playwright/test';
(async () => {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://www.instagram.com/');
// ここで手動でログインしてから、続行ボタンを押してください
await page.pause();
// ログイン状態を保存する
await context.storageState({ path: 'auth.json' });
console.log('ログイン情報を auth.json に保存しました');
await browser.close();
})();
実行方法:
npx tsx test.ts
ブラウザが開いたら、
手動でInstagramにログインしてください。
ログインできたら、
Playwright Inspectorの
緑色の「続行ボタン」を押します。
すると auth.json というファイルが作られます。
これが、あなたのログイン状態を記録したファイルです。

フォロー中のアカウントを自動で巡回する
ここが一番苦戦したポイントです。
「フォロー中」のリンクを探すコードが何度もタイムアウトしました。
原因は、Instagramの「フォロー中」表示が、
リンクタグではなくボタン要素に変わっていたことでした。
文字を含む要素を柔軟に探す書き方に変更したら解決しました。
「reels-scraper.ts」というファイルを新しく作り、
以下のコードを貼り付けます。
import { chromium, Page } from '@playwright/test';
import * as fs from 'fs';
// ===== 条件設定 =====
const MIN_VIEWS = 90000; // 最低再生数
const MIN_DURATION_SEC = 30; // 最低動画の長さ(秒)
const MAX_DAYS_AGO = 30; // 何日以内の投稿か
// ===== 「誰の」フォロー一覧を見るか =====
const BASE_ACCOUNT = 'あなたのユーザー名';
// ===== フォロー一覧から、最大何人まで調べるか =====
const MAX_ACCOUNTS_TO_CHECK = 15;
(async () => {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext({ storageState: 'auth.json' });
const page = await context.newPage();
const followingUsernames = await getFollowingList(page, BASE_ACCOUNT, MAX_ACCOUNTS_TO_CHECK);
console.log(`フォロー中のアカウント: ${followingUsernames.length}件取得しました`);
const candidateUrls: string[] = [];
for (const username of followingUsernames) {
console.log(`\n--- @${username} を確認中 ---`);
try {
await page.goto(`https://www.instagram.com/${username}/reels/`);
await page.waitForTimeout(3000 + Math.random() * 2000);
const items = await page.locator('a[href*="/reel/"]').evaluateAll(els =>
els.map(el => ({
href: (el as HTMLAnchorElement).href,
text: el.textContent || ''
}))
);
for (const item of items) {
const views = parseViewCount(item.text);
if (views !== null && views >= MIN_VIEWS) {
candidateUrls.push(item.href);
console.log(`候補: ${item.href} (約${views}回再生)`);
}
}
} catch (e) {
console.log(`@${username} の確認をスキップしました`);
}
}
const results: { url: string; postedDate: string; durationSec: number }[] = [];
for (const url of candidateUrls) {
try {
const reelPage = await context.newPage();
await reelPage.goto(url, { waitUntil: 'domcontentloaded' });
await reelPage.waitForTimeout(2000);
const dateAttr = await reelPage.locator('time').first().getAttribute('datetime').catch(() => null);
const durationSec = await reelPage.locator('video').first()
.evaluate((v: HTMLVideoElement) => v.duration).catch(() => 0);
await reelPage.close();
if (dateAttr) {
const postedDate = new Date(dateAttr);
const daysAgo = (Date.now() - postedDate.getTime()) / (1000 * 60 * 60 * 24);
if (daysAgo <= MAX_DAYS_AGO && durationSec >= MIN_DURATION_SEC) {
results.push({ url, postedDate: postedDate.toISOString(), durationSec });
console.log(`最終候補: ${url}`);
}
}
} catch (e) {
console.log(`スキップ: ${url}`);
}
}
const csvHeader = 'URL,投稿日,動画の長さ(秒)\n';
const csvRows = results.map(r => `${r.url},${r.postedDate},${r.durationSec}`).join('\n');
fs.writeFileSync('reels_candidates.csv', csvHeader + csvRows);
console.log(`\n完了!${results.length}件の候補を reels_candidates.csv に保存しました`);
await browser.close();
})();
async function getFollowingList(page: Page, username: string, maxCount: number): Promise<string[]> {
await page.goto(`https://www.instagram.com/${username}/`);
await page.waitForTimeout(3000);
await page.locator('a, button').filter({ hasText: 'フォロー中' }).first().click();
await page.waitForTimeout(2000);
const usernames = new Set<string>();
const dialog = page.locator('div[role="dialog"]');
for (let i = 0; i < 15 && usernames.size < maxCount; i++) {
const links = await dialog.locator('a[href^="/"][href$="/"]').evaluateAll(els =>
els.map(el => (el as HTMLAnchorElement).href)
);
links.forEach(l => {
const match = l.match(/instagram\.com\/([^/]+)\/$/);
if (match) usernames.add(match[1]);
});
await dialog.locator('> div > div').last().evaluate(el => el.scrollBy(0, 500)).catch(() => {});
await page.waitForTimeout(1500);
}
return Array.from(usernames).slice(0, maxCount);
}
function parseViewCount(text: string): number | null {
const manMatch = text.match(/([\d.]+)\s*万/);
if (manMatch) return parseFloat(manMatch[1]) * 10000;
const plainMatch = text.match(/([\d,]+)/);
if (plainMatch) return parseInt(plainMatch[1].replace(/,/g, ''));
return null;
}
BASE_ACCOUNTの部分を、ご自身のユーザー名に書き換えてから実行してください。
npx tsx reels-scraper.ts

Instagramの自動化結果をGoogleスプレッドシートに取り込む
実行が終わると reels_candidates.csv というファイルができます。
これをGoogleスプレッドシートに取り込みます。
- Googleスプレッドシートを新規作成
- 「ファイル」→「インポート」→「アップロード」からCSVを選択
- 「新しいシートを挿入」を選んでインポート

ここで一つ大事な注意点があります。
動画の音声を全文書き起こすのは
著作権的にグレーなので避けましょう。
「アカウント名」「構成メモ」の列を追加しておくと、
後で見返しやすくなります。構成メモ欄には、
以下のように「構成の型」を自分の言葉で
まとめることをおすすめします。
例:冒頭で意外な一言→中盤で機能を実演→締めで一言アドバイス
Instagramの自動化を毎週決まった曜日に実行する
Macには、決まった時間にプログラムを
自動実行する「launchd」という仕組みがあります。
これを使って、毎週土曜日の朝10時に自動実行する設定をします。
まず、自分のnpxの場所を確認します。
which npx
表示されたパスを使って、
以下のコマンドを実行します
※パスは環境に合わせて書き換えてください
cat > ~/Library/LaunchAgents/com.reels.scraper.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.reels.scraper</string>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-c</string>
<string>cd /Users/あなたのユーザー名/作業フォルダ && /usr/local/bin/npx tsx reels-scraper.ts >> log.txt 2>&1</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Weekday</key>
<integer>7</integer>
<key>Hour</key>
<integer>10</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
</dict>
</plist>
EOF
(Weekdayは0=日曜〜6=金曜、7=土曜を表します)
登録するには、以下を実行します。
launchctl load ~/Library/LaunchAgents/com.reels.scraper.plist
⚠️ 自動実行の注意点
- パソコンがスリープ中・電源オフの場合は実行されません
- 定期的な自動実行は通常よりアクセス頻度が上がります
- アカウント制限のリスクにも注意してください
ClaudeCodeを利用してInstagramリールリサーチを自動化する方法
この記事で紹介した手順で、以下のことができるようになりました。
- Playwrightを使ったブラウザ自動操作の基本
- Instagramへの自動ログインとログイン状態の保存
- フォロー中アカウントの自動巡回
- 再生数・投稿日・動画の長さでの自動フィルタリング
- Googleスプレッドシートへの出力
- 毎週決まった曜日の自動実行
繰り返しになりますが、この方法はInstagramの利用規約に触れる可能性があります。
個人の学習・
研究目的の範囲で、
節度を持って利用してください。
また、動画の内容(音声・映像そのもの)を
複製・保存することは避け、
あくまで数値データや構成の「型」を
参考にする使い方をおすすめします。