Apify について
Apify は、TypeScript の Actor ラッパーでソーシャルメディア、企業情報、EC、ウェブサイトをスクレイピングするスキルです。結果をモデルのコンテキストに渡す前に絞り込み、モニタリングやリード獲得に活用できます。
主な機能
- 01ソーシャルメディアとウェブのスクレイピング
- 02Google Maps で企業リードを検索
- 03Amazon の商品とレビューを収集
- 04TypeScript で結果を絞り込み・変換
- 05複数プラットフォームの並列スクレイピング
活用シーン
- 01複数プラットフォームの投稿監視
- 02地域企業のリード検索と情報補完
- 03Amazon の商品とレビューの追跡
- 04ウェブサイトのクロールと抽出データの絞り込み
MCP 対応
ファイルベースの MCP 代替手段として説明されています。TypeScript の Actor ラッパーで結果をモデルのコンテキストに渡す前に処理し、コンテキストを多く使う MCP 呼び出しを避けます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ danielmiessler/ lifeos --skill apifyインストール後、Claude Code で/apifyを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.md.gitignoreINTEGRATION.mdindex.tstsconfig.jsonpackage.jsonactors/index.tsactors/business/index.tsgoogle-maps.tsactors/ecommerce/amazon.tsindex.tsactors/social-media/facebook.tsinstagram.tslinkedin.tstiktok.tstwitter.tsindex.tsyoutube.tsactors/web/index.tsweb-scraper.tsexamples/comparison-test.tsinstagram-scraper.tssmoke-test.tsskills/get-user-tweets.tstypes/index.tscommon.tsWorkflows/Update.md詳細
カスタマイズ
実行前に、次の場所にユーザーによるカスタマイズがあるか確認してください:
~/.claude/LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Apify/
このディレクトリが存在する場合は、そこにあるPREFERENCES.md、設定、またはリソースを読み込み、適用してください。これらはデフォルトの動作より優先されます。ディレクトリが存在しない場合は、スキルのデフォルト設定で進めてください。
🚨 必須:音声通知(アクションを起こす前に必ず実施)
このスキルが呼び出されたら、何よりも先にこの通知を送信してください。
-
音声通知を送信する:
curl -s -X POST http://localhost:31337/notify \ -H "Content-Type: application/json" \ -d '{"message": "Running the WORKFLOWNAME workflow in the Apify skill to ACTION"}' \ > /dev/null 2>&1 & -
テキスト通知を出力する:
Running the **WorkflowName** workflow in the **Apify** skill to ACTION...
これは任意ではありません。このスキルが呼び出されたら、直ちにこのcurlコマンドを実行してください。
Apify - ソーシャルメディアとウェブスクレイピング
概要
Apifyアクターを通じて、ソーシャルプラットフォーム、ビジネスデータ、Eコマースの情報をスクレイピングします。対応先はInstagram、LinkedIn、TikTok、YouTube、Facebook、Google Mapsのビジネス検索、Amazon、汎用ウェブクローリングです。TypeScriptラッパーがデータをコード内でフィルタリング、変換してからモデルに渡すため、100件の投稿のスクレイピングでも、約10件分と同程度のコストで済みます。ソーシャルリスニングダッシュボード向けに複数のプラットフォームを並行実行したり、Google MapsからLinkedInへ連携してリード情報を充実させたりできます。
課題
生のMCP経由でスクレイピングすると、フィルタリングされていない結果がすべてモデルのコンテキストに送られます。Instagramのプロフィールを1つスクレイピングするだけで約52,000トークンを消費し、そのほとんどは破棄するノイズです。通常必要なのは、上位10件の投稿、直近1週間の否定的なレビュー、メールアドレス付きの条件に合うリードなどです。データがモデルに届いた後でフィルタリングしても手遅れで、トークンはすでに消費されています。最初にコードでフィルタリングすれば、52,000トークンを約500トークンに減らせます。
仕組み
このスキルはファイルベースのMCPです。トークン消費の大きいMCPプロトコル呼び出しを置き換える、コードファーストのAPIラッパーです。アクターラッパーを呼び出して、TypeScriptで結果をフィルタリング、並べ替えし、絞り込んだデータだけをモデルのコンテキストに渡します。このコンテキストに渡す前にコードで処理する手順によって、トークンを95〜99%削減できます。
ワークフローの振り分け
| ワークフロー | 呼び出し条件 | ファイル |
|---|---|---|
| 更新 | Apifyスキルの更新、アクターの更新、アクター呼び出しで予期しないエラーが発生する場合、月次の機能確認 | Workflows/Update.md |
| (インライン) | すべてのスクレイピング/リード/クロールのリクエスト — Instagram/LinkedIn/TikTok/YouTube/Facebookのスクレイピング、Google Mapsのリード、Amazonのレビュー、ウェブクロール | actors/ 以下のアクターラッパー(アクター一覧は下記を参照) |
📊 利用可能なアクター
ソーシャルメディア(5プラットフォーム)
- Instagram(ユーザー数14万5,000人、評価4.60★)- プロフィール、投稿、ハッシュタグ、コメント
- LinkedIn(ユーザー数2万6,000人、評価4.10★)- プロフィール、求人、投稿
- TikTok(ユーザー数9万人、評価4.61★)- プロフィール、動画、ハッシュタグ、コメント
- YouTube(ユーザー数4万人、評価4.40★)- チャンネル、動画、コメント、検索
- Facebook(ユーザー数3万5,000人、評価4.56★)- 投稿、グループ、コメント
ビジネスとリード獲得
- Google Maps(ユーザー数19万8,000人、評価4.76★)- 最も価値の高いアクターです!
- ビジネスの検索、連絡先・レビュー・画像の抽出
- リード獲得に最適
Eコマース
- Amazon(ユーザー数8,000人、評価4.97★)- 商品、レビュー、価格
ウェブスクレイピング
- Web Scraper(ユーザー数9万4,000人、評価4.39★)- 汎用スクレイパー。あらゆるウェブサイトで動作します
🚀 クイックスタート
基本的な使用パターン
import { scrapeInstagramProfile, searchGoogleMaps } from 'actors'
// 1. Call the actor wrapper
const profile = await scrapeInstagramProfile({
username: 'target_username',
maxPosts: 50
})
// 2. Filter in code - BEFORE data reaches model!
const viral = profile.latestPosts?.filter(p => p.likesCount > 10000)
// 3. Only filtered results reach model context
console.log(viral) // ~10 posts instead of 50
📚 用途別の例
ソーシャルメディアのモニタリング
Instagram — エンゲージメントの追跡:
import { scrapeInstagramProfile, scrapeInstagramPosts } from 'actors'
// Get profile with recent posts
const profile = await scrapeInstagramProfile({
username: 'competitor',
maxPosts: 100
})
// Filter in code - only high-performing posts from last 30 days
const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000)
const topRecent = profile.latestPosts
?.filter(p =>
new Date(p.timestamp).getTime() > thirtyDaysAgo &&
p.likesCount > 5000
)
.sort((a, b) => b.likesCount - a.likesCount)
.slice(0, 10)
// Only 10 posts reach model instead of 100!
LinkedIn — 求人検索:
import { searchLinkedInJobs } from 'actors'
const jobs = await searchLinkedInJobs({
keywords: 'AI engineer',
location: 'San Francisco',
remote: true,
maxResults: 200
})
// Filter in code - only senior roles at well-funded startups
const topJobs = jobs.filter(j =>
j.seniority?.includes('Senior') &&
parseInt(j.applicants || '0') > 50
)
TikTok — トレンド分析:
import { scrapeTikTokHashtag } from 'actors'
const videos = await scrapeTikTokHashtag({
hashtag: 'ai',
maxResults: 500
})
// Filter in code - only viral content
const viral = videos
.filter(v => v.playCount > 1000000)
.sort((a, b) => b.playCount - a.playCount)
.slice(0, 20)
リード獲得(ビジネスインテリジェンス)
Google Maps — 地域ビジネスのリード:
import { searchGoogleMaps } from 'actors'
// Search with contact info extraction
const places = await searchGoogleMaps({
query: 'restaurants in Austin',
maxResults: 500,
includeReviews: true,
maxReviewsPerPlace: 20,
scrapeContactInfo: true // Extracts emails from websites!
})
// Filter in code - only highly-rated with email/phone
const qualifiedLeads = places
.filter(p =>
p.rating >= 4.5 &&
p.reviewsCount >= 100 &&
(p.email || p.phone)
)
.map(p => ({
name: p.name,
rating: p.rating,
reviews: p.reviewsCount,
email: p.email,
phone: p.phone,
website: p.website,
address: p.address
}))
// Export leads - only qualified results!
console.log(`Found ${qualifiedLeads.length} qualified leads`)
Google Maps — レビューの感情分析:
import { scrapeGoogleMapsReviews } from 'actors'
const reviews = await scrapeGoogleMapsReviews({
placeUrl: 'https://maps.google.com/maps?cid=12345',
maxResults: 1000
})
// Filter in code - analyze sentiment by rating
const recentNegative = reviews
.filter(r => {
const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000)
return (
r.rating <= 2 &&
new Date(r.publishedAtDate).getTime() > thirtyDaysAgo &&
r.text.length > 50
)
})
// Identify common complaints
const complaints = recentNegative.map(r => r.text)
Eコマースと競合情報
Amazon — 価格のモニタリング:
import { scrapeAmazonProduct } from 'actors'
const product = await scrapeAmazonProduct({
productUrl: 'https://www.amazon.com/dp/B08L5VT894',
includeReviews: true,
maxReviews: 200
})
// Filter in code - only recent negative reviews
const recentNegative = product.reviews
?.filter(r => {
const weekAgo = Date.now() - (7 * 24 * 60 * 60 * 1000)
return (
r.rating <= 2 &&
new Date(r.date).getTime() > weekAgo
)
})
console.log(`Price: $${product.price}`)
console.log(`Rating: ${product.rating}/5`)
console.log(`Recent issues: ${recentNegative?.length} complaints`)
カスタムウェブスクレイピング
任意のウェブサイト — カスタム抽出:
import { scrapeWebsite } from 'actors'
const products = await scrapeWebsite({
startUrls: ['https://example.com/products'],
linkSelector: 'a.product-link',
maxPagesPerCrawl: 100,
pageFunction: `
async function pageFunction(context) {
const { request, $, log } = context
return {
url: request.url,
title: $('h1.product-title').text(),
price: $('span.price').text(),
inStock: $('.in-stock').length > 0,
description: $('.description').text()
}
}
`
})
// Filter in code - only available products under $100
const affordable = products.filter(p =>
p.inStock &&
parseFloat(p.price.replace('$', '')) < 100
)
🎨 高度なパターン
パターン1:複数プラットフォームのソーシャルリスニング
import {
scrapeInstagramHashtag,
scrapeTikTokHashtag,
searchYouTube
} from 'actors'
// Run all platforms in parallel
const [instagramPosts, tiktokVideos, youtubeVideos] = await Promise.all([
scrapeInstagramHashtag({ hashtag: 'ai', maxResults: 100 }),
scrapeTikTokHashtag({ hashtag: 'ai', maxResults: 100 }),
searchYouTube({ query: '#ai', maxResults: 100 })
])
// Combine and filter - only viral content across all platforms
const allViral = [
...instagramPosts.filter(p => p.likesCount > 10000),
...tiktokVideos.filter(v => v.playCount > 100000),
...youtubeVideos.filter(v => v.viewsCount > 50000)
]
console.log(`Found ${allViral.length} viral posts across 3 platforms`)
パターン2:リード情報の充実化パイプライン
import { searchGoogleMaps, scrapeLinkedInProfile } from 'actors'
// 1. Find businesses on Google Maps
const restaurants = await searchGoogleMaps({
query: 'restaurants in SF',
maxResults: 100,
scrapeContactInfo: true
})
// 2. Filter for qualified leads
const qualified = restaurants.filter(r =>
r.rating >= 4.5 &&
r.email &&
r.reviewsCount >= 50
)
// 3. Enrich with LinkedIn data (if available)
const enriched = await Promise.all(
qualified.map(async (restaurant) => {
// Try to find LinkedIn company page
// ... additional enrichment logic
return restaurant
})
)
パターン3:競合分析ダッシュボード
import {
scrapeInstagramProfile,
scrapeYouTubeChannel,
scrapeTikTokProfile
} from 'actors'
async function analyzeCompetitor(username: string) {
// Gather data from all platforms
const [instagram, youtube, tiktok] = await Promise.all([
scrapeInstagramProfile({ username, maxPosts: 30 }),
scrapeYouTubeChannel({ channelUrl: `https://youtube.com/@${username}`, maxVideos: 30 }),
scrapeTikTokProfile({ username, maxVideos: 30 })
])
// Calculate engagement metrics in code
return {
username,
instagram: {
followers: instagram.followersCount,
avgLikes: average(instagram.latestPosts?.map(p => p.likesCount) || []),
engagementRate: calculateEngagement(instagram)
},
youtube: {
subscribers: youtube.subscribersCount,
avgViews: average(youtube.videos?.map(v => v.viewsCount) || [])
},
tiktok: {
followers: tiktok.followersCount,
avgPlays: average(tiktok.videos?.map(v => v.playCount) || [])
}
}
}
💰 トークン節約計算ツール
例:投稿が100件あるInstagramプロフィール
MCP アプローチ:
1. search-actors → 1,000 tokens
2. call-actor → 1,000 tokens
3. get-actor-output → 50,000 tokens (100 unfiltered posts)
TOTAL: ~52,000 tokens
ファイルベースのアプローチ:
const profile = await scrapeInstagramProfile({
username: 'user',
maxPosts: 100
})
// Filter in code - only top 10 posts
const top = profile.latestPosts
?.sort((a, b) => b.likesCount - a.likesCount)
.slice(0, 10)
// TOTAL: ~500 tokens (only 10 filtered posts reach model)
節約率:99%削減(52,000 → 500トークン)
🔧 Actor リファレンス
ソーシャルメディア
scrapeInstagramProfile(input)- プロフィール+投稿scrapeInstagramPosts(input)- ユーザーの投稿scrapeInstagramHashtag(input)- ハッシュタグ別の投稿scrapeInstagramComments(input)- 投稿へのコメント
scrapeLinkedInProfile(input)- プロフィール+職歴+メールアドレスsearchLinkedInJobs(input)- 求人情報scrapeLinkedInPosts(input)- プロフィール/企業の投稿
TikTok
scrapeTikTokProfile(input)- プロフィール+動画scrapeTikTokHashtag(input)- ハッシュタグ別の動画scrapeTikTokComments(input)- 動画へのコメント
YouTube
scrapeYouTubeChannel(input)- チャンネル+動画searchYouTube(input)- 動画の検索scrapeYouTubeComments(input)- 動画へのコメント
scrapeFacebookPosts(input)- ページの投稿scrapeFacebookGroups(input)- グループの投稿scrapeFacebookComments(input)- 投稿へのコメント
ビジネスとリード獲得
Google Maps
searchGoogleMaps(input)- 場所の検索(連絡先情報も抽出可能!)scrapeGoogleMapsPlace(input)- 1件の場所の詳細情報scrapeGoogleMapsReviews(input)- 場所のレビュー
Eコマース
Amazon
scrapeAmazonProduct(input)- 商品の詳細情報+レビューscrapeAmazonReviews(input)- 商品レビューのみ
Webスクレイピング
一般的なWebサイト
scrapeWebsite(input)- 複数ページのカスタムクロールscrapePage(url, pageFunction)- 1ページのデータ抽出
⚙️ 設定
環境変数:
# Required - Get from https://console.apify.com/account/integrations
APIFY_TOKEN=apify_api_xxxxx...
Actor の実行オプション:
{
memory: 2048, // MB: 128, 256, 512, 1024, 2048, 4096, 8192
timeout: 300, // seconds
build: 'latest' // or specific build number
}
🎯 こちらと MCP の使い分け
ファイルベース(このスキル)を使用する場合:
- ✅ 大規模なデータセット(100件超)を絞り込む必要がある
- ✅ コードでデータを変換/集計したい
- ✅ 複数の連続した操作を行う
- ✅ 制御フロー(ループ、条件分岐)を使用する
- ✅ トークン効率を最大化したい
MCP を使用する場合:
- ❌ 結果が少ない(10件未満)単純な単発操作
- ❌ 一度限りの探索的なクエリ
- ❌ コードを書きたくない
🔗 リンク
- Apify プラットフォーム:https://apify.com
- Actor ストア:https://apify.com/store
- API ドキュメント:https://docs.apify.com/api/v2
忘れないでください:モデルのコンテキストに返す前に、コードでデータを絞り込みます。トークンを99%節約できるのはここです!
注意点
- Actor の選択は重要です。 ソーシャルプラットフォームごとに専用の Actor があります。専用の Instagram Actor がある場合は、Instagram に汎用スクレイパーを使用しないでください。
- レート制限はプラットフォームやプランによって異なります。 大規模なスクレイピングを実行する前に、Actor のドキュメントで制限を確認してください。
- スクレイピングしたデータの形式は Actor によって異なります。 結果を処理する前に、Actor の出力スキーマを確認してください。
例
例1:Instagramプロフィールのスクレイピング
User: "get the recent posts from this Instagram account"
→ Selects Instagram Profile actor
→ Runs with target profile URL
→ Returns structured post data (text, engagement, dates)
例2:LinkedIn企業情報のスクレイピング
User: "scrape this company's LinkedIn page"
→ Selects LinkedIn Company actor
→ Returns company info, employee count, recent posts
実行ログ
ワークフローを完了するたびに、JSONL エントリーを1件追記します。
echo '{"ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","skill":"Apify","workflow":"WORKFLOW_USED","input":"8_WORD_SUMMARY","status":"ok|error","duration_s":SECONDS}' >> ~/.claude/LIFEOS/MEMORY/SKILLS/execution.jsonl
WORKFLOW_USED は実行したワークフローに、8_WORD_SUMMARY は入力の簡潔な説明に、SECONDS はおおよその実時間に置き換えてください。ワークフローが失敗した場合は、status: "error" を記録してください。