脚本开发环境
说明下开发和实施这个自动化脚本的几个微不足道的小前提:
- 电脑或Mac或Surface,操作系统不限,Mac或Linux优先
- 手机
- 有条件访问Youtube或Tiktok(无需注册账号)
- 国内平台的APP及账号
- 每月1-2美金的服务器费用
功能框架
按照整个流程步骤,首先是要完成对若干频道的监测,这部分可以使用平台API如Youtube API或第三方API如Pytube,也可以直接使用selenium库进行更直接的网页监控,一旦发现有新视频上架立刻进入下载流程,下载功能可以通过第三方API如Pytube或第三方下载网页用selenium脚本下载。接着,使用FFMPEG/Opencv/Pillow等第三方多媒体库对视频进行编辑,为发布到自媒体平台提供必要的资源,如画面缩放锐化亮度调整,抽帧做封面,翻译标题,添加翻译字幕,美化封面等等。最后,使用selenium把发布内容依次输入到自媒体平台的上传界面里。听上去是不是超级简单,接下来我们就一个一个步骤详细操作一遍。
安装Python环境
既然面向零基础,那么Python环境搭建也带过一下,不需要看的可以直接跳过这一章节。当前我们虽然使用本地计算机进行调试,但由于未来我们的搬运脚本是需要运行在云上里的,因此请尽量优先选择Mac或Ubuntu等比较常用的操作系统,方便提前熟悉服务器配置环境,当然Python是跨平台的语言,因此使用Windows也完全没有问题。首先确保你的电脑里安装了Python3,一般较新的MacOS或Linux发行版都是安装的了。用个命令读取一下版本确认一下:
$ python --version
如果不是python3.x,再试一下:
$ python3 --version
如打印结果没有Python 3.x.x,那就需要去python.org根据提示进行下载和安装,也是很简单。
第二步需要确保包安装器 pip 也安装完成,命令行中输入:
$ pip -V
或
$ pip3 -V
进行确认,如未安装,可以使用以下命令快速安装:
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ sudo python get-pip.py
或
$ sudo python3 get-pip.py
接着讲下文本编辑器环境,当然作为解释性语言,系统默认的文本编辑器都可以作为Python编写的工具。但有时候我们为了提高我们效率的功能,如语法错误提醒,如函数/变量自动补全等等,会使用一些功能更强大的编辑器,如我比较喜欢的Sublime Text,它轻量免费,又有大量插件可以按需安装,可以上https://www.sublimetext.com/下载安装,安装完界面如下:
安装完后别忘在Install package里装上Anaconda插件,方便Python语法的提示和补全。
最后一步,运行Python程序。最简单的方式,当然就是直接在命令行中用Python命令直接运行脚本,如:
$ python hello.py
当然调试过程中更推荐直接用Sublime Text的Build功能在编辑器里直接看到运行结果。
好了,基本的Python环境我们有了,接下来让我们通过编写一个个搬运相关的分解脚本,完成整个自动化功能吧。
脚本一:Youtube影片获取
常见的后台调取Youtube频道和影片数据的方法有两种,一种是使用Google官方的Youtube Data API,另一种使用第三方Python库Pytube,由于官方API需要注册账号激活API等等操作,也不支持任意下载,而Pytube数据功能完整,还可以下载视频的各个分辨率版本,所以我们就统一使用Pytube来完成所有在Youtube上的操作。
需要注意,由于现在我们还在本地执行,须确保执行脚本的电脑可以访问Youtube官网,这样Pytube的接口才可以读取到Youtube上的信息。
1) 读取指定视频的信息。
读取频道前,我们先写个几行读取某个指定视频的信息,首先import Pytube模组,使用YouTube()接口导入视频的URL地址生成video对象,这里随意找了个视频地址:
from pytube import YouTube
video = YouTube("https://www.youtube.com/watch?v=tO_L8bik10k")
尝试打印video对象里的各种参数,更多的参数可参考文档https://pytube.io/en/latest/api.html#youtube-object:
print("Video_title = " + video.title)
print("Video_author = " + video.author)
print("Video_length = " + str(video.length))
打印结果如下:
Video_title = Los Angeles Clippers vs. Brooklyn Nets Full Game Highlights | Nov 12 | 2022-23 NBA Season
Video_author = The Asylum
Video_length = 578
[Finished in 4.1s]
2) 下载视频
众所周知Youtube的视频都会有不同的分辨率进行选择,我们Pytube进行下载的时候,也是可以选择不同的分辨率的,一般质量较好的视频都是有1080p的,而且根据我的观察,很多Short影片(Youtube的短视频)还会有2160p这样的高质量画面可供下载。在Pytube里我们把这些不同的格式和分辨率的副本叫做流(Stream)。我们随便找个Short影片看看它有多少Stream:
from pytube import YouTube
video = YouTube("https://www.youtube.com/watch?v=WZbKAFP1090")
print(video.streams)
执行以上代码后的打印信息会相当庞大,粗粗看下它是列表结构,列表中的每一项都是包含了每个stream的详细信息的字典:
[..., <Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2" progressive="True" type="video">,, ...]
如果我们只想看到分辨率为720p的视频,只需要在打印的代码调用streams的filter方法,过滤出我们需要的stream:
print(video.streams.filter(res="720p"))
当然,我们搬运视频当然最好是用比较高的分辨率,一般不建议使用大于1440p,因为过高的分辨率可能会在后面上传自媒体平台时被平台压缩,导致画质更差,因此用1080p一般就足够了,所以让我们用一个for循环找出res不大于1080p的画质最高的那个stream:
current_res = 0
stream_highest_res = video.streams[0]
for everystream in video.streams.filter(type="video"):
if int(everystream.resolution[:-1]) > 1080:
continue
if int(everystream.resolution[:-1]) > current_res:
current_res = int(everystream.resolution[:-1])
stream_highest_res = everystream
print("Highest stream: ", stream_highest_res)
从而找到了:
Highest stream: <Stream: itag="248" mime_type="video/webm" res="1080p" fps="30fps" vcodec="vp9" progressive="False" type="video">
这里要特别提一下的是,streams对象本身有提供一个找出最高分辨率的方法,video.streams.get_highest_resolution(),但是这个方法最高只能找到720p,无法返回1080p或更高的视频,所以弃用。(这可能也是很多国外油管下载站为什么最高只能提供到720p的原因)
接下来,我们把这个手工找到的1080p影片下载下来:
stream_highest_res.download(filename='v1080p.webm')
这时可以看到在python文件的同目录下有了一个叫做v1080p.webm的视频文件,用chrome就可以打开。当然除了filename,还可以在download()里用output_path=来指定文件存放目录。做的更细致点还可以在YouTube方法里指定下载进度和完成的回调函数,用来追踪下载过程。比如想收到下载完成通知,可以修改原来的YouTube()调用参数,并增加回调函数定义:
video = YouTube("https://www.youtube.com/watch?v=WZbKAFP1090", on_complete_callback=download_complete_handler)
...
def download_complete_handler(stream, file_path):
print ("File: " + stream.title + "downloaded completed in " + file_path)
这样下载完成后,我们就可以看到提示打印:
File: JIGGY! Merrick & Fynn #Shortsdownloaded completed in /Users/yeyu/Docs/python projects/demo for media/v1080p.webm
目前我们下载是完成了,但是用chrome播放这个视频的时候会发现只有图像没有声音,翻到前面的打印查看它的stream,发现1080p的stream参数里只有vcode=‘VP9’,却没有类似720p stream里的acode=,不知道这是什么原因,似乎超过720p以后音频和视频就分离了,基本油管里的视频都是这个样子。但是我们完全不用担心,还是有很多办法的,比如不是很在意极致效果的可以直接非常方便地下载720p,如果还是要用1080p,那就在stream里找到一条音轨合并进视频即可。
让我们先找到一条音轨,还是使用filter方法,找到第一条采样率128k的音频stream:
stream_audio = video.streams.filter(type="audio", abr="128kbps")[0]
stream_audio.download(filename="audio.mp4")
这样我们就已经把视频文件和音频文件都单独下载好了
在下一篇文章里我们将使用FFMPEG工具对两个文件进行自动合并,输出分辨率为1080p的音视频文件,并开始进入频道(Channel)监控。
进入下一篇:《躺着就能涨粉?Python自动化短视频搬运(二)|合并影片》
本篇用到的代码:
from pytube import YouTube
def download_complete_handler(stream, file_path):
print ("File: " + stream.title + "downloaded completed in " + file_path)
video = YouTube("https://www.youtube.com/watch?v=WZbKAFP1090",
on_complete_callback=download_complete_handler)
print("Video_title = " + video.title)
print("Video_author = " + video.author)
print("Video_length = " + str(video.length))
current_res = 0
stream_highest_res = video.streams[0]
for everystream in video.streams.filter(type="video"):
if int(everystream.resolution[:-1]) > 1080:
continue
if int(everystream.resolution[:-1]) > current_res:
current_res = int(everystream.resolution[:-1])
stream_highest_res = everystream
print("Highest stream: ", stream_highest_res)
stream_highest_res.download(filename='v1080p.webm')
stream_audio = video.streams.filter(type="audio", abr="128kbps")[0]
print(stream_audio)
stream_audio.download(filename='audio.mp4')
download_youtube_video.py