前段時間閒得無聊,使用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 !
一個人最好的生活狀態,有自己的生活和情趣,努力完善自己。沒人愛時專注自己,有人愛時,有能力擁抱彼此。