关于 Apify
Apify 技能通过 TypeScript Actor 封装抓取社交平台、商业信息、电商和网站数据,并在结果进入模型上下文前进行筛选与转换,适用于监测和线索开发。
主要功能
- 01抓取社交平台和网站
- 02搜索 Google Maps 商业线索
- 03采集 Amazon 商品与评价
- 04用 TypeScript 筛选和转换结果
- 05并行抓取多个平台
适用场景
- 01跨平台监测社交内容
- 02查找并丰富本地商业线索
- 03跟踪 Amazon 商品和评价
- 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 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 参考
社交媒体
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)- 单个地点的详情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 项)的简单单次操作
- ❌ 一次性的探索性查询
- ❌ 不想编写代码
🔗 链接
- Apify 平台:https://apify.com
- Actor 商店:https://apify.com/store
- API 文档:https://docs.apify.com/api/v2
请记住:在将数据返回到模型上下文之前,先用代码筛选数据。这正是节省 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"。