前段时间闲得无聊,使用python抓取了自己想看的小说,抓取方法:一个资深小说迷打开小说的正确姿势
最近发现连续长时间盯着屏幕,眼睛实在是有点遭不住。对于我这种又想保护视力,又不想放下小说的人来说,简直就是遇到了像 “ 鱼与熊掌不可兼得” 一般的世纪难题。
正当我思考如何两害取其轻的时候,有人私信我帮忙做一个文字转语音的接口,我突然灵机一动,这简直就是送上门来的满分答案啊
当然,对于我这种社畜来说,是万万不可能自己实现文字转语音功能的,我没有那个精力,更没有那个 money
不过,咱不会煮饭,咱还不会点外卖么?O(∩_∩)O哈哈~
打开快被我点裂开了的 google chrome 搜了搜,果然很多公司都提供现成的免费接口,比如百度、讯飞…最后我选择了百度AI接口(这种东西啊,就和点外卖是一样的,同样都是芋儿鸡,店家不一样,做出来的味道就有好有坏。当你都没吃过时,牌子大一点的店或许是个不坏的选择)
言归正传,首先你得去百度控制台登录一下,没有百度账号的需要注册:
https://ai.baidu.com/tech/speech
然后需要创建一个应用,创建好了之后,就能拿到我们想要的三个东西
然后,python需要安装两个库(百度接口库和语音播放库),如果不需要python播放音频的话,只需要安装第一个库就行:
pip install baidu-aip
pip install playsound
根据百度提供的接口文档https://ai.baidu.com/ai-doc/SPEECH/Gk4nlz8tc,我们可以很容易的将一段文本翻译成音频文件,如:
from aip import AipSpeech # 导入api接口
from playsound import playsound # 音频模块
#对应填入百度控制台获取的三个参数
APP_ID = ''
API_KEY = ''
SECRET_KEY = ''
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
data = '你是最棒的,hello world'
result = client.synthesis(data, 'zh', 1, {
'per': 4,
'spd': 3, # 速度
'vol': 7 # 音量
})
if not isinstance(result, dict):
with open('hello.mp3', 'wb') as f:
f.write(result)
# 播放
playsound("hello.mp3")
上面这段代码,你只需要对应的填入百度后台获取的三个参数,然后运行文件,就会在你的代码文件同级目录下生成一个音频文件hello.mp3,并且会有美女夸你
有美女夸固然是好,可是我们最初的梦想是听小说啊。
别着急,你只需要将代码中的 data 内容换成咱们使用爬虫爬下来的小说内容,如:
#读取文本文件内容
with open(file_name, 'r', encoding='utf-8') as f:
data = f.read()
此时要注意,百度API每一次翻译的文本长度必须小于1024字节,小说每一章的内容往往大于1024字节,怎么办呢?
咱们可以将文本分割,然后多次请求就行了,写一个分割方法,像这样:
#按指定字节数分割字符串
def byte_split(seq):
list = []
while seq:
if len(seq) >= 1024:
list.append(seq[:1024])
seq = seq[1024:]
else:
list.append(seq)
seq = []
return list
简单封装一下,第一版就出炉啦:
from aip import AipSpeech # 导入api接口
from playsound import playsound # 音频模块
import sys
#百度账号信息配置
#对应填入百度控制台获取的三个参数
APP_ID = ''
API_KEY = ''
SECRET_KEY = ''
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
#按指定字节数分割字符串
def byte_split(seq):
list = []
while seq:
if len(seq) >= 1024:
list.append(seq[:1024])
seq = seq[1024:]
else:
list.append(seq)
seq = []
return list
'''
@desc 写入音频
@param data_arr list 文件数组
@param vedio_name string 音频文件名
@return 音频文件名
'''
def vedio_write(data_arr, vedio_name):
name = vedio_name + '.mp3'
for i in data_arr:
#请求百度接口,获取语音二进制
result = client.synthesis(i, 'zh', 1, {
'per': 4,
'spd': 3, # 速度
'vol': 7 # 音量
})
#判断是否翻译成功-成功则写入,失败则打印错误信息
if not isinstance(result, dict):
with open(name, 'ab') as f:
f.write(result)
else:
print(result)
return name
#主函数
if __name__ == "__main__":
#文本文件
file_name = r'../novel/quanzhifashi/第1章 世界大变.txt'
#音频文件名
vedio_name = file_name.split('/')[-1].split('.')[0]
#读取文本文件内容
with open(file_name, 'r', encoding='utf-8') as f:
data = f.read()
#按字符串拆分成数组
data_arr = byte_split(data)
#写入音频,返回音频文件名
vedio = vedio_write(data_arr, vedio_name)
# 播放
playsound(vedio)
点击运行,在我的保存目录找到了自己想要的结果
但是并没有给我播放视频,而且反手扔给我一个Error
查看报错信息发现,由于我的音频文件是中文名,所以播放失败了,将中文换掉就可以正常播放。
但是总有像我一样杠中带倔的人,喜欢将音频文件命名为中文,怎么办呢?当然是打开我那要裂开了的google chrome 啊。巡视了一圈,最后发现pygame库可以解决这个问题。好嘛,安装pygame库:
pip install pygame
封装个方法,使用pygame播放音频:
# 播放音频
# 貌似只能播放单声道音乐,可能是pygame模块限制
def playMusic(filename, loops=0, start=0.0, value=0.5):
"""
:param filename: 文件名
:param loops: 循环次数
:param start: 从多少秒开始播放
:param value: 设置播放的音量,音量value的范围为0.0到1.0
:return:
"""
flag = False # 是否播放过
pygame.mixer.init() # 音乐模块初始化
while 1:
if flag == 0:
pygame.mixer.music.load(filename)
# pygame.mixer.music.play(loops=0, start=0.0) loops和start分别代表重复的次数和开始播放的位置。
pygame.mixer.music.play(loops=loops, start=start)
pygame.mixer.music.set_volume(value) # 来设置播放的音量,音量value的范围为0.0到1.0。
if pygame.mixer.music.get_busy() == True:
flag = True
else:
if flag:
pygame.mixer.music.stop() # 停止播放
break
再将之前的代码整合一下子,最终版本就出炉了:
from aip import AipSpeech # 导入api接口
#from playsound import playsound # 音频模块
import sys
import pygame
#百度账号信息配置
#对应填入百度控制台获取的三个参数
APP_ID = ''
API_KEY = ''
SECRET_KEY = ''
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
#按指定字节数分割字符串
def byte_split(seq):
list = []
while seq:
if len(seq) >= 1024:
list.append(seq[:1024])
seq = seq[1024:]
else:
list.append(seq)
seq = []
return list
'''
@desc 写入音频
@param data_arr list 文件数组
@param vedio_name string 音频文件名
@return 音频文件名
'''
def vedio_write(data_arr, vedio_name):
name = vedio_name + '.mp3'
for i in data_arr:
#请求百度接口,获取语音二进制
result = client.synthesis(i, 'zh', 1, {
'per': 4,
'spd': 3, # 速度
'vol': 7 # 音量
})
#判断是否翻译成功-成功则写入,失败则打印错误信息
if not isinstance(result, dict):
with open(name, 'ab') as f:
f.write(result)
else:
print(result)
return name
# 播放音频
# 貌似只能播放单声道音乐,可能是pygame模块限制
def playMusic(filename, loops=0, start=0.0, value=0.5):
"""
:param filename: 文件名
:param loops: 循环次数
:param start: 从多少秒开始播放
:param value: 设置播放的音量,音量value的范围为0.0到1.0
:return:
"""
flag = False # 是否播放过
pygame.mixer.init() # 音乐模块初始化
while 1:
if flag == 0:
pygame.mixer.music.load(filename)
# pygame.mixer.music.play(loops=0, start=0.0) loops和start分别代表重复的次数和开始播放的位置。
pygame.mixer.music.play(loops=loops, start=start)
pygame.mixer.music.set_volume(value) # 来设置播放的音量,音量value的范围为0.0到1.0。
if pygame.mixer.music.get_busy() == True:
flag = True
else:
if flag:
pygame.mixer.music.stop() # 停止播放
break
#主函数
if __name__ == "__main__":
#文本文件
file_name = r'../novel/quanzhifashi/第1章 世界大变.txt'
#音频文件名
vedio_name = file_name.split('/')[-1].split('.')[0]
#读取文本文件内容
with open(file_name, 'r', encoding='utf-8') as f:
data = f.read()
#按字符串拆分成数组
data_arr = byte_split(data)
#写入音频,返回音频文件名
vedio = vedio_write(data_arr, vedio_name)
#音频播放
playMusic(vedio)
#playMusic('out.wav')
# 播放
#playsound(vedio)
谁说鱼与熊掌不可兼得?
The end !
一个人最好的生活状态,有自己的生活和情趣,努力完善自己。没人爱时专注自己,有人爱时,有能力拥抱彼此。