mcpField
A
Apify

Apify

github.com/danielmiesslerデータ・データベース19.6k155 回インストール今日更新
リポジトリ

Apify について

Apify は、TypeScript の Actor ラッパーでソーシャルメディア、企業情報、EC、ウェブサイトをスクレイピングするスキルです。結果をモデルのコンテキストに渡す前に絞り込み、モニタリングやリード獲得に活用できます。

主な機能

  1. 01ソーシャルメディアとウェブのスクレイピング
  2. 02Google Maps で企業リードを検索
  3. 03Amazon の商品とレビューを収集
  4. 04TypeScript で結果を絞り込み・変換
  5. 05複数プラットフォームの並列スクレイピング

活用シーン

  1. 01複数プラットフォームの投稿監視
  2. 02地域企業のリード検索と情報補完
  3. 03Amazon の商品とレビューの追跡
  4. 04ウェブサイトのクロールと抽出データの絞り込み

MCP 対応

ファイルベースの MCP 代替手段として説明されています。TypeScript の Actor ラッパーで結果をモデルのコンテキストに渡す前に処理し、コンテキストを多く使う MCP 呼び出しを避けます。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/danielmiessler/lifeos --skill apify

インストール後、Claude Code で/apifyを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
.gitignore
INTEGRATION.md
index.ts
tsconfig.json
package.json
actors/
index.ts
actors/business/
index.ts
google-maps.ts
actors/ecommerce/
amazon.ts
index.ts
actors/social-media/
facebook.ts
instagram.ts
linkedin.ts
tiktok.ts
twitter.ts
index.ts
youtube.ts
actors/web/
index.ts
web-scraper.ts
examples/
comparison-test.ts
instagram-scraper.ts
smoke-test.ts
skills/
get-user-tweets.ts
types/
index.ts
common.ts
Workflows/
Update.md

詳細

カスタマイズ

実行前に、次の場所にユーザーによるカスタマイズがあるか確認してください: ~/.claude/LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Apify/

このディレクトリが存在する場合は、そこにあるPREFERENCES.md、設定、またはリソースを読み込み、適用してください。これらはデフォルトの動作より優先されます。ディレクトリが存在しない場合は、スキルのデフォルト設定で進めてください。

🚨 必須:音声通知(アクションを起こす前に必ず実施)

このスキルが呼び出されたら、何よりも先にこの通知を送信してください。

  1. 音声通知を送信する:

    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 &
    
  2. テキスト通知を出力する:

    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 リファレンス

ソーシャルメディア
Instagram
  • scrapeInstagramProfile(input) - プロフィール+投稿
  • scrapeInstagramPosts(input) - ユーザーの投稿
  • scrapeInstagramHashtag(input) - ハッシュタグ別の投稿
  • scrapeInstagramComments(input) - 投稿へのコメント
LinkedIn
  • scrapeLinkedInProfile(input) - プロフィール+職歴+メールアドレス
  • searchLinkedInJobs(input) - 求人情報
  • scrapeLinkedInPosts(input) - プロフィール/企業の投稿
TikTok
  • scrapeTikTokProfile(input) - プロフィール+動画
  • scrapeTikTokHashtag(input) - ハッシュタグ別の動画
  • scrapeTikTokComments(input) - 動画へのコメント
YouTube
  • scrapeYouTubeChannel(input) - チャンネル+動画
  • searchYouTube(input) - 動画の検索
  • scrapeYouTubeComments(input) - 動画へのコメント
Facebook
  • 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件未満)単純な単発操作
  • ❌ 一度限りの探索的なクエリ
  • ❌ コードを書きたくない

🔗 リンク


忘れないでください:モデルのコンテキストに返す前に、コードでデータを絞り込みます。トークンを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" を記録してください。

コメント