Python实战之听书小子
程序员文章站
2022-04-18 20:51:45
...
前段时间在公众号《Python爱好者社区》看到这篇文章:
觉得挺有意思,就和小伙伴一起写了一下当作学习python的练习。
语音合成
科大讯飞提供的语音合成有限制次数,只能免费调用500次,而百度提供的语音合成不限次数,但QFS限额为5,即一秒钟最多调用5次。于是果断选择用百度语音合成API。
注册一个百度账户,登录到百度AI智能平台,创建一个应用。
记录AppID、API Key、Secret Key,在调用API的时候会用到。
具体调用代码参考:https://ai.baidu.com/ai-doc/SPEECH/Gk4nlz8tc
result = client.synthesis('你好百度', 'zh', 1, {
'vol': 5,
})
# 识别正确返回语音二进制 错误则返回dict 参照下面错误码
if not isinstance(result, dict):
with open('auido.mp3', 'wb') as f:
f.write(result)
'zh'应该是中文的意思;'vol'选项为选择语音类型(1为普通男声,2为普通女声,3为度逍遥,4为度丫丫)。
此外,还可以通过参数调节音量、语调、语速等。
获取小说内容
小说内容从笔趣阁获取,原因是免费且没有反爬。首先选择一本小说,找到其网址。
这里以《我真没想重生啊》为例,其网址是http://www.biquge.info/69_69102/。
观察网站源代码,发现章节信息为:
<dd><a href="12893198.html" title="1、喝酒不开车">1、喝酒不开车</a></dd>
因此从dd标签中获取章节名、章节链接。
def getChapters(self):
"""获取所有章节信息(章节名、章节url)
input:
output:"""
r=requests.get(self.main_url)
r.encoding='utf-8'
soup = BeautifulSoup(r.text,'html.parser')
#每个章节
cpts=soup.findAll('dd')
num=1
for cpt in tqdm(cpts):
if str(num) not in cpt.text:
continue
#章节名
self.chapters_name[num]=cpt.text
#章节url
url=cpt.find('a')
self.chapters_url[num]=url.get('href').split('.')[0]
num+=1
然后使用BeautifulSoup.find(attrs={"id":"content"})来获取具体章节内容。
def getContents(self,chapter):
"""获取指定章节内容"""
r=requests.get(self.main_url+self.chapters_url[chapter]+'.html')
r.encoding='utf-8'
soup=BeautifulSoup(r.text,'html.parser')
content=soup.find(attrs={"id":"content"})
soup_text = BeautifulSoup(str(content), 'lxml')
text=soup_text.div.text.replace('\xa0','')
self.chapters_contens[chapter]=text
播放语音
使用pygame库,做法与上述文章一致。
def play(self,chapter):
"""播放指定章节内容"""
#如果没有下载章节内容则先下载
if chapter not in self.chapters_contens:
self.getContents(chapter)
#调用百度语音合成API,把文字转成语音
result = self.client.synthesis(self.chapters_contens[chapter][:1024], 'zh', 1, {"per": 4})
if isinstance(result, dict):
print('合成失败')
#播放语音
pygame_mixer = pygame.mixer
pygame_mixer.init(frequency=16000)
byte_obj = BytesIO()
byte_obj.write(result)
byte_obj.seek(0, 0)
pygame_mixer.music.load(byte_obj)
pygame_mixer.music.play()
while pygame_mixer.music.get_busy():
time.sleep(0.1)
pygame_mixer.stop()
最终代码
from bs4 import BeautifulSoup
import requests
from aip import AipSpeech
from tqdm import tqdm
import time
import pygame
from io import BytesIO
class listenWebNovel():
def __init__(self):
"""初始化"""
self.main_url='http://www.biquge.info/69_69102/'
self.chapters_name=dict()
self.chapters_url=dict()
self.chapters_contens=dict()
self.APP_ID=''#需改为个人APP_ID
self.API_KEY=''#需改为个人API_KEY
self.SECRET_KEY=''#需改为个人SECRET_KEY
self.client = AipSpeech(self.APP_ID,self.API_KEY,self.SECRET_KEY)
self.getChapters()
def getChapters(self):
"""获取所有章节信息(章节名、章节url)
input:
output:"""
r=requests.get(self.main_url)
r.encoding='utf-8'
soup = BeautifulSoup(r.text,'html.parser')
#每个章节
cpts=soup.findAll('dd')
num=1
for cpt in tqdm(cpts):
if str(num) not in cpt.text:
continue
#章节名
self.chapters_name[num]=cpt.text
#章节url
url=cpt.find('a')
self.chapters_url[num]=url.get('href').split('.')[0]
num+=1
def getContents(self,chapter):
"""获取指定章节内容"""
r=requests.get(self.main_url+self.chapters_url[chapter]+'.html')
r.encoding='utf-8'
soup=BeautifulSoup(r.text,'html.parser')
content=soup.find(attrs={"id":"content"})
soup_text = BeautifulSoup(str(content), 'lxml')
text=soup_text.div.text.replace('\xa0','')
self.chapters_contens[chapter]=text
def play(self,chapter):
"""播放指定章节内容"""
#如果没有下载章节内容则先下载
if chapter not in self.chapters_contens:
self.getContents(chapter)
#调用百度语音合成API,把文字转成语音
result = self.client.synthesis(self.chapters_contens[chapter][:1024], 'zh', 1, {"per": 4})
if isinstance(result, dict):
print('合成失败')
#播放语音
pygame_mixer = pygame.mixer
pygame_mixer.init(frequency=16000)
byte_obj = BytesIO()
byte_obj.write(result)
byte_obj.seek(0, 0)
pygame_mixer.music.load(byte_obj)
pygame_mixer.music.play()
while pygame_mixer.music.get_busy():
time.sleep(0.1)
pygame_mixer.stop()
if __name__ == '__main__':
#实例化
lw=listenWebNovel()
#播放第1章
lw.play(1)
上一篇: jsp中,后端传递的日期参数,前端格式化
下一篇: 016、双向绑定实现