mcpField
A
Apify

Apify

github.com/danielmiessler数据与数据库19.6k155 次安装今天更新
代码仓库

关于 Apify

Apify 技能通过 TypeScript Actor 封装抓取社交平台、商业信息、电商和网站数据,并在结果进入模型上下文前进行筛选与转换,适用于监测和线索开发。

主要功能

  1. 01抓取社交平台和网站
  2. 02搜索 Google Maps 商业线索
  3. 03采集 Amazon 商品与评价
  4. 04用 TypeScript 筛选和转换结果
  5. 05并行抓取多个平台

适用场景

  1. 01跨平台监测社交内容
  2. 02查找并丰富本地商业线索
  3. 03跟踪 Amazon 商品和评价
  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 actor 抓取社交平台、商业数据和电商信息:Instagram、LinkedIn、TikTok、YouTube、Facebook、Google Maps 商家搜索、Amazon,以及通用网页爬取。TypeScript 封装会在数据到达模型之前先在代码中筛选和转换数据,因此抓取 100 条帖子所需的开销大致相当于抓取 10 条。它还能并行运行多个平台,为社交聆听仪表板提供数据,并将 Google Maps 数据串接到 LinkedIn,以丰富潜在客户信息。

问题所在

通过原始 MCP 抓取数据,会将所有未经筛选的结果直接塞入模型上下文——单个包含 100 条帖子的 Instagram 个人资料就会消耗约 52,000 个 token,其中大部分都是你会丢弃的噪声。你通常只需要热门的 10 条帖子、上周的负面评价,或包含电子邮件地址的合格潜在客户。等数据到达模型后再筛选就太晚了,token 已经消耗。先在代码中筛选,可将 52,000 个 token 减少到约 500 个。

工作原理

此技能是基于文件的 MCP——一种以代码为先的 API 封装,用于替代 token 开销高的 MCP 协议调用。你可以调用 actor 封装,在 TypeScript 中筛选和排序结果,只有筛选后的部分才会进入模型上下文。先处理代码、再进入上下文的这一步,正是节省 95%–99% token 的关键。

工作流路由

工作流触发条件文件
更新更新 Apify 技能、刷新 actor、actor 调用意外失败、每月能力检查Workflows/Update.md
(内联)所有抓取/潜在客户/爬取请求——抓取 Instagram/LinkedIn/TikTok/YouTube/Facebook、Google Maps 潜在客户、Amazon 评价、网页爬取actors/ 下的 actor 封装(见下文的 Actor 参考)

📊 可用 Actor

社交媒体(5 个平台)
  • Instagram(14.5 万用户,4.60★)- 个人资料、帖子、话题标签、评论
  • LinkedIn(2.6 万用户,4.10★)- 个人资料、职位、帖子
  • TikTok(9 万用户,4.61★)- 个人资料、视频、话题标签、评论
  • YouTube(4 万用户,4.40★)- 频道、视频、评论、搜索
  • Facebook(3.5 万用户,4.56★)- 帖子、群组、评论
商业与潜在客户开发
  • Google Maps(19.8 万用户,4.76★)- 价值最高!
    • 搜索商家,提取联系方式、评价和图片
    • 非常适合开发潜在客户
电商
  • Amazon(8,000 用户,4.97★)- 商品、评价、定价
网页抓取
  • Web Scraper(9.4 万用户,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)
电商与竞争情报

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) || [])
    }
  }
}

💰 Token 节省计算器

示例:包含 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 个 token)

🔧 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) - 单个地点的详情
  • scrapeGoogleMapsReviews(input) - 地点评价
电子商务
Amazon
  • scrapeAmazonProduct(input) - 商品详情 + 评价
  • scrapeAmazonReviews(input) - 仅商品评价
网页抓取
通用网页
  • scrapeWebsite(input) - 自定义多页面爬取
  • scrapePage(url, pageFunction) - 提取单个页面

⚙️ 配置

环境变量:

# 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 条结果)
  • ✅ 想用代码转换/汇总数据
  • ✅ 需要执行多个连续操作
  • ✅ 需要控制流(循环、条件判断)
  • ✅ 追求最高 token 效率

使用 MCP:

  • ❌ 结果较少(<10 项)的简单单次操作
  • ❌ 一次性的探索性查询
  • ❌ 不想编写代码

🔗 链接


请记住:在将数据返回到模型上下文之前,先用代码筛选数据。这正是节省 99% token 的关键!

注意事项

  • 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 记录:

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"。

评论

支持 Markdown