YouTube KOL 信息爬取:输入搜索关键词 → 输出创作者列表(频道名称、URL、视频数量、最相关视频的播放量、联系邮箱/社交链接) 触发场景: - “按关键词搜索 YouTube 以查找创作者信息” - “收集 YouTube 创作者联系信息” - “提取频道数据和邮箱”
YouTube — KOL InfoScraping. 输入搜索关键词 — 从搜索结果输入每个创建者的频道页面 — 提取频道名称、 URL、 视频计数、 大多数
功能概述
YouTube — KOL InfoScraping. 输入搜索关键词 — 从搜索结果输入每个创建者的频道页面 — 提取频道名称、 URL、 视频计数、 大多数是一项面向实际任务的技能。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。
核心要点
- 使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要求处理异常情况。
- 该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。
- 从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。
使用与执行
实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。
结果检查与注意事项
执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
YouTube — KOL 信息抓取
输入搜索关键词 → 从搜索结果中逐个进入创作者频道页 → 提取频道名称、URL、视频总数、最相关视频的播放量、联系邮箱(优先从频道简介中正则匹配 → 其次尝试从个人网站提取 → 最后回退至社交平台链接)
目标
按关键词在 YouTube 上执行搜索,收集搜索结果中每位创作者的频道基础信息及联系方式。
前置条件
- 浏览器已打开 YouTube 网站:
https://www.youtube.com
前置条件描述的是任务启动前网站必须所处的状态。它不指定 browser-act 如何连接浏览器——调用方应根据自身运行环境选择连接方式。
执行前检查
1. 工具就绪性
若 browser-act 已完成更新、API Key 已验证、且当前会话中已加载用量,则跳过此步骤。
否则请按顺序执行以下操作;任一环节失败即中止:
uv tool upgrade browser-act-cli || uv tool install browser-act-cli --python 3.12browser-act browser list验证 API Key 是否可用。若返回缺失 Key 错误,请向用户完整展示错误信息(含注册链接),待其完成注册后再重试- 通过 Skill 工具调用
browser-act加载 browser-act 用量
能力组件
所有在探索过程中发现的原子能力均列于下方;执行时按需组合使用。
API:关键词搜索 — 获取首页视频列表
导航至搜索页后,从页面内嵌的 ytInitialData 中提取结果:
browser-act navigate 跳转至搜索页:
https://www.youtube.com/results?search_query={keyword}
页面加载完成后,执行 browser-act eval(运行时数据提取):
// keyword={搜索关键词}
const d = ytInitialData;
const contents = d?.contents?.twoColumnSearchResultsRenderer?.primaryContents?.sectionListRenderer?.contents;
const videos = [];
contents.forEach(s => {
(s?.itemSectionRenderer?.contents || []).forEach(i => {
if (i.videoRenderer) {
const v = i.videoRenderer;
videos.push({
title: v.title?.runs?.[0]?.text,
videoId: v.videoId,
views: v.viewCountText?.simpleText || v.viewCountText?.runs?.map(r => r.text).join(''),
channel: v.ownerText?.runs?.[0]?.text,
channelUrl: v.ownerText?.runs?.[0]?.navigationEndpoint?.browseEndpoint?.canonicalBaseUrl,
channelId: v.ownerText?.runs?.[0]?.navigationEndpoint?.browseEndpoint?.browseId
});
}
});
});
// 提取分页 continuation token
const lastItem = contents[contents.length - 1];
const continuationToken = lastItem?.continuationItemRenderer?.continuationEndpoint?.continuationCommand?.token;
JSON.stringify({ count: videos.length, videos, continuationToken: continuationToken || null })
响应结构:{ "count": N, "videos": [...], "continuationToken": "..." }
API:关键词搜索 — 加载更多结果(分页)
browser-act eval(请求在浏览器内发起,会话凭据自动注入):
// continuationToken={上一页返回的 continuationToken}
const apiKey = ytcfg?.data_?.INNERTUBE_API_KEY;
const ctx = ytcfg?.data_?.INNERTUBE_CONTEXT;
const res = await fetch('https://www.youtube.com/youtubei/v1/search?prettyPrint=false&key=' + apiKey, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ context: ctx, continuation: '{continuationToken}' })
});
const data = await res.json();
const actions = data?.onResponseReceivedCommands?.[0]?.appendContinuationItemsAction?.continuationItems || [];
const videos = [];
actions.forEach(i => {
if (i?.itemSectionRenderer?.contents) {
i.itemSectionRenderer.contents.forEach(c => {
if (c.videoRenderer) {
const v = c.videoRenderer;
videos.push({
title: v.title?.runs?.[0]?.text,
videoId: v.videoId,
views: v.viewCountText?.simpleText || v.viewCountText?.runs?.map(r => r.text).join(''),
channel: v.ownerText?.runs?.[0]?.text,
channelUrl: v.ownerText?.runs?.[0]?.navigationEndpoint?.browseEndpoint?.canonicalBaseUrl,
channelId: v.ownerText?.runs?.[0]?.navigationEndpoint?.browseEndpoint?.browseId
});
}
});
}
});
const nextToken = actions[actions.length - 1]?.continuationItemRenderer?.continuationEndpoint?.continuationCommand?.token;
JSON.stringify({ count: videos.length, videos, continuationToken: nextToken || null })
响应结构与第一页一致。continuationToken 为 null 表示无更多结果。
API:频道基础信息提取
导航至频道页后,从 ytInitialData 中提取基础信息:
browser-act navigate 跳转至频道页:
https://www.youtube.com{channelUrl}
channelUrl 格式为 /@ChannelHandle(源自搜索结果)。
页面加载完成后,执行 browser-act eval:
const d = ytInitialData;
const meta = d?.metadata?.channelMetadataRenderer;
const h = d?.header?.pageHeaderRenderer?.content?.pageHeaderViewModel;
const rows = h?.metadata?.contentMetadataViewModel?.metadataRows;
const desc = meta?.description;
const emailMatch = desc?.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}/g);
JSON.stringify({
channelName: meta?.title,
channelUrl: meta?.vanityChannelUrl,
channelId: meta?.externalId,
description: desc,
emailInDesc: emailMatch,
handle: rows?.[0]?.metadataParts?.[0]?.text?.content,
subscribers: rows?.[1]?.metadataParts?.[0]?.text?.content,
videoCount: rows?.[1]?.metadataParts?.[1]?.text?.content
})
响应结构:{ "channelName": "...", "channelUrl": "...", "channelId": "UC...", "description": "...", "emailInDesc": ["email@example.com"] | null, "handle": "@...", "subscribers": "100K subscribers", "videoCount": "546 videos" }
API:频道 About 数据 — 社交链接提取
通过频道页上的 browse API 获取 About 数据(社交链接、国家、加入日期等):
browser-act eval(请求在浏览器内发起,无需登录):
(async () => {
const d = ytInitialData;
const desc = d?.header?.pageHeaderRenderer?.content?.pageHeaderViewModel?.description?.descriptionPreviewViewModel;
const ep = desc?.rendererContext?.commandContext?.onTap?.innertubeCommand?.showEngagementPanelEndpoint;
const cont = ep?.engagementPanel?.engagementPanelSectionListRenderer?.content?.sectionListRenderer?.contents?.[0]?.itemSectionRenderer?.contents?.[0]?.continuationItemRenderer?.continuationEndpoint;
const token = cont?.continuationCommand?.token;
if (!token) return JSON.stringify({ error: 'no continuation token' });
const apiKey = ytcfg?.data_?.INNERTUBE_API_KEY;
const ctx = ytcfg?.data_?.INNERTUBE_CONTEXT;
const res = await fetch('https://www.youtube.com/youtubei/v1/browse?prettyPrint=false&key=' + apiKey, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ context: ctx, continuation: token })
});
const data = await res.json();
const items = data?.onResponseReceivedEndpoints?.[0]?.appendContinuationItemsAction?.continuationItems;
const aboutRenderer = items?.find(i => i?.aboutChannelRenderer);
const vm = aboutRenderer?.aboutChannelRenderer?.metadata?.aboutChannelViewModel;
if (!vm) return JSON.stringify({ error: 'no aboutChannelViewModel' });
return JSON.stringify({
country: vm.country,
joinedDate: vm.joinedDateText?.content,
subscribers: vm.subscriberCountText,
videoCount: vm.videoCountText,
viewCount: vm.viewCountText,
links: (vm.links || []).map(l => ({
title: l?.channelExternalLinkViewModel?.title?.content,
link: l?.channelExternalLinkViewModel?.link?.content
}))
});
})()
响应结构:{ "country": "...", "joinedDate": "...", "links": [{"title": "Instagram", "link": "instagram.com/xxx"}, ...] }
API:社交链接过滤 — 提取个人网站邮箱
从 About 数据返回的 links 中,剔除需登录才能访问的社交平台,仅保留公开可访问的个人/公司官网,并逐一访问以提取邮箱。
过滤规则 — 排除以下域名(需登录或通常不含邮箱):
instagram.com、tiktok.com、linkedin.com、x.com、twitter.com、facebook.com、discord.gg、discord.com、skool.com、apps.apple.com、play.google.com、github.com、buymeacoffee.com、youtube.com
browser-act eval(过滤逻辑,可在浏览器或本地执行):
// links={About 数据返回的 links 数组}
const socialDomains = ['instagram.com','tiktok.com','linkedin.com','x.com','twitter.com','facebook.com','discord.gg','discord.com','skool.com','apps.apple.com','play.google.com','github.com','buymeacoffee.com','youtube.com'];
const websiteLinks = links.filter(l => {
const domain = l.link?.toLowerCase() || '';
return !socialDomains.some(sd => domain.includes(sd));
});
JSON.stringify({ websiteLinks })
对 websiteLinks 中每个链接执行如下流程:
browser-act navigate 访问目标站点 → browser-act wait stable 等待页面稳定 → browser-act eval:
// 双路匹配邮箱(正文正则 + mailto 链接)
(() => {
const text = document.body.innerText;
const emailsInText = text.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}/g) || [];
const mailtoLinks = Array.from(document.querySelectorAll('a[href^="mailto:"]')).map(a => a.href.replace('mailto:', '').split('?')[0]);
const allEmails = [...new Set([...emailsInText, ...mailtoLinks])];
return JSON.stringify({ emails: allEmails });
})()
若首页未提取到邮箱,则查找 Contact / About 页面链接并最多下探一级:
(() => {
const contactLinks = Array.from(document.querySelectorAll('a')).filter(a => {
const t = (a.textContent + ' ' + a.href).toLowerCase();
return t.includes('contact') || t.includes('about');
}).map(a => a.href).filter(h => h.startsWith('http'));
return JSON.stringify({ contactLinks: [...new Set(contactLinks)].slice(0, 3) });
})()
访问 Contact 页面并重复邮箱提取流程;一旦找到邮箱即终止;最多访问两级(首页 + Contact 页面)。
枚举参数
无枚举参数。搜索关键词由用户指定,不存在预定义枚举值。
分页机制
API 分页:使用 continuationToken,类型为游标(cursor),起始值:从 ytInitialData 中最后一个 continuationItemRenderer 获取;下一页值:从每次 API 响应中最后一个 item 的 continuationItemRenderer.continuationEndpoint.continuationCommand.token 提取;终止条件:continuationToken 为 null,或响应中未包含新的 videoRenderer。
成功标准
- 搜索结果:
videos.length ≥ 1 - 频道基础信息:
channelName和channelId均非空 - About 数据:
links数组成功获取(允许为空) - 邮箱提取:对每个频道完整执行邮箱提取链(简介正则匹配 → 个人网站提取 → 社交平台链接回退)
- 字段完整性:
channelName、channelUrl、videoCount每个频道的非空率达 100%
已知限制
- 邮箱获取成功率取决于创作者是否在个人网站上公开邮箱;并非所有频道都提供邮箱
- 需登录的社交平台(如 Instagram、LinkedIn)不会被访问,直接跳过
- 个人/公司网站邮箱提取最多下探两级(首页 + Contact 页面),不进行全站爬取
- 每页搜索结果约含 18–20 条视频;分页依赖 continuation token
ytInitialData和ytcfg是 YouTube 页面内嵌的运行时变量;页面结构变更可能影响路径访问
经验记录
路径:{working_dir}/browser-act-skill-forge-memories/youtube-kol-scraper-youtube-kol-scraper.memory.md
执行前:若该文件存在,请先读取——其中记录了历史执行中遇到的异常事件(例如端点变更),据此调整本次执行策略。
执行后:若发生异常事件(端点失效、页面重构、反爬升级等),追加一行记录:
{YYYY-MM-DD}: {发生了什么} → {结论}
正常执行无需写入。
文件格式示例:
# youtube-kol-scraper-youtube-kol-scraper 经验记录 2026-04-16: YouTube reveal_business_email API 无论使用 Stealth Chrome 还是 Real Chrome 均返回 400(BotGuard 编码不兼容) → 放弃 reCAPTCHA 路径 2026-04-16: 社交平台简介(Instagram/X/TikTok)极少包含邮箱 → 不值得访问 2026-04-16: 个人/公司官网是最佳邮箱来源(命中率约 3/10),通过 mailto 链接 + 正则提取 → 作为主邮箱提取路径
热门AI工具
相关专题
youtube(油管)是源自美国的视频分享网站,也是当前全球最大的视频搜索和分享平台,让用户上传、观看、分享及评论视频。想了解更多相关的内容,可阅读本专题下面的相关文章。
9902
2024.10.28
本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。
0
2026.10.22
本专题介绍Gradle Wrapper的基本作用,涵盖文件组成、生成方法、版本配置和任务调用,帮助你理解项目如何使用指定的Gradle版本,减少不同开发环境带来的构建差异。
0
2026.10.22
本专题整理Golangci-lint常用Linters的用途与配置方法,覆盖错误处理、无效代码、安全、复杂度、命名和依赖检查,帮助项目合理选规则。
0
2026.10.22
本专题介绍Gradle Java项目构建方法,涵盖Java插件配置、依赖声明、源码编译、测试执行和打包检查,帮助你理解各阶段的任务关系,逐步完成项目构建。
0
2026.10.22
本专题汇总PHP常见时间戳漏洞,包括2038年溢出、时区漂移、时间戳伪造、重放攻击、时间盲注与日志审计失效等,并给出升级64位环境、使用 DateTimeImmutable、统一UTC、严格超时校验、预处理绑定、hash_equals 比对等修复方案,帮助开发者快速排查和加固时间相关代码。
0
2026.10.22
本专题聚焦Golangci-lint YAML配置文件,讲清运行参数、规则启停、目录排除、问题过滤及严重级别设置,便于团队统一检查标准。
0
2026.10.22
本专题讲解Golangci-lint的安装、初始化、基础命令和首次代码检查,覆盖本地环境、Docker及多平台用法,帮助Go开发者快速上手。
0
2026.10.22
PHP2Shell漏洞是什么,哪些PHP版本和运行环境会受到影响,服务器应该如何检测与修复?本专题提供版本自查脚本、Linux与Docker升级命令、PHP-FPM和Apache排查步骤,以及修复验证、临时缓解和应急响应方案。
0
2026.10.22
热门下载
相关下载
精品课程