更好的阅读体验见飞书文档
解放双手,利用工具轻松找YouTube对标频道 https://rlwxa0zgke.feishu.cn/docx/H2kYdqAQvoB4fwxbHhYcju6kn2b
1、为什么写这个帖子
生财的精神分享利他,本来不打算写这个帖子才拖了这么久,@方波妮 方波妮跟我说写出来呗,你觉得技术含量不高,不过对于小白来说也是很有帮助的。
因此,今天分享一个小工具,对于技术一点都不懂的人不一定能开发出来。 这次做一个全保姆级的分享。
2、工具实现的功能演示
说明:视频就只抓了几个视频,大家可以实际操作不停程序就一直抓了,可能出现的情况就是有重复的URL,其实不影响实际的数据的。我这里 sleep 的数值大了,因此一个视频就可能有重复了。大家视情况可以调整这个数值
3、非常详细的实操流程确保每个人都会
3.1 把扩展程序全部关闭,以免插件会对代码造成干扰
补充一点:插件关闭后,记得重启下Chrome浏览器
链接:chrome://extensions/


3.2 复制代码 Shorts自动爬取核心代码 ,同时 F12调出开发面板(苹果电脑按fn,调出f12)


我们按F12,就是为了调出 Chrome开发者工作

复制文档代码以后,需要在 xx 处替换成自己的apikey,如下图 (这个很重要,再次强调)


- win电脑:代码输入后,按Enter回车键,如下图会有一个跳动的光标,说明这一步完成了

- mac电脑:代码输入后,有如图警告⚠️,请手动输入:allow pasting,按enter结束;再次输入以上代码即可。

3.3 执行核心代码 run() 程序开始执行

直接把 run() 复制粘贴,再按Enter回车,程序就开始跑了

这里的 已爬取 1 就是代码 Shorts自动爬取核心代码 如下图的代码段


如果想结束,导出很简单,就是地址不包含 shorts就好,比如说点一下首页

让地址变成这样

程序就结束了
3.4 执行核心代码 exportCsv() 文件导出
如下图,提示:获取失败:Cannot read properties of umdefine(reading id') 就停止抓取了
输入exportCsv() ,文件会自动下载,全部过程就完成了

如下图就是导出的文件信息了,可以围绕这个代码进行扩展

比如说,导出视频的#标签,在后续就通过#标签来进行一个搜索



其他的扩展:
调用google API来上传视频、下载视频 Youtube自动化工具分享 & 开发复盘
4、用到的知识点
4.1 获取Google API密钥
Shorts自动爬取核心代码 这个文档是全部的代码,用到的知识点如下图

AIzaaq3aJGXdrCMcXpSyCe7_ldNDBH1uzTUYkYY (要换成自己的API KEY)
run() exportCsv()
AIzaaq3aJGXdrCMcXpSyCe7_ldNDBH1uzTUYkYY 就是Google的API Youtube自动化工具分享 & 开发复盘 这个文档有详细的介绍。当然了,也可以不看这个文档。
先搞定第一步,就是获取 Google的API AIzaaq3aJGXdrCMcXpSyCe7_ldNDBH1uzTUYkYY
https://console.cloud.google.com/ 先进入这个网站如下图

点API和服务

跳转到这个页面

点启用API和服务

跳转到下面的页面

输入关键词,选第一个

跳转到下面的页面

与我保持一致,这里要显示 API已启用

点管理

跳转到这个页面再点凭据 ,我这里已经有了,会显示 API密钥

第一次就点创建凭据就好了


创建好后,点显示密钥,在【您的 API密钥】 复制就完成第一步

说明下:如果对代码不感兴趣,只想知道怎么用,请直接看 3、非常详细的实操流程确保每个人都会
4.2 程序执行的关键代码 run() 程序开始执行
Shorts自动爬取核心代码 点此链接可以跳转到 run()的代码段,说明:下面的描述是给想学编程的朋友看的,如无兴趣可直接看实操就好
publishedAt: resp.items[0].snippet.publishedAt,
viewCount: resp.items[0].statistics.viewCount,
likeCount: resp.items[0].statistics.likeCount,
commentCount: resp.items[0].statistics.commentCount,
这里的 publishedAt、viewCount、likeCount、commentCount 就是一个Shorts的 发布时间、观看量、点赞数、评论数
const url = https://youtube.googleapis.com/youtube/v3/videos?part=statistics,snippet&id=${videoID}&key=${apiKey};
这个调用API的地址,我也列出来了

必需参数 part
string
part 参数会指定一个逗号分隔列表,其中包含 API 响应将包含的一个或多个 video 资源属性。
如果该参数标识了包含子属性的媒体资源,相应子属性将包含在响应中。例如,在 video 资源中,snippet 属性包含 channelId、title、description、tags 和 categoryId 属性。因此,如果您设置了 part=snippet,API 响应将包含所有这些属性。
以下列表包含您可以包含在参数值中的 part 名称:
- contentDetails
- fileDetails
- id
- liveStreamingDetails
- localizations
- player
- processingDetails
- recordingDetails
- snippet
- statistics
- status
- suggestions
- topicDetails
https://youtube.googleapis.com/youtube/v3/videos?part=statistics,snippet&id=${videoID}&key=${apiKey}; 在这个请求的链接,我请求了两个参数 statistics, snippet
再看这个代码就清楚了
publishedAt: resp.items[0].snippet.publishedAt,
viewCount: resp.items[0].statistics.viewCount,
likeCount: resp.items[0].statistics.likeCount,
commentCount: resp.items[0].statistics.commentCount,
publishedAt 还自于 snippet
viewCount 还自于 viewCount 、likeCount、commentCount
如果你想知道更详细的,那么就看这个链接 https://developers.google.com/youtube/v3/docs/videos?hl=zh-cn#resource
{
"kind": "youtube#video",
"etag": etag,
"id": string,
"snippet": {
"publishedAt": datetime,
"channelId": string,
"title": string,
"description": string,
"thumbnails": {
(key):
{
"url": string,
"width": unsigned integer,
"height": unsigned integer }
},
"channelTitle": string,
"tags": [ string ],
"categoryId": string,
"liveBroadcastContent": string,
"defaultLanguage": string,
"localized": {
"title": string, "description": string }, "defaultAudioLanguage": string },
"contentDetails": {
"duration": string, "dimension": string, "definition": string, "caption": string, "licensedContent": boolean,
"regionRestriction": {
"allowed": [ string ], "blocked": [ string ] },
"contentRating": {
"acbRating": string, "agcomRating": string, "anatelRating": string, "bbfcRating": string, "bfvcRating": string, "bmukkRating": string, "catvRating": string, "catvfrRating": string, "cbfcRating": string, "cccRating": string, "cceRating": string, "chfilmRating": string, "chvrsRating": string, "cicfRating": string, "cnaRating": string, "cncRating": string, "csaRating": string, "cscfRating": string, "czfilmRating": string, "djctqRating": string,
"djctqRatingReasons": [, string ],
"ecbmctRating": string, "eefilmRating": string, "egfilmRating": string, "eirinRating": string, "fcbmRating": string, "fcoRating": string, "fmocRating": string, "fpbRating": string, "fpbRatingReasons": [, string ], "fskRating": string, "grfilmRating": string, "icaaRating": string, "ifcoRating": string, "ilfilmRating": string, "incaaRating": string, "kfcbRating": string, "kijkwijzerRating": string, "kmrbRating": string, "lsfRating": string, "mccaaRating": string, "mccypRating": string, "mcstRating": string, "mdaRating": string, "medietilsynetRating": string, "mekuRating": string, "mibacRating": string, "mocRating": string, "moctwRating": string, "mpaaRating": string, "mpaatRating": string, "mtrcbRating": string, "nbcRating": string, "nbcplRating": string, "nfrcRating": string, "nfvcbRating": string, "nkclvRating": string, "oflcRating": string, "pefilmRating": string, "rcnofRating": string, "resorteviolenciaRating": string, "rtcRating": string, "rteRating": string, "russiaRating": string, "skfilmRating": string, "smaisRating": string, "smsaRating": string, "tvpgRating": string, "ytRating": string }, "projection": string, "hasCustomThumbnail": boolean },
"status": {
"uploadStatus": string, "failureReason": string, "rejectionReason": string, "privacyStatus": string, "publishAt": datetime, "license": string, "embeddable": boolean, "publicStatsViewable": boolean, "madeForKids": boolean, "selfDeclaredMadeForKids": boolean, "containsSyntheticMedia": boolean },
"statistics": {
"viewCount": string, "likeCount": string, "dislikeCount": string, "favoriteCount": string, "commentCount": string },
"paidProductPlacementDetails": {
"hasPaidProductPlacement": boolean }, "player": {
"embedHtml": string, "embedHeight": long, "embedWidth": long }, "topicDetails": {
"topicIds": [ string ], "relevantTopicIds": [ string ], "topicCategories": [ string ] },
"recordingDetails": {
"recordingDate": datetime },
"fileDetails": {
"fileName": string, "fileSize": unsigned long, "fileType": string, "container": string, "videoStreams": [ {
"widthPixels": unsigned integer, "heightPixels": unsigned integer, "frameRateFps": double, "aspectRatio": double, "codec": string, "bitrateBps": unsigned long, "rotation": string, "vendor": string }
],
"audioStreams": [ {
"channelCount": unsigned integer, "codec": string, "bitrateBps": unsigned long, "vendor": string }
], "durationMs": unsigned long, "bitrateBps": unsigned long, "creationTime": string },
"processingDetails": {
"processingStatus": string,
"processingProgress": {
"partsTotal": unsigned long, "partsProcessed": unsigned long, "timeLeftMs": unsigned long },
"processingFailureReason": string, "fileDetailsAvailability": string, "processingIssuesAvailability": string, "tagSuggestionsAvailability": string, "editorSuggestionsAvailability": string, "thumbnailsAvailability": string },
"suggestions": {
"processingErrors": [ string ], "processingWarnings": [ string ], "processingHints": [ string ], "tagSuggestions": [ {
"tag": string, "categoryRestricts": [ string ] }
], "editorSuggestions": [ string ] },
"liveStreamingDetails": {
"actualStartTime": datetime, "actualEndTime": datetime, "scheduledStartTime": datetime, "scheduledEndTime": datetime, "concurrentViewers": unsigned long, "activeLiveChatId": string }, "localizations": {
(key): {
"title": string, "description": string }
}
}
讲这么细的目的是让你对我的代码进行修改,如果你想获取视频更多的参考,你就不用来问我了,授人以鱼,不如授人以渔。
4.3 程序执行的关键代码 exportCsv() 文件导出

这一部分的代码没有特别要讲的,原理就是把存到浏览器的信息保存到后缀为 csv的文件,这里的result你自己可以进行修改,取一个自己喜欢的名字就好。
5、感谢
感谢 @方波妮 的督促,不然这个帖子可能遥遥无期哈哈哈
感谢 马哥@老马内容出海 Youtube官方api调用以及selenium方式采集 提供的信息
感谢 @敖健龙 Youtube自动化工具分享 & 开发复盘 提供的好用的软件