本文来自知乎@李南瓜,但是原文以及被作者自行删除。该文从 Cache 中获取,并调整一些文字。
前言
这篇文章将告诉你如何通过 Python
打造一台全自动发布 YouTube
视频并赚取美元收益的系统。
其中一个 YouTube
频道从零起步到达到最低开通获利门槛,只花了一个月。前天成功开通了 Adsense
账号并投放视频广告,今天查看频道第一天的广告收益约 $90
。以这个基准值计算的,大概每个月有约 ¥1.8 万
的收益。
基本上,整个视频的制作、上传发布、获取收益等环节都不需要人工介入。整个系统以全自动模式运行,仅在出现 bug
时需要人肉修复。
备注:
- 本文
不包含
完整的代码实现,仅做思路分享 - 本系统
仅个人使用
,不出售
,不出租
,不代开发
同类系统 - 本人
不收徒
,不留
联系方式,没有群
,无
收费课程 - 本人仅为知识分享,但
没有义务
解答你的任何个人疑问
如果以上这些前置条件你都可以接受,那我们可以正式开始自动赚美元系统的打造之旅了。
技术栈
- 程序语言:
Python 3
- 服务器:
Google Cloud Platform
- 数据库:
Firestore
- 程序托管:
Github
、Google Cloud Source Repositories
- 自动任务调度:
Cloud Scheduler
- 第三方库、软件:
FFmpeg
、Requests
、PIL
、Selenium
- IM:
Telegram
系统功能模块分解
一个全自动发布 YouTube 视频的系统,大致需要包含以下几个模块,根据你自己选择的类别、原始素材的不同,可能会有一定差异。
- 任务分配模块
- 原始图片、音频、视频素材提取、制作模块
- YouTube 视频上传模块
- 服务器自动部署模块
- 程序运行结果通知模块
- 程序自动更新模块
接下来我们将对每个模块一一展开阐述。
任务分配模块
对于一个自动化制作视频并上传的系统,整个系统运作的第一步是系统需要知道自己当前需要从哪个任务开始执行。
以一个最简单的任务系统来说,假如整个任务是一个线性增长的任务 ID,那么这个任务分配模块也就等同于一个自增 ID 的数据库字段。
对于一个现实的任务分配模块而言,肯定要比这复杂一些,不过最核心的还是告诉程序接下来要进行哪个任务。
由于整个系统基本都架构在强大而易用的 Google Cloud Platform
(后面简称 GCP
)平台之上,所以任务分配模块我直接使用 GCP
平台上的 NoSQL
数据库: Cloud Firestore
。
什么是 Cloud Firestore
呢?
借用 Firestore
官网来做个简单介绍:
Cloud Firestore 是一款 NoSQL 文档数据库,它使您可以在全球范围内轻松存储、同步和查询您的移动应用及 Web 应用的数据。
我使用 Firestore
来做很多事,在任务分配模块,只需要新建一个 专属的 Collection
及每个标签对应的 Document
即可。
包含 counter
、 task
、 taskID
等三个 Document
,其中 task
文档中的 status
的值设置为 on
,代表当前任务状态为可继续执行。如果某个阶段的任务执行完毕,或有严重 bug
需要人工修复,那么这个值就会被设置为 off
。
其中 taskID
仅为演示才临时添加的 Document
,实际上的任务分配模块是在另一个专属的 Collection
中,要复杂的多,但核心是一样的。
任务分配模块的具体执行流程:
- 程序读取
task
文档中的status
的值,如果为:on
,则任务继续执行,如果为off
,程序直接退出并发送通知消息 - 程序随机提取一个
taskID
文档,并解析当前需要执行的任务 ID,根据一定规则解析成需要下载的原始素材 URL - 程序在后续动作中成功上传一个
YouTube
视频后,更新taskID
中对应的任务 ID - 某个时间段内任务数量达到上线,设置
task
文档中status
的值为off
视频制作模块
不同于其他大多数人,目标是能实现视频的全自动制作与上传,整个过程不需要人工参与,所以这个前提让我直接摒弃了无法用程序生成的视频类型,比如:自拍讲解、真人出镜、影视剪辑等等。
以我自己某个频道的视频制作来做案例,那么这个用程序自动生成视频的流程是这样的:
- 下载音频
MP3
的原始素材 - 制作封面图片
- 用音频
MP3
和封面图用程序自动合成完整视频
下载 MP3 素材
使用 Python
的 Requests
库,或者使用 Linux
下的命令行工具 wget
、curl
都是可以的。
制作封面图
使用 Python
的 PIL
库。
提前准备好背景图、字体、标题文字,用 PIL
就能自动生成任何需要的图片。具体实现思路可以自行 Google,当初我也是花了不少时间在研究这个库(为了让图上的文字能自动居中)。
下面的代码仅供参考(这是我程序中使用的原始代码)
avatar = Image.open(BG_PATH)
drawAvatar = ImageDraw.Draw(avatar)
# 背景图尺寸
xSize, ySize = avatar.size
#字体大小,根据背景图尺寸 和 字数个数而定 最大 400
fontSize = min((xSize - 300) // len(cover_title), 400)
myFont = ImageFont.truetype(FONTS_PATH, fontSize) # 中文字体
# print('font Size = {}'.format(fontSize))
# 放置文字的坐标
xPos = (xSize - fontSize * len(cover_title)) / 2
yPos = (ySize - 400 - fontSize) / 2
# print('xPos = {}, yPos = {}'.format(xPos, yPos))
# 生成封面图
drawAvatar.text([xPos, yPos], cover_title, fill=(255, 224, 41), font=myFont)
del drawAvatar
avatar.save(COVER_PATH) # 保存封面图
合成视频
使用神器 FFmpeg
比如,一条 16.8M 的音频,搭配背景图,生成的 1080P 清晰度的视频大小,也只是 16.9M 而已。
下面是耗费无数心血测试成功,用来生成视频的 FFmpeg
命令,供你参考。具体 FFmpeg
使用方法,请自行 Google。
command = f'ffmpeg -loglevel panic -r 0.01 -loop 1 -i {cover_path} -i {mp3_file_path} -c:v libx264 -t {mp3_length} {video_file_path}'
subprocess.run(command, shell=True)
又一个让我耗费无数日日夜夜的模块。
起初,我使用的是 YouTube
官方的 API 上传接口: YouTube Data API V3 。
这个接口的使用非常简单,也特别稳定,按照官方教程基本都能操作成功。但,由于两点特别的理由(虽然算不上致命缺陷),让我下决心转向了使用不太稳定又不省心的 Selenium
模块进行模拟上传。
- YouTube API 每天最多只能上传 6 条视频,上传更多需要填写一个超长的申请表且不一定能通过审核
- YouTube API 两个月前开始要求经过认证才能给“第三方”使用,除非你开通 每个月 $6 的
G Suit
套装
6 刀我暂时是不想出的,但更重要的是每天只能上传 6 条的配额,这点让我无法忍受。毕竟,咱这种自动生成的视频,无法跟别人那种动辄吸引百万播放的精美制作视频相比,只能以量取胜。
每天 6 条,喝西北风去啊。
无奈,Selenium
模拟上传走起呗。
关于这个,我不想多说,有需要的,可以参考一个 Github 上的开源库,我自己的上传模块也是基于这位小哥的代码进行个性化定制而来的。
Github: youtube_uploader_selenium
要说最大的贡献,就是这个开源库让我意识到使用 Selenium
模拟上传 YouTube
视频是切实可行的(之前我一直以为 YouTube
上传页面没有使用标准 input
是无解的)。
信心有了,开源库也有了,相信你也可以很快搞定的,起码应该比我这个半路出家自学 Python
的家伙应该顺利很多吧。
服务器自动部署模块
前面所有的模块开发完毕后,你就要面临一个很重要的环节了:把程序部署到服务器上去。
虽说可以在类似 Vultr
这样的平台采购一台 VPS
并把程序部署上去并不间断运行,但基于以下几条理由,我继续选择了 GCP
旗下的 Google Cloud Engine
。
- 使用
Google Cloud Engine
可以和GCP
的其他功能无缝衔接,比如Firestore
等 - 选择
抢占式实例
,一台2vCPU、1G 内存
的实例,每个月只需要 $2,实际运行费用则只有 $1 左右(并没有 24 小时运行) - 在
Google Cloud Engine
内上传视频到YouTube
是免流量费的
鉴于此,选择将程序托管在 GCE
并选择抢占式实例。
注意,这类抢占式实例价格只有标准实例的一半左右,但是每次运行时间最长不能超过 24 小时,但对于我们的任务而言,这点完全不成问题。
在 GCP
上配置一个 服务器模版
并实现全自动 启动实例
、销毁实例
是一件让人体验极其愉悦的事情。以下是大体的操作流程:
- 开一台普通实例(抢占式也无所谓,这里仅作为基础配置使用)
- 在这台服务器上部署你的程序,安装所有必要的模块,调试并运行成功
- 使用
crontab
设置每分钟运行一次你的主程序(配置 flock 锁确保不重复启动) - 关闭服务器,以这台配置好的服务器为基础,新建一个
机器映像
- 以前面新建的
机器映像
为基础,新建一个实例模版
,在实例模板中选择抢占式实例
- 配置一个云函数
Google Cloud Functions
,实现以实例模版
为基础的自动启动或销毁实例群组
- 配置一个
Cloud Scheduler
,设置为从早上 10 点到晚上 22 点,每小时自动启动一台抢占式实例
经过以上配置,现在的程序运行机制是这样的:
Cloud Scheduler
会在每天上午 10 点,到晚上 22 点之间,每小时访问一次你的云函数。- 这个云函数会自动启动一台你之前配置好的抢占式实例。
- 一旦服务器启动完毕,便会每分钟运行一次你的主程序。但由于设置了
flock
程序锁,所以不用担心程序会重复启动。只有当前程序运行完毕后,才会在下一分钟再次启动新任务。 - 程序在一小时内制作并上传一定数量的视频,达到限额(我设置的是每小时 8 个),则自动发送销毁当前服务器的指令,同时将任务状态设置为
off
,等待下一小时的唤醒。 - 经过一小时后,
Cloud Scheduler
再次访问你的任务云函数并启动实例、运行程序、销毁实例,以此循环,直到晚上十点,结束一天的任务,进入休息状态。等待第二天上午十点的到来,并开始新一天的任务。
恭喜你,你有了一套完整的全自动运行并帮你赚取美元收益的 YouTube 视频发布系统
。
程序自动更新模块
对于一个已经部署好服务器模板的系统而言,如何自动更新程序版本成了另外一个需要解决的小问题。
最早,我需要手动 SSH
连接 VPS
,再上传新版程序,但这明显不可持续。
后来,我通过云函数中转的方式更新程序版本。
现在,我把程序托管在 Github
私人仓库,并在 Google Cloud Source Repositories
进行同步。然后,在程序自动运行的命令中,加入自动更新代码的环节,就可以实现这样的效果:
每次更新完代码,直接上传到 Github
仓库,Google Cloud Source Repositories
会自动同步最新代码。在主程序运行前会自动拉取最新代码,然后才开始运行主程序。
比如我配置的一份自动运行命令(关键内容已启用自动混淆功能)
#!/bin/sh
echo $'\n'
time=$(date "+%Y-%m-%d %H:%M:%S")
echo "${time}"
cd /home/whoami/iYTB
git pull https://source.developers.google.com/p/ytb/r/github_whoami_iytb
/usr/bin/python3 iYTB.py >> iYTB.log 2>&1
程序运行结果通知模块
由于程序以自动化方式运行于一台随时可能会自我销毁的服务器中,打通一条发送任务状态的消息通道就有了很大的必要性。
好在,这样的一个消息通道实现起来是非常容易的,比如我目前在用的这个方式: Telegram 群组通知
基本只需要三个步骤即可。
- 申请一个
Telegram Bot
- 新建一个
Telegram Group
,把机器人拉入群组并设置为管理员 - 部署一个能向群组发送消息的
Cloud Functions
部署完毕以后,不管是程序的出错消息、意外 bug
、成功通知等,都可以用发送 GET
请求的方式到云函数,你就可以在群组内收到最新的消息通知了,类似这样:
截图是程序的运行日志(经过简单修改以便大家不那么容易猜测出我实际上传的视频内容),包含了程序开始时间、cookies 状态、上传视频的标题、程序实际上传所化的时间、发布成功的视频 ID、程序完整运行时长等。
另外,还可以实时接收到任务状态通知:
除此外,还有好几个单独的频道用于发送其他类型的通知消息,这里不再赘述。
以上就是整个 YouTube 自动化运作系统
及各个模块的简要介绍,希望这些内容能对你有所帮助。